go语言http长连接的简单介绍( 三 )


saver service是存储访问层 , 承担了对redis和mysql的操作,另外也提供部分业务逻辑相关的内存缓存,比如广播信息的加载可以在saver中进行缓存 。另外一些策略 , 比如客户端sdk由于被恶意或者意外修改 , 每次加载了消息,不回复ack,那服务端就不会删除消息,消息就会被反复加载,形成死循环,可以通过在saver中做策略和判断 。(客户端总是不可信的) 。
center service提供给接入方的内部api服务器 , 比如单播或者广播接口,状态查询接口等一系列api,包括运维和管理的api 。
举两个常见例子,了解工作机制:比如发一条单播给一个用户,center先请求Register获取这个用户之前注册的连接通道标识、room实例地址,通过room service下发给长连接 Center Service比较重的工作如全网广播,需要把所有的任务分解成一系列的子任务,分发给所有center,然后在所有的子任务里 , 分别获取在线和离线的所有用户,再批量推到Room Service 。通常整个集群在那一瞬间压力很大 。
deployd/agent service用于部署管理各个进程,收集各组件的状态和信息,zookeeper和keeper用于整个系统的配置文件管理和简单调度
关于推送的服务端架构
常见的推送模型有长轮训拉取 , 服务端直接推送(360消息系统目前主要是这种),推拉结合(推送只发通知 , 推送后根据通知去拉取消息).
拉取的方式不说了,现在并不常用了,早期很多是nginx+lua+redis,长轮训,主要问题是开销比较大,时效性也不好 , 能做的优化策略不多 。
直接推送的系统,目前就是360消息系统这种,消息类型是消耗型的,并且对于同一个用户并不允许重复消耗,如果需要多终端重复消耗 , 需要抽象成不同用户 。
推的好处是实时性好,开销?。?直接将消息下发给客户端,不需要客户端走从接入层到存储层主动拉取.
但纯推送模型 , 有个很大问题,由于系统是异步的,他的时序性无法精确保证 。这对于push需求来说是够用的,但如果复用推送系统做im类型通信,可能并不合适 。
对于严格要求时序性,消息可以重复消耗的系统 , 目前也都是走推拉结合的模型,就是只使用我们的推送系统发通知,并附带id等给客户端做拉取的判断策略,客户端根据推送的key,主动从业务服务器拉取消息 。并且当主从同步延迟的时候,跟进推送的key做延迟拉取策略 。同时也可以通过消息本身的QoS,做纯粹的推送策略,比如一些“正在打字的”低优先级消息,不需要主动拉取了 , 通过推送直接消耗掉 。
哪些因素决定推送系统的效果?
首先是sdk的完善程度,sdk策略和细节完善度,往往决定了弱网络环境下最终推送质量.
SDK选路策略,最基本的一些策略如下:有些开源服务可能会针对用户hash一个该接入区域的固定ip,实际上在国内环境下不可行,最好分配器(dispatcher)是返回散列的一组 , 而且端口也要参开 , 必要时候 , 客户端告知是retry多组都连不上,返回不同idc的服务器 。因为我们会经常检测到一些case,同一地区的不同用户,可能对同一idc内的不同ip连通性都不一样,也出现过同一ip不同端口连通性不同,所以用户的选路策略一定要灵活,策略要足够完善.另外在选路过程中,客户端要对不同网络情况下的长连接ip做缓存,当网络环境切换时候(wifi、2G、3G),重新请求分配器,缓存不同网络环境的长连接ip 。
客户端对于数据心跳和读写超时设置,完善断线检测重连机制

推荐阅读