websocket

最后更新于:2022-04-02 02:50:51

[TOC] ## demo 参考 [个人github](https://github.com/idcpj/go_websocket) 参考 [个人 im 带群聊,发图片,语音](https://github.com/idcpj/go_IM) ## 推送的高并发解决方案 ### 内核优化 把同一秒内要推送的弹幕,合并成一条,如每条发送10条的数,合并为10条同时发送 ## 锁瓶颈-优化方案 1. 连接打散到多个集合中,每个集合有自己的锁 2. 多线程并发推送多个集合,避免锁竞争 3. 读写锁取代互斥锁,多个推送任务可以并发遍历相同集合 ## 单机瓶颈 1. 维护海量长连接会花费不少内存 2. 消息推送瞬时消耗大量CPU资源 3. 消息推送瞬时带宽高达400~600MB(4-6Gbiⅰts),是主要瓶颈! ## 资源标准化 把图片,视频,音频资源先上传到服务器,在传递 url ## 群聊解决方案 1. 使用缩略图 2. 使用云服务,如阿里云 ## 心跳机制 1. 每 30s 发送一次 2. 距离最近发送的消息,后的 30s [推荐] ## 降低 cpu 资源的使用 1. 降低 json 编码频次 2. 一次编码多次使用 ## 降低对 io 资源的使用 1. 合并写数据库次数 2. 优化对数据库读操作 3. 能缓存的就缓存 ## 群聊的 struct 表 ### 方案一 [推荐] 优势 - 锁的频次低,只需要在加入时,clientMap 加锁 劣势 - 要轮训全部map ``` type Node struct { Conn websocket.Conn //找到用户就可以发送 conn 所以不需要锁 //并行转串行, DataQueue chan []byte GroupSets set.Interface //设置人员所在群聊的 id 列表 使用(gopkg.in/fatih/set.v0) } //映射关系表, userid-node 映射表 var clientMap map[int64]Node = make(map[int64]*Node,0) ``` ### 方案二 优势 - 找用户ID非常快 劣势 - 登录用户的时,需要给 clientMap 与 comMap 都加锁 - 发送信息时需要根据userid获取node,锁的频次太高 ``` type Node struct { Conn *websocket.Conn //并行转串行, DataQueue chan []byte } //映射关系表 var clientMap map[int64]*Node = make(map[int64]*Node,0) //群中的人员userid var comMap map[int64]set.Interface= make(map[int64]set.Interface,0) ``` ## 聊天的 struct ``` type Message struct { Id int64 `json:"id,omitempty" form:"id"` //消息ID //谁发的 Userid int64 `json:"userid,omitempty" form:"userid"` //谁发的 //什么业务 Cmd int `json:"cmd,omitempty" form:"cmd"` //群聊还是私聊 //发给谁 Dstid int64 `json:"dstid,omitempty" form:"dstid"` //对端用户ID/群ID //怎么展示 Media int `json:"media,omitempty" form:"media"` //消息按照什么样式展示 //内容是什么 Content string `json:"content,omitempty" form:"content"` //消息的内容 //图片是什么 Pic string `json:"pic,omitempty" form:"pic"` //预览图片 //连接是什么 Url string `json:"url,omitempty" form:"url"` //服务的URL //简单描述 Memo string `json:"memo,omitempty" form:"memo"` //简单描述 //其他的附加数据,语音长度/红包金额 Amount int `json:"amount,omitempty" form:"amount"` //其他和数字相关的 } const ( //点对点单聊,dstid是用户ID CMD_SINGLE_MSG = 10 //群聊消息,dstid是群id CMD_ROOM_MSG = 11 //心跳消息,不处理 CMD_HEART = 0 ) const ( //文本样式 MEDIA_TYPE_TEXT = 1 //新闻样式,类比图文消息 MEDIA_TYPE_News = 2 //语音样式 MEDIA_TYPE_VOICE = 3 //图片样式 MEDIA_TYPE_IMG = 4 //红包样式 MEDIA_TYPE_REDPACKAGR = 5 //emoj表情样式 MEDIA_TYPE_EMOJ = 6 //超链接样式 MEDIA_TYPE_LINK = 7 //视频样式 MEDIA_TYPE_VIDEO = 8 //名片样式 MEDIA_TYPE_CONCAT = 9 //其他自己定义,前端做相应解析即可 MEDIA_TYPE_UDEF = 100 ) type Node struct { Conn *websocket.Conn DataQueue chan []byte GroupSets set.Interface //把群放入其中 } var clientMap = make(map[int64]*Node, 0) var rw sync.RWMutex ``` ## 分布式 使用 udp + nginx ,参考 [个人 im 带群聊,发图片,语音](https://github.com/idcpj/go_IM)
';