socket长连接在手游场景下的技术实践

📅 2026/7/2 2:50:22
socket长连接在手游场景下的技术实践
、引言本文介绍了37手游基于B站goim框架自研长连接系统的实践。系统采用分层设计支持多协议和发布/订阅机制用于直播弹幕、实时推送等场景实现了高性能与业务适配。2、长连接对于大部分公司的意义实时的响应总是让人兴奋的就如你在微信里看到对方正在输入如你在王者峡谷里一呼百应如你们在直播弹幕里不约而同的 666它们的背后都离不开长连接技术的加持。每个互联网公司里几乎都有一套长连接系统它们被应用在消息提醒、即时通讯、推送、直播弹幕、游戏、共享定位、股票行情等等场景。而当公司发展到一定规模业务场景变得更复杂后更有可能是多个业务都需要同时使用长连接系统。3、长连接是什么?长连接在百科上的定义指在一个连接上可以连续发送多个数据包在连接保持期间如果没有数据包发送需要双方发链路检测包。严格上来说长连接是一种概念它指的是在网络发送接收双方保持一个持续连接的状态双方都可以发送或接收消息全双工。当然长连接系统听起来好像高深莫测但实际不可能说完全脱离于我们实际公司的业务去出发设计这就引出来我们今天的主题—— 长连接技术在37手游内是如何设计以及实践的4、技术痛点从服务端而言缺乏在SDK内实时推送通知用户的能力如防沉迷的弹窗通过http定时轮询来实现给服务造成很大的压力从客户端而言也缺乏低成本告知服务端自身在线的能力如维持用户在线状态靠客户端定时上报心跳到防沉迷服务实现。5、搭建背景业务背景手游的SDK需要提供内嵌直播弹幕的功能供玩家在看直播的时候进行沟通发言业界一般会用到长连接来进行实时的推送以降低服务的轮训和请求。从业务上而言直播弹幕需求由于初始量级很少不用通过长连接的形式也能实现具体业务逻辑但出于平台的拓展和能力考虑长连接的能力是必须具备的。长连接系统的这次搭建本质是通过SDK内嵌直播弹幕为切入点从0到1为平台提供了完整的一套实时推送触达用户的能力。从以上角度出发我们便着手想要设计一个高可用且高性能的长连接系统提供给我们使用。6、方案选型从实际上而言我们考虑三个方向。1云服务市面上可购买的服务如环信等大多数都以即时聊天通讯为主长连接往往只是附带产品过于偏向于社交业务在花钱的同时也很难适应到自身游戏业务。2开源框架b站的goim框架、NettyChat框架、MobileIMSDK框架等好处是免费且能快速接入但业务还是不相适应且语言栈和技术栈不一定相契合。3自研弊开发成本高且容易踩坑。利基础组件完善统一框架好进行监控和问题查询。且能充分契合自身业务进行拓展并将数据源掌控在自己手中。4结论出于扩展性的考虑肯定是自研的方式更加合适但完全自研相应的成本和不确定性会非常高因此最终的选型方案为借鉴b站的goim框架设计和部分代码并做了符合自身技术栈和业务架构的改善。可认为是基于开源框架的自研方案的形式完成了长连接这个系统的落地。7、goim技术概况7.1 goim是什么为什么借鉴它goim是b站开源研发的一个支持集群的im及实时推送服务。业务上为直播间的弹幕发送场景。主要考虑到1技术栈契合语言栈为Golang 消息队列为kafka缓存设计为redis2高性能有压测报告性能设计有保障3多协议支持websocket、tcp。7.2 goim的模块如上图所示1comet用于跟端上保连在内存中存储订阅信息2logic用于处理鉴权在线房间等业务逻辑3business业务服务4balancer负载均衡模块5discovery服务发现模块6jobkafka用于削峰。redis用于缓存房间信息7logic和comet的通讯采用rpc优化性能。从上面的goim的设计而言我们可以总结出长连接的设计原则。长连接架构的设计总是大同小异的通用的有这几点1业务层次分明分接入层逻辑层存储层服务发现层通过这几层实现业务解耦2协议通用传输的数据协议必须在所有服务内进行通讯并支持扩展3上行和下行收敛上行和下行都会有一个对应的网关来进行收敛消息的收敛4消息削峰通过队列来将发送信息削峰。并使接入层和逻辑层解藕8、手游长连接系统的设计实践根据以上的通用设计原则我们不难得出需要针对goim的架构如何做适配才能实际满足我们的业务需求下面我们将会一一介绍。8.1 架构改动从架构而言我们改动的点不多1cient获取连接节点手游内无统一的服务发现模块但有外层LB因此通过LB来实现comet节点负载均衡2推送消息同上消费者获取节点时需要到logic服务中查询而不是discovery3服务通讯协议由于手游内架构通讯协议的统一接入层和逻辑层的通讯由RPC转为http8.2 逻辑改动1鉴权机制客户端第一次连接上comet的时候会发送鉴权上行。comet会解析客户端传输的数据若包体协议或对应的签名错误comet会将会直接主动断连2心跳机制comet会有心跳计时器若客户端无定时上报心跳则认为该连接已经超时直接断开。这种业务的心跳主要是为了防止僵尸连接的存在。3回包机制客户端每发送一次上行操作comet都会有对应的消息回包给端上。端上可根据回包来知道自己鉴权心跳或者订阅退订的操作是否成功从而决定是否进行重试。4发布/订阅机制我们在观看goim的源码时发现goim适用于直播群体推送以房间为维度带有强业务属性因此我们针对该部分抽象出发布/订阅机制。将房间抽象为topic修改进房/出房动作为 订阅/退订。将所有的通知抽象为业务事件客户端想要接受到哪个事件过来的消息时可发送对应的订阅上行。单个连接订阅的事件不做限制对某个用户或某个事件范围内的用户推送消息时comet会根据事件去取到推送的用户只有用户订阅了才会收到消息。5内存设计a. bucket维护消息通道和事件的信息b. 一个session对应一个用户连接c. 根据sessionid做一致性哈希来选择落到那个bucket上d. bucket有两个map一个是session map一个是topic mape. 所有bucket都会开启一个chan做监听广播的时候会通知到所有bucket所有bucket再取出某个事件的所有连接进行下发。8.3 总体交互8.4 总体特点因此我们可以总结出来我们手游长连接系统的总体特点1纯golang实现2多协议支持websocket和tcp3可拓扑结构主要模块均无状态可横向扩展4消息支持单推/群推消息协议业务可自定义5发布/订阅机制事件可业务自定义。9、性能评估在说性能之前我们先抛出一个疑问协程数过多实际占用的是什么连接数过多是否影响CPU从实际上来说长连接的性能瓶颈一般卡在接入层因此以接入层为评估维度通过全链路压测得出来结果。如下1压测参数3000连接 3000 qps的实时推送2推送内容{msg:test} 3推送类型群推4推送持续时长5分钟 5资源使用1核2G的容器6CPU的使用达到100%。目前采用的长连接系统通过压测结果发现本身的连接数的维持和实时推送实际影响到是机器两个维度的性能推送量影响到的是CPU连接数影响到的是内存。分别提高两个参数对相应的内存CPU的影响并不大。10、实际应用情况直播弹幕悬浮球实时红点