注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

逍遥子 曰:

得失失得 何必患得患失 舍得得舍 不妨不舍不得

 
 
 

日志

 
 

[原]关于推送系统设计的一些总结与思考(三)  

2016-11-24 19:53:16|  分类: 分布式-服务器相 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

本文由逍遥子撰写,转发请标注原址:

http://houjixin.blog.163.com/blog/static/356284102016102475316967

http://blog.csdn.net/houjixin/article/details/53324788


四、        推送系统的集群化

4.1长连接集群

推送系统作为一项基础服务,它需要承载全部在线用户量,对于移动互联网行业,在设计之初的期望目标用户量就非常大,并且用户未来一段时间的增长量通常难以预估,因此要求在设计推送系统时,都要求能够集群化部署、支持动态扩展。那么长连接集群化设计时需要解决那些问题呢?

个人认为长连接服务需要解决三个问题:路由、管理和动态扩展;另外,如果想要锦上添花,让长连接通道更加安全,还可以在长连接的集群管理中采取本文中所提出的应用层加解密方法。

路由是指长连接集群能根据目标用户的标识快速确定它所连接的长连接服务;在推送系统发送客户端的每个推送通知时,首先要找到它所连接的长连接服务,然后再将待发送的通知交付给长连接服务,由长连接服务发送到推送客户端。由此可以看到路由功能是长连接的核心功能,它直接决定了整个推送系统能否正确、高效地工作。

管理是指长连接集群的管理和调度服务对集群中的多个长连接服务进行分配、调度和管理的功能;具体包括:长连接服务的负载均衡和客户端分配信息的管理;负载均衡功能要根据每个长连接服务当前的负载压力,确定下一个客户端分配到它上面的概率,例如:长连接服务A上已经连接了20万客户端,而长连接服务B上目前只有10客户端,那么当新客户端请求连接进来时,长连接的集群调度服务将该客户端分配到A上的概率要远大于分配到B上的概率,从而对整个长连接集群进行负载均衡;负载均衡算法中需要综合考虑每个长连接服务的最大连接数的承载能力、目前已经承载的长连接数量,以及服务所在主机的CPU、内存、网络等各种因素。可以采取的如下措施来满足此要求:通过长连接服务或者配套的辅助软件协助上报这些数据到ZooKeeper上,然后由ZooKeeper负责将这些数据转发到集群调度和管理服务上。客户端分配管理主要管理长连接服务集群管理客户端和所分配的长连接服务的对应关系,它是进行路由算法的基础,这种管理方法可以通过算法或者缓存来完成,通过算法是指:长连接集群服务通过固定算法将客户端的标识映射到指定的长连接服务上,这种方式的优点是不需要长连接集群服务记录客户端分配到哪个长连接上,实现简单,缺点是:不利于动态扩展,它适合最大用户量可以预估的项目;通过缓存方式是指:长连接集群服务通过缓存记录下每个客户端所分配的长连接服务,在发送通知时,需要先查询缓存找到客户端对应的长连接服务,然后再将通知内容交付给对应的长连接服务,这种方式的优点是:易于扩展长连接服务,缺点是:实现相对复杂,需要考虑缓存的可靠性、访问效率、集群部署等问题;

动态扩展是指推送系统应能根据用户量的增加,动态增加新的长连接服务。长连接集群的动态扩展与缓存集群的扩展不一样,在缓存扩展时,需要动态迁移一部分数据到新增缓存节点上,而长连接服务中已经建立的长连接是不能被迁移的。

因此,长连接服务集群的管理技术和技巧非常重要,它主要体现在以下几点:

(1)       加强监控在线用户量的增长情况,要在长连接服务的承载能力范围内时就开始预先添加长连接服务,而不是等到现有系统承载不了的时候再添加;

(2)       合理制定负载均衡策略,当新增长连接服务时,不要在新增初期把新增的客户端全部都负载到新增的长连接服务上,而是以适当的高概率将新增用户导向至新长连接服务。

4.2 消息缓存集群

推送系统中主要用缓存集群存储待拉取的消息,在推送系统的消息缓存集群中,每个有待拉取消息的客户端都被分配一个消息队列,拉模式和混合模式中,所有发往该客户端的消息都会依次存储到该消息队列中,待推送客户端SDK拉取并处理之后,再由推送客户端SDK主动删除。

设计消息缓存时应该注意以下问题:

(1)       缓存集群的易扩展性;推送系统对缓存的使用将基于离线用户量(因为在线用户的消息将会很快被拉取走并删除)、每个用户的消息数量两个因素的增长而快速增长,它要求消息缓存集群的能非常方便扩展,以支持更多的客户端;

