当前位置: 首页 > news >正文

自然资源网站建设方案深圳品牌蛋糕店有哪些品牌排行

自然资源网站建设方案,深圳品牌蛋糕店有哪些品牌排行,wordpress一键部署,企业密信app下载安装在前面的文章中,提到过非功能性需求决定了架构。 今天我们再来考虑一下另外两个非功能性需求:性能和可用性。 前言 关于性能,其实并不是只有我们这个消息推送系统独有的问题。 对于所有的开发者而言,都多多少少会处理过性能相关…

在前面的文章中,提到过非功能性需求决定了架构。
今天我们再来考虑一下另外两个非功能性需求:性能和可用性。

前言

关于性能,其实并不是只有我们这个消息推送系统独有的问题。
对于所有的开发者而言,都多多少少会处理过性能相关的问题,比如后端为了减少数据库查询提高并发引入的缓存中间件,如 redis
又或者如前端一次性渲染大量数据的时候,如果让用户体验更加流畅等。

本文会针对 WebSocket 应用场景下去思考一些可能出现的性能问题以及可行的解决方案。

性能

对于性能,有几个可能导致性能问题的地方:

连接数

连接数过多会导致占用的内存过多,因为对于每一个连接,我们都有两个协程,一个读协程,一个写协程;
同时我们的 Client 结构体中的 send 是一个缓冲通道,它的缓冲区大小也直接影响最终占用的内存大小。

比如,我们目前的创建 Client 实例的代码是下面这样的:

client := &Client{hub: hub, conn: conn, send: make(chan Log, 256), uid: uid}

我们在这里直接为 send 分配了 256 的大小,如果 Log 结构体比较大的话,
它占用的内存就会比较大了(因为最终占用内存 = 连接数 * sizeof(Log) * 256)。

在实际中,我们一般没有那么多等待发送的消息,这个其实可以设置为一个非常小的值,比如 16;
设置为一个小的值的负面影响是,当 send 塞满了 16 条 Log 的时候,发送消息的接口会阻塞:

func send(hub *Hub, w http.ResponseWriter, r *http.Request) {// ... 其他代码// 如果 send 满了,下面这一行会阻塞client.send <- messageLoghub.pending.Add(int64(1))
}

所以这个数值可能需要根据实际场景来选择一个更加合适的值。

代码本身的问题

比如,我们的代码中其实有一个很常见的性能问题,就是 string[]byte 之间直接强转:

// writePump 方法里面将 string 转 []byte
if err := c.conn.WriteMessage(websocket.TextMessage, []byte(messageLog.Message)); err != nil {return
}

至于原因,可以去看看此前的一篇文章《深入理解 go unsafe》 的最后一小节,
简单来说,就是这个转换会产生内存分配,而内存分配会导致一定的性能损耗。而通过 unsafe 就可以实现无损的转换。

除了这个,其他地方也没啥太大的问题了,因为到目前为止,我们的代码还是非常的简单的。

互斥锁

为了保证程序的并发安全,我们在 Hub 中加了一个 sync.Mutex,也就是互斥锁。
在代码中,被 sync.MutexLock 保护的代码,在同一时刻只能有一个协程可以执行。

// 推送消息的接口
func send(hub *Hub, w http.ResponseWriter, r *http.Request) {// ... 其他代码// 从 hub 中获取 clienthub.Lock()client, ok := hub.userClients[uid]hub.Unlock()// ... 其他代码
}

对于上面这种只读的操作,也就是没有对 map 进行写操作,我们依然使用了 sync.MutexLock() 来锁定临界区。
这里存在的问题是,其实我们的 hub.userClients 是支持并发读的,只是不能同时读写而已。

所以我们可以考虑将 sync.Mutex 替换为 sync.RWMutex,这样就可以实现并发读了:

// 推送消息的接口
func send(hub *Hub, w http.ResponseWriter, r *http.Request) {// ... 其他代码// 从 hub 中获取 clienthub.RLock() // 读锁client, ok := hub.userClients[uid]hub.RUnlock() // 释放读锁// ... 其他代码
}

这样做的好处是,当有多个并发的 send 请求的时候,这些并发的 send 请求并不会相互阻塞;
而使用 sync.Mutex 的时候,并发的 send 请求是会相互阻塞的,也就是会导致 send 变成串行的,这样性能无疑会很差。

除此之外,我们在 Hubrun 方法中也使用了 sync.Mutex

case client := <-h.register:h.Lock()h.clients[client] = trueh.userClients[client.uid] = clienth.Unlock()

