苏宁即时通信系统改造实践

版权声明:原创文章 https://blog.csdn.net/cpongo5/article/details/88995845
\u003ch2\u003e一、从外采即时通信系统到自研\u003c/h2\u003e\n\u003cp\u003e苏宁最早出于办公的需要,考虑到外网访问权限控制及企业数据安全,没有采用QQ、微信这类公有云部署的聊天软件,而是采购了IBM的ST在公司内做私有化部署。随着日常办公中企业定制化需求的深入,业务部门对IM和OA一体化诉求的日益凸显,ST逐渐无法胜任,于是苏宁自研了一套IM系统。\u003c/p\u003e\n\u003cp\u003e苏宁产品定位的发展历程,从基础通讯,到企业办公、社交一体化,再到纯对内办公用途,最终服务于内同时对外提供一体化工作平台。系统架构也随着产品定位和产品架构的改变而改变,经历了从基于XMPP开源框架搭建的1.0系统到纯自研的2.0系统,直至目前正在研发的办公一体化、多活高可用、组件化、可轻量化灵活部署的3.0系统。\u003c/p\u003e\n\u003ch2\u003e二、基于XMPP的1.0系统\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca1791412d1e.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca1792b54cbe.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e上图所示的是苏宁构建于XMPP协议系统的实现原理。在实现上每个独立的Node Server都包含完整的业务逻辑模块,服务器和服务器之间均建有长连接通道用于交换报文。通过消息的已达已读回执,来确保消息的可靠传输。\u003c/p\u003e\n\u003cp\u003e上述实现方式有以下四个主要弊病:\u003c/p\u003e\n\u003cp\u003e1.由于Node之间均需维持长连接,随着服务端的横向扩展,长连接数是N*(N-1),增长非常快。\u003c/p\u003e\n\u003cp\u003e2.每台服务器都部署全量的服务,在部署上是种浪费,也不利于单个服务的升级和维护。\u003c/p\u003e\n\u003cp\u003e3.XMPP报文按照xml格式定义,三种通讯原语message、presence和iq的无效载荷非常重,按以下所示,即使不携带任何信息,头部至少也是上百字节(1字符=2字节),如果用iq实现业务层面的心跳,那也是上百字节。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;message \n to=\u0026quot;[email protected]/contact\u0026quot; \n type=\u0026quot;chat\u0026quot; \u0026gt; \n \u0026lt;body\u0026gt; 你好,在忙吗\u0026lt;/body\u0026gt; \n\u0026lt;/message\u0026gt; \n\n\u0026lt;presence from=\u0026quot;[email protected]/pda\u0026quot;\u0026gt; \n \u0026lt;show\u0026gt;xa\u0026lt;/show\u0026gt; \n \u0026lt;status\u0026gt;down the rabbit hole!\u0026lt;/status\u0026gt; \n\u0026lt;/presence\u0026gt; \n\n\u0026lt;iq from=\u0026quot;[email protected]/pda\u0026quot; \n id=\u0026quot;rr82a1z7\u0026quot; \n to=\u0026quot;[email protected]\u0026quot; \n type=\u0026quot;get\u0026quot;\u0026gt; \n \u0026lt;query xmlns=\u0026quot;jabber:iq:roster\u0026quot;/\u0026gt; \n\u0026lt;/iq\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e4.XMPP框架下的标准聊天消息以id为关键字,已经在本地的消息,往往会在对服务端的历史消息请求中,再次被拉取,无法做到按需增补、查漏补缺。究其本质,是这种消息结构的设置,无法完成增量比对。\u003c/p\u003e\n\u003cp\u003e采用XMPP协议也有以下三个主要优点:\u003c/p\u003e\n\u003cp\u003e1.XMPP有很多开源框架支撑,Ios端有XMPPFramework,java的有smack。能快速的开发和搭建自己的系统。\u003c/p\u003e\n\u003cp\u003e2.默认支持SASL和TLS的通道加密,传输更安全。\u003c/p\u003e\n\u003cp\u003e3.XMPP实体的地址称为Jabber Identifier或JID,作用相当于用户id,其格式为:[node’@’]domain[’/'resource],在组网上也配有协议网关。这就支持了与其他通信系统(如AIM、ICQ、IRC、MSN Massager、RSS0.9和Yahoo Massager)的互通,也可以在架构上支持多域名的部署及互通。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17980a0cba.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003ch2\u003e三、自研2.0系统\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca179aa0f219.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca179c515345.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e为了解决1.0系统的上述问题,同时支持高可用、支持SaaS多企业,苏宁开发了自研2.0系统。\u003c/p\u003e\n\u003cp\u003e在系统架构层面:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e服务端将接入层Node Server做薄,只负责通信接入以及协议解析,使用netty作为NIO通信层框架,同时将所有业务逻辑归并到业务逻辑层Center Server,Node和Center Server都可以自由扩展, Node和Center Server建立长连接通道交换数据。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eNode实现协议转换层和兼容XMPP连接方式,重构过渡期支持新老客户端互通。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e提供单独的passport,支持OAuth方式与其他账号体系联合登陆。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在业务逻辑层面:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e支持多企业,苏宁作为一个独立的企业,企业之间互相隔离;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e优化了消息归档机制;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e部分数据实体增加了版本号,变更拉取更省流量;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e消息按会话增加了long型序列号,离线消息由推送变成按需拉取,消息状态及已达已阅,通过消息区间来计算实现;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e单点登录SOA;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e增加批量接口、合并推送。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e高可用的基本要求是无单点故障,基本方法是分层 (分而治之) 与冗余 (失效转移),苏宁采取了以下措施:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e在应用层:负载均衡,集群;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在数据层:主从复制,读写分离;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在软件质量控制上:制定代码规范标准,代码控制,自动化测试,支持灰度发布;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在日志与监控上:服务端接入调用链监控,客户端接入稳定性、性能监控。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e四、消息的多端同步、终端消息的防乱序防丢失办法\u003c/h2\u003e\n\u003cp\u003e2.0系统业务逻辑层面的最大变化在于对消息的处理。因为IM系统的核心问题就是要解决聊天消息的离线和在线处理,解决好这个,系统问题就等于解决了一半。\u003c/p\u003e\n\u003cp\u003e我们想到的是两点:\u003c/p\u003e\n\u003cp\u003e1.移除离线缓冲,变离线消息推送为上线后终端的按需拉取,确保离线消息在各个客户端上均能被同步、按需补充。\u003c/p\u003e\n\u003cp\u003e2.作为配套算法,解决在线消息推送至终端时展示乱序的问题。\u003c/p\u003e\n\u003cp\u003e为了做到这个我们的技术方案为:\u003c/p\u003e\n\u003cp\u003e1.除消息的uuid(全局唯一标识)和ts(时间戳)以外,给消息定义long类型的seq(序列号),按会话独立编号,编号从1开始必须连续。服务端需保证任意两条同一会话内的消息,seq1 \u0026gt; seq2、ts1 \u0026gt; ts2互为充要条件;\u003c/p\u003e\n\u003cp\u003e2.终端上线后,由终端主动获取最近会话列表,从而得到每个会话的最大seq。在某个会话需要展示消息时,检查该会话当前的本地消息区间,向消息服务端请求本地缺失的消息,请求以seq区间为参数发起批量请求。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17a81b7974.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e3.终端在收到推送消息后,如果推送消息的seq与会话的最后一条消息的seq不连续,则先把消息加入到对应的缓冲窗口,并启动定时器。在收到后续的推送消息时,先检查缓冲窗口,把连续的一批消息退出窗口并写入数据库、展示给用户。如果超过定时器的时长,消息seq还未接续,则说明消息在传输过程中发生丢失,不再等待,一次性把窗口中的消息写入数据库并展示。丢失消息的补充,则通过前述的终端主动拉取来实现。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17aa45ad98.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17abd2bd0e.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e苏宁与业内典型的离线消息处理方案的差别如下图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17ad70a22d.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e1.移除了离线缓冲和配套数据库\u003c/p\u003e\n\u003cp\u003e2.流程1改为请求最近会话的最大seq\u003c/p\u003e\n\u003cp\u003e3.流程3返回最近会话的最大seq\u003c/p\u003e\n\u003cp\u003e4.流程4、6改为上述技术方案图示的按需拉取\u003c/p\u003e\n\u003ch2\u003e五、对于高性能移动端架构的一些想法\u003c/h2\u003e\n\u003cp\u003e由于用户对IM系统的体验是通过终端来感知的,所谓的高性能,最终还是要靠终端的算法来完成。\u003c/p\u003e\n\u003cp\u003e而具体到高性能的移动端设计这块,我觉得主要弄好以下几点:\u003c/p\u003e\n\u003cp\u003e1.需要独立的组件用于支撑登陆账号和网络协议这块。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17b134f9b6.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cp\u003e2.在协议层上构建逻辑层,对于移动端的上传下载、接口调用、内部算法调用,都要有统一的线程池管理。其他服务,如断线重连、心跳服务,数据库DAO服务,缓冲服务等都在逻辑层统一封装和控制。\u003c/p\u003e\n\u003cp\u003e3.服务端推送的变更,要先在数据库生效,再通知UI层生效,走消息总线通知。通知尽量细分颗粒度,变更的数据携带在通知中,避免通知接收方再去查数据库。\u003c/p\u003e\n\u003cp\u003e4.如果数据库使用的是系统默认的SQLite,要避免在主线程直接进行任何数据库操作(增删改查),因为SQLite并发锁的颗粒度是文件级别的,会导致后台线程的数据库操作阻塞前台的。一方面,我们要识别和优化端上最慢的数据库操作的耗时,另一方面,全在后台操作数据库,界面就不会随机卡顿。\u003c/p\u003e\n\u003cp\u003e5.在UI层还涉及到要防跳帧(用户可感知的60帧/秒–16ms/帧)。这需要持续关注和简化各个UI布局的嵌套层次,从而减少布局尺寸计算和渲染的开销。另外在android端需要特别关注内存抖动引发的跳帧:避免高频调用的方法中分配局部大对象频繁触发大GC,从而挂起主线程造成跳帧。\u003c/p\u003e\n\u003cp\u003e6.没有6了,一时大脑堵塞了。\u003c/p\u003e\n\u003ch2\u003e六、正在研发的3.0系统\u003c/h2\u003e\n\u003cp\u003e移动办公已成为企业提效、降成本的有效手段之一,在企业建设移动信息化的过程中,存在以下建设痛点:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca17b56ee5bd.png\" alt=\"\" /\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e内部沟通渠道混乱,信息外泄风险大\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e移动业务繁多,使用和管理混乱\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e信息系统孤岛现象严重,相互隔离\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e缺乏通用办公应用及个性化应用开发能力\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e为此苏宁正在研发办公一体化的3.0系统,具体的产品和技术架构稍后公司会通过正式渠道对外公布。\u003c/p\u003e\n\u003ch2\u003e七、结语\u003c/h2\u003e\n\u003cp\u003e个人技术面偏移动端架构,涉及服务端的实现可能阐述的不够透彻,唯希望能以有限文字多少给后来者提供些借鉴吧,谢谢。\u003c/p\u003e\n\u003ch4\u003e作者简介\u003c/h4\u003e\n\u003cp\u003e陈思佳,苏宁科技集团移动端资深架构师,主要负责苏宁移动通讯、IoT 、一体化工作平台等项目研发工作。在移动端架构方面拥有十多年的实践经验,先后就职于华为无线产品线、Motorola GSG(Global Software Group)。精通Android、iOS编程架构、开发工具,对IM协议及架构也有深厚积累。\u003c/p\u003e\n\u003cp\u003e赵一唯,苏宁科技集团服务端资深架构师,主要负责易适配、邮件系统、移动办公一体化平台等项目研发工作,并为IM产品线技术第一负责人。在分布式架构方面拥有十多年的实践经验,先后就职于ZTE中兴通讯、趋势科技、IBM等公司。精通java服务端编程,对多活、高可用的解决方案有独到见解,在IM协议及架构方面也有深厚积累。\u003c/p\u003e\n\u003cp\u003e更多内容,请关注前端之巅。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://static.geekbang.org/infoq/5ca235771b6e9.png\" alt=\"\" /\u003e\u003c/p\u003e\n

猜你喜欢

转载自blog.csdn.net/cpongo5/article/details/88995845