互联网+时代,消息量级的大幅上升,消息形式的多元化,给即时通讯云服务平台带来了非常大的挑战。高并发的IM系统背后究竟有着什么样的架构和特性?
以上内容由网易云信首席架构师内部分享材料整理而成。
相关阅读推荐
IM推送保障及网络优化详解(一):如何实现不影响用户体验的后台保活
IM推送保障及网络优化详解(二):如何做长连接加推送组合方案
IM即时通讯推送保障及网络优化详解(三):如何在弱网环境下优化大数据传输
本文要点:
-
网易云信
整体架构解析
-
云信中的
客户端
连接和接入点管理
-
服务化和高可用
网易 IM 云分层架构图解析
-
底层客户端
SDK
,覆盖了安卓,iOS,windows PC桌面端,web网页端和嵌入式设备等多个平台。在SDK层使用的网络协议有4层的TCP协议和基于7层的Socket.IO协议,后者专门用于Web SDK中提供长连接能力;除了集成到应用App中的SDK之外,还提供了供第三方服务器调用的API接口,基于Http协议;最后的A/V SDK是基于UDP协议的实时音视频SDK,用于实现基于网络的语音和视频通话。
-
网关层:提供客户端直接接入并维护与服务器之间的长连接;其中WebSDK直连的是Weblink服务,这是一个基于Socket.IO协议实现的长连接服务,而供AOS/IOS/PC等客户端SDK直连的是基于TCP协议的Link服务;在Link和WebLink服务中承担的一个非常重要的功能就是所有客户端长连接的管理,后面基于HTTP协议上的网关有API服务,和LBS服务等,其中LBS服务用于帮助客户端SDK选取最合适自己的网关接入点,优化网络效率;而API服务则直接提供来自第三方服务器的业务请求;
-
HA层:在网关接入层之上是HA层,网关接入层可提供给客户端直连,在link层和Service层之间有一个HA层用来解耦并提供高可用和易扩展等特性;在HA的具体实现方式上,对Link和WebLink这两个维持客户端长连接的服务,云信提供了协议路由的服务,代为分发业务请求,路由层会按照预定义的规则将来自客户端的请求转发到相应的业务节点上,当业务集群扩容之后路由服务马上能发现新的可用节点,并将请求转发过去,当发现业务节点出现异常时也会被路由层标记并隔离下线以备替换。
-
业务节点集群:在HA层上就是具体的业务节点集群,我们称为App服务,该服务处理具体的客户端请求,后端直连DB、cache等各种基础服务,这个集群中的节点的特点是轻量,并且每个节点都是无状态的,云信在实际部署这个集群时会跨网络环境部署,比如在同城双机房中分别部署一套业务服务节点,前端通过路由层来分发业务请求,平时正常时业务互为热备,平均分担线上的业务流量;当单一网络环境或者基础设施出现故障时马上会被路由服务检测到,并将该环境下的计算节点标记下线,将线上的流量请求全部转发到正常工作的集群中;从而提高了服务的整体可用性;配合监控平台等运维工具,业务节点的实时处理能力和容量使用情况都会被动态监测起来,当处理能力达到预设的水位线时会立即出发报警,运维人员可以非常方便快捷得通过自动部署平台对业务节点集群进行扩容。
-
业务层:其中包含了一些关键功能:核心的单聊消息、群聊消息和聊天室,通知等;以及用户信息托管,特殊关系管理等;还有面向API提供的如短信业务,回拨电话和专线会议等;还有实时音视频和直播功能等相关能力。
最右边列出的是从服务层上单独列出来的更重要的功能,包括与开发者应用的第三方数据同步,个性化的内容审核支持,超大群服务,登陆登出事件日志,漫游消息和云端消息历史功能,推送服务等等。
网易 IM 云部署拓扑
通过以下这张简化后的部署拓扑图可以对云信整体技术体系的有初步了解。最右边是客户端,客户端通过LBS服务获取到网关接入点列表,再与Link和WebLink这类长连接服务器建立起长连接,并进行RPC操作,所有来自客户端的请求都会通过路由层转发到后端的APP层,APP层实时处理并下发同步请求的处理结果,并把一些异步任务通过队列服务送到异步任务中,这些异步服务如大群消息的发送,推送服务,云端历史消息的存储和第三方的数据抄送同步服务等;在最下面的API接口上也是类似,API直接提供给第三方的服务器调用请求,API后端是各种独立的业务,如回拨电话,短信等;同样的所有的API后端业务请求也会产生相应的日志;和APP上的日志样,这些日志都会被通过日志采集平台收集到大数据平台中,一方面这类数据会存储到HDFS上用于作为数据统计分析的数据源;另一方面会被导入到Hbase等数据仓库中,用于提供日志检索和二次分析。
高并发 IM 系统连接层的优化实践
即时通讯功能中最重要的连接管理服务怎么做?消息快速到达的前提是客户端和服务器之间保持了稳定的连接;可以理解为奠定云信服务稳定性的基石。网关接入层需要解决的最重要的问题是什么?核心依然是稳定,安全和快速。
如何保证稳定?
网易云信SDK采用长连接机制来实现,并且由心跳的方式来检测断线和自动做重连,同时云信的SDK对移动网络等弱网环境非常多的优化工作,对移动端/PC端使用TCP来连接客户端与服务器,对与Web端使用socketIO协议,实现长连接的同时解决浏览器的兼容性问题;
如何实现安全?
云信要求所有在公网传输的数据都必须被加密;在SDK与服务器的连接建立过程中有一个复杂的秘钥协商过程,首先客户端需要生成一个一次性使用的加密秘钥,并使用非对称加密方式将这个秘钥加密之后传给服务器,加密数据会被服务器解密,之后该加密秘钥被保留在该长连接的会话信息中,数据来往均使用该秘钥加密,这是一个流式加密,可以有效防止中间人攻击和数据包回放等攻击手段。
如何保证快速?
首先是在网关接入点的选择上,借助LBS服务可以帮助客户端寻找到最适合自己的网关接入点,比如从ip等信息判断到的物理距离最近节点,其次在连接建立之后,长连接的机制可以极大提升消息上下行的速度,并且在数据传输过程中,云信会对数据包压缩传输,降低网络开销来升消息收发的速度;对频繁的前后台切换和重登陆这种移动客户端场景,SDK提供自动登录和重连等机制,即在UI界面起来的同时已经提前把消息通道建立;在接入网关的选择策略中,通过并行来提升连接建立的速度。
客户端与服务器建立长连接的过程展现
SDK接入的第一步是先请求LBS服务,获取可以进入的接入网关地址列表,LBS服务会根据多种策略条件来给客户端分配地址,常见的条件如下:
-
appkey, 通过appkey可以将一个特定的应用请求全部指向到一组特定的接入点,可用于专属服务器方案;
-
客户端ip,用于根据客户端所处的地理位置,为其就近分配接入网关,常见于海外节点的配置;
-
SDK版本号,将特定版本范围的客户端指向到特定网关,常用于新老版本升级的兼容方案,目前无实际使用案例;
-
特定环境标识,如智能客服环境等,用于将特定类型的app指向到特定网关,用于较大粒度环境隔离需求。
在从LBS服务请求到接入网关地址之后,客户端会按列表中的地址依次尝试建立连接;如果严格按照这样的顺序,那客户端建立连接的过程就会偏慢,为了加速接入过程,实际上在操作时,SDK都会使用本地缓存的最后一次LBS请求返回的地址列表来建立连接,同从LBS上拿一次新的地址列表缓存在本地,以备下次使用;当列表中的所有地址在尝试过一遍均失效,则会使用默认的link地址来建立连接;默认地址也失败是会出现415或者408这种网络错误码;
在获取到目标地址之后就会尝试建立TCP长连接,连接建立之后就会与服务器协商加密秘钥,并发出第一个鉴权包,鉴权完成之后这个长连接就是一个安全有效的连接,客户端可以发起后续的RPC请求;服务器也可以往这个连接上下发消息通知;如果秘钥协商失败或者鉴权失败,这个连接就会被认为是一个非法的连接请求,服务器会强制断开;
最后聊一下加速节点的问题 ,为了实现连接的快速,在网关接入点的分配时会优先距离该客户端最近的节点;这里将的加速节点就是为了更靠近用户提供的一种特殊节点。
加速节点的原理背景是运营商提供给个人用户的线路,不管是移动网络还是有线网络,其质量和IDC中心之间的网络总是有差异的;如果将整个用户链路中的关键路径替换成IDC之间的网络线路,那么对提升连接的稳定性和速度是有帮助的。
假设一个处于美国的客户通过手机网络访问位于杭州的一个网关接入点,由于客户端所在的网络是一个移动网络,直连到杭州服务器需要经过的链路非常长而且可能跳转的中间节点不可预期,在中国来说,还要跨越防火墙;所以直连的情况大部分可能就是无法连接,或者连接之后频繁断线。
我们提供了多层的加速节点:加入了加速节点之后,用户的整体链路中原来不可预期的那段链路都换成了质量较好的线路,用户直连到本地的加速节点的网络往往就会好很多。
下面说说不同的投递模式对消息送达效率的影响:
问题一:怎么让消息投递并发能力倍增?
在这张图中,上半部分表示的是一个点对点型的Link服务器,当发送者A发送一条消息之后,通过Link这条消息提交到APP中处理,APP中查询到该消息接收者B所在的Link服务器是Link y,于是向Link y服务器下发一条下行通知包,Link y上再找到用户B对应的长连接并将通知下发到客户端;这种模式下,所有的接入点Link对于所有的用户来说都是对等的,他可以接入到任何一个服务器中,任何消息的发送都必须在业务层查询到目标接收者所在的Link服务器,并往相应的Link服务器下发通知包,如果是一次群发行为,那就需要在业务APP上把所有群内的成员所在的Link列表都查询一遍;这是一个比较耗时的操作;并且是随着消息接收成员的数量不断上升开销不断增大;所以如果是需要往聊天室内发送消息,由于聊天室内的成员数量非常庞大,这种模式很快就会遇到性能瓶颈,消息投递的延时会非常严重;