(2)       消息队列的时效性;推送系统不是IM,不应为用户提供太长时间甚至无限期的缓存,它缓存消息的时效性一般都远小于IM,因此,在推送系统中应该限制每个客户端的消息缓存队列的长度,可以采取的措施有很多,例如:限制时间或限制个数,限制时间是指推送系统为每个客户端缓存最近定长时间(例如2周)内的消息,如果客户端长时间不登录,缓存的消息一旦超过此时间,将会被缓存删除;限制个数是指推送系统为每个客户端限制了缓存消息队列的长度,一旦缓存的消息超过队列长度,再发送的消息将会挤掉最早的那条消息。无论采取哪种限制措施,基于安全性、代价、访问效率等各方面考虑,推送系统都应对消息缓存队列的长度进行限制。

(3)       缓存的易用性和及时性;推送系统所采用的缓存应该能直接满足消息存取的要求,以简化开发的复杂度,除此之外,缓存集群应能满足对消息队列的快速访问,包括:从指定位置开始读取、删除等。

消息缓存集群建议采用Redis来构建。Redis本身的数据结构类型非常丰富,例如它本身支持的List类型就可以直接用作消息队列;另外,Redis的访问速度也非常快,能够满足推送系统的需求。Redis的集群化方案也非常多,非常便于推送系统构建缓存集群,例如Codis,不过大多数集群方案不支持lua脚本和pipline等操作,如果实现过程中需要用到这些功能就要慎重考虑一下。

二、        心跳

心跳是指服务端或者客户端定期发送特定消息,以告知对端自己依然正常的消息发送机制,对端接收到该消息之后给予回复,心跳消息有时也被称为ping/pong消息。心跳机制的作用是让长连接服务能尽早检查出异常断开(未走正常的四次分手流程)的客户端连接。由于TCP协议本身无法感知弱网络情况下TCP连接的的连、断情况(详见《TCP对连接断开的感知——保活定时器》,地址为:

http://blog.csdn.net/houjixin/article/details/19153325http://houjixin.blog.163.com/blog/static/35628410201411310232267/),

需要应用层采取措施定时检查连接是否有效;

需要注意:心跳机制由于需要定时发送心跳数据,它并不能及时检查客户端的连接好坏,因此服务端也无法实时感知到每个连接的状态(主要是弱网情况下的网络连接情况),在心跳间隔内,连接异常断开时,服务端依然无法感知。

心跳对客户端的影响

如果心跳时间太短,则频繁的心跳消息不仅会增加客户端的耗电量、流量,而且会对服务端产生较大的压力,尤其当长连接服务承载的连接量较大时,该问题尤为明显。如果心跳时间太长,则连接一旦异常断开,客户端与服务端都无法感知,自然也就无法及时完成消息推送。

心跳时间应该设置为多少?

首先要明确一点:不同网络情况下,心跳的限制值不一样,一般2G或早期3G时运营商会有5分钟的限制,在4G网络情况下,此值可能会大一些,在WIFI情况下该心跳数据还可以更长,有可能会达到部分OSTCP的默认超时时间2小时,因此,建议在移动网络情况下尽量不要超过5分钟。

动态心跳

动态心跳是指心跳时间不是固定值,而是随着网络的状态而自动探测并设定合适的值,它既能减少客户端收发心跳数据包造成的耗电、耗流量的问题,也能满足尽快检测连接状态的需求,但是动态心跳实现起来非常复杂,考虑的场景比较多,一旦考虑不周就可能无法及时感知连接的异常断开;动态心跳有非常多中方法,这列举两种简单探测机制:(1)增量探测,根据网络类型确定探测的上限Amax和下限Amin,发送心跳包从下限Amin开始,每次都增加一个增量x,直到出现连接断开的情况或者达到上限Amax;这种方式尤其注意一旦出现连接断开要注意采取快速恢复机制,否则就可能造成短时间内客户端的频繁断开;(2)减量探测根据网络类型确定探测的上限Dmax和下限Dmin,发送心跳包从上限Dmin开始,每次都减去一个时间长度x,直到连接正常,或者到达下限,这两种实现机制太过简单,在实际运用过程中往往需要多次短开才能确定一个心跳值,而且确定的心跳值也不是最优的。

心跳包的发送频度优化

在自己开发长连接服务器时尤其要注意心跳包和业务包的结合可以大大降低心跳包的数量,例如一旦有任何消息正常收到或者发出,就认为该连接正常,此时就可以不用发心跳包,即有业务数据包时,把业务数据包也当做心跳包来使用;

客户端和服务端对心跳的检测机制

一旦客户端和服务端商定好心跳之后,后续心跳将按照协商的时间间隔发送心跳消息,此时主动发送心跳包的一方要在协商值之前发送心跳,例如实际发送心跳间隔为协商值80%,而接收心跳包的一方在检查心跳间隔的周期为协商值的1.5倍,这样可以防止网络传输延迟造成的连接误判。

  评论这张
 
阅读(27)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017