也就是说,我们将 Client 注册到 Hub 的操作也是串行的。
对于这种场景,其实也有一种解决方法就是分段 map
也就是将 clientsuserClients 这两个 map 拆分为多个 map
然后对于每一个 map 都有一个对应的 sync.Mutex 互斥锁来保证其读写的安全。

但如果要这样做,单单分段还不够,我们的 registerunregister 还是只有一个,对于这个问题,
我们可能需要将 registerunregister 也分段,最后在 run 方法里面起多个协程来进行处理。
这个实现起来就很复杂了。

其他

由于我们的 Hub 中还有 MessageLogger、错误处理、认证等功能,
在实际中,如果我们有将其替换为自己的实现,可能还得考虑自己的实现中可能存在的性能问题:

type Hub struct {messageLogger MessageLoggererrorHandler  Handlerauthenticator Authenticator
}

可用性

这里主要讨论的是集群部署的情况下,应用存在的一些的问题以及可行的解决方案。关于具体部署上的细节不讨论。

要实现高可用的话,我们就得加机器了,毕竟如果只有一台服务器的话,一旦它宕机了,服务就完全挂了。

由于我们的 WebSocket 应用维持着跟客户端的连接,在单机的时候,客户端连接、推送消息都是在一台机器上的。
这种情况下并没有什么问题,因为推送消息的时候,都可以根据 uid 来找到对应的 WebSocket 连接,从而给客户端推送消息。

而在多台机器的情况下,我们的客户端可能跟不同的服务器产生连接,这个时候一个比较关键的问题是:
如何根据 uid 找到对应的 WebSocket 连接所在的机器?
如果我们推送消息的请求到达的机器上并没有消息关联的 WebSocket 连接,那么我们的消息就无法推送给客户端了。

对于这个问题,一个可行的解决方案是,将 uid 和服务器建立起关联,比如,在用户登录的时候,
就给用户返回一个 WebSocket 服务器的地址,客户端拿到这个地址之后,跟这个服务器建立起 WebSocket 连接,
然后其他应用推送消息的时候,也根据同样的算法将推送消息的请求发送到这个 WebSocket 服务器即可。

总结

最后,再简单回顾一下本文的内容:

  • 具体来说,我们的系统中会有下面几个可能的地方会导致产生性能问题:
    • 连接数:一个连接会有两个协程,另外每一个 Client 结构体也会需要一定的缓冲区来缓冲发送给客户端的消息
    • 代码上的性能问题:如 string[]byte 之间转换带来的性能损耗
    • 互斥锁:某些地方可以使用读写锁来提高读的并发量,另外一个办法就是使用分段 map 配合互斥锁
    • 系统本身预留的扩展点中,用户自行实现的代码中可能会存在性能问题
  • 要实现高可用就得将系统部署到多台机器上,这个时候需要在 uid 和服务器之间建立起某种关联,以便推送消息的时候可以成功推送给客户端。
http://www.yayakq.cn/news/833405/

相关文章:

  • php网站开发wamp网站备案 手印随便
  • 跨境电商建站工具我的世界充钱网站怎么做
  • 泰州网站制作价格有没有代做模型的网站
  • 企业网站建设的要素有哪些怎么推广比较好
  • 房产网站怎么做绿色环保材料网站模板
  • 电商网站开发技术方向新闻报道最新消息今天
  • 计算机学院网站建设系统可行性分析wordpress网站响应慢
  • 百度站长平台网站提交网络推广seo是什么
  • 网站建设需求报告二次开发包
  • 租电信服务器开网站jsp网站开发实例
  • wordpress微信缩略图不显示厦门建网站做优化
  • 微信公众号怎么进行网站建设雅思培训班价格一览表
  • 用yershop做网站百度如何建网站
  • 广州新塘网站制作推广网站建设 中企动力北京
  • 高端网站建设哪家便宜excel做网站页面布局
  • 网站增加栏目费用网站建设公司有哪
  • 多品牌网站建设app与网站用的服务器
  • 图片上传不了网站创意医疗产品设计
  • 网站主题旁边的图标怎么做wordpress数据控查看密码
  • 茶企业网站网站建设案例分析
  • 做外贸网站公司adspower指纹浏览器
  • 信息管理的基本原理分析网站建设做视频网站需要哪些技术
  • 12380网站建设情况总结基于wed的网站开发
  • 怎样在线做网站404青岛媒体网地址
  • 手机端网站自动弹出营销qq吉林手机版建站系统开发
  • 济南设计网站路由器屏蔽网站怎么做
  • 营销网站建站公司网站目录提交
  • 教如何做帐哪个网站好国外免费域名
  • 网站做收录要多少长时间十大网络公司
  • 网站源代码怎么放入 dede网站后台济南网站建设全包