本文由will分享,个人博客zhangyaoo.github.io,原题“基于Netty的IM系统设计与实现”,有修订和重新排版。
本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。
本文中针对这套架构和系统设计,同时还会提供完整的源码,比较适合有一定Java开发能力和Netty知识的IM初学者。
(相关资料图)
*友情提示:如果你对IM即时通讯的基础技术理论了解的太少,建议可以先读:《新手入门一篇就够:从零开发移动端IM》。
技术交流:
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》
- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地址点此)
(本文已同步发布于:http://www.52im.net/thread-4257-1-1.html)
本文配套源码的开源托管地址是:
如果你访问Github太慢,可直接从以下附件打包下载:
fastim-master(52im.net).zip(1.12 MB, 下载次数:5, 售价:1金币)
完整源码的目录结构,如下图:
关于 Netty 是什么,这里简单介绍下:
Netty 是一个 Java 开源框架。Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。
Netty 相当简化和流线化了网络应用的编程开发过程,例如,TCP 和 UDP 的 Socket 服务开发。
有关Netty的入门文章:
1)新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
2)写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略
3)史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战
如果你连Java NIO都不知道,下面的文章建议优先读:
Netty源码和API 在线查阅地址:
本次的IM系统设计主要基于可扩展性高可用原则,把网关层、逻辑层、数据层进行了分离,并且还要支持分布式部署。
以下是整体系统的架构设计概览图:
下面将针对整体架构来逐一分享设计的主要思路等。
客户端的设计主要从以下几点出发:
1)方案一:
设计思路:
注:上述生成器可以用18年[(2^29-1)/3600/24/365]左右,一秒内最多产生4个消息。
优点:可以在断线重连和重装APP的情况下,18年之内是有序的。
缺点:每秒只能发4个消息,限制太大,对于群发场景不合适。
改进:使用long进行传输,年限扩展很久并且有序。
2)方案二:
设计思路:
优点:可以在断线重连和重装APP的情况下,接收者可以按照发送者发送时序来显示,并且对发送消息的速率没限制。
IM接入层的高可用、负载均衡、扩展性全部在这里面做。客户端通过LSB,来获取gate IP地址,通过IP直连。
这样做的目的是:
上述设计存在一个问题:就是当某个实例重启后,该实例的连接断开后,客户端会发起重连,重连就大概率转移其他实例上,导致最近启动的实例连接数较少,最早启动的实例连接数较多。
解决方法:
GATE层网关设计主要遵从以下几点:
logic按照分布式微服务的拆分思想进行拆分,拆分为多个模块,集群部署。
主要包括:
消息logic服务集成路由客户端的SDK,SDK职责主要是:
针对上述第4)点:
SDK和网关底层通信设计:
如上图所示:网关层到服务层,只需要单向传输发请求,网关层不需要关心调用的结果。而客户端想要的ack或者notify请求是由SDK发送数据到网关层,SDK也不需要关心调用的结果,最后网关层只转发数据,不做额外的逻辑处理。
SDK和所有的网关进行长连接,当发送信息给客户端时,根据路由寻址信息,即可通过长连接推送信息。
通信协议设计的主要目标是:
IM协议采用二进制定长包头和变长包体来实现客户端和服务端的通信,并且采用谷歌protobuf序列化协议。
设计如下:
各个字段解释如下:
PS:如果你对Protobuf不了解,建议详读以下系列文章:
1.《强列建议将Protobuf作为你的即时通讯应用数据传输格式》
2.《IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!》
3.《IM通讯协议专题学习(二):快速理解Protobuf的背景、原理、使用、优缺点》
4.《IM通讯协议专题学习(三):由浅入深,从根上理解Protobuf的编解码原理》
5.《IM通讯协议专题学习(四):从Base64到Protobuf,详解Protobuf的数据编码原理》
6.《IM通讯协议专题学习(五):Protobuf到底比JSON快几倍?全方位实测!》
7.《IM通讯协议专题学习(六):手把手教你如何在Android上从零使用Protobuf》
8.《IM通讯协议专题学习(七):手把手教你如何在NodeJS中从零使用Protobuf》
9.《IM通讯协议专题学习(八):金蝶随手记团队的Protobuf应用实践(原理篇)》
10.《IM通讯协议专题学习(九):手把手教你如何在iOS上从零使用Protobuf》
针对数据data,网关gate层不做反序列化,反序列化步骤在service做,避免重复序列化和反序列化导致的性能损失。
网关层不做业务逻辑处理,只做消息转发和推送,减少网关层的复杂度。
为防止消息传输过程中不被截获、篡改、伪造,采用TLS传输层加密协议(可参考《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》)。
私有化协议天然具备一定的防窃取和防篡改的能力,相对于使用JSON、XML、HTML等明文传输系统,被第三方截获后在内容破解上相对成本更高,因此安全性上会更好一些。
消息存储安全性:将针对账号密码的存储安全可以通过“高强度单向散列算法”和“加盐”机制来提升加密密码可逆性;IM消息采用“端到端加密”方式来提供更加安全的消息传输保护。
安全层协议设计:基于动态密钥,借鉴类似SSL,不需要用证书来管理(可参考《探讨组合加密算法在IM中的应用》)。
一个正常的消息流转需要如下图所示的流程:
如上图所示:
需要考虑的是:一个健壮的IM系统需要考虑各种异常情况,比如丢消息,重复消息,消息时序问题。
我的设计和实现思路是这样的:
相关资料可参考:
1.《从客户端的角度来谈谈移动端IM的消息可靠性和送达机制》
2.《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》
3.《IM消息送达保证机制实现(二):保证离线消息的可靠投递》
4.《IM开发干货分享:如何优雅的实现大量离线消息的可靠投递》
5.《理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨》
6.《融云技术分享:全面揭秘亿级IM消息的可靠投递机制》
超时与重传机制将导致接收的client收到重复的消息,具体做法就是一份消息使用同一个消息ID进行去重处理。
相关资料可参考:
1.《IM群聊消息如此复杂,如何保证不丢不重?》
2.《完全自已开发的IM该如何设计“失败重试”机制?》
消息乱序影响的因素:
以上:如果保持绝对的实现,那么只能是一个发送方,一个接收方,一个线程阻塞式通讯来实现。那么性能会降低。
1)如何保证时序:
单聊:通过发送方的绝对时序seq,来作为接收方的展现时序seq。
实现方式:可以通过时间戳或者本地序列号方式来实现
缺点:本地时间戳不准确或者本地序列号在意外情况下可能会清0,都会导致发送方的绝对时序不准确
群聊:因为发送方多点发送时序不一致,所以通过服务器的单点做序列化,也就是通过ID递增发号器服务来生成seq,接收方通过seq来进行展现时序。
实现方式:通过服务端统一生成唯一趋势递增消息ID来实现或者通过redis的递增incr来实现。
缺点:redis的递增incr来实现,redis取号都是从主取的,会有性能瓶颈。ID递增发号器服务是集群部署,可能不同发号服务上的集群时间戳不同,可能会导致后到的消息seq还小。
群聊时序的优化:按照上面的群聊处理,业务上按照道理只需要保证单个群的时序,不需要保证所有群的绝对时序,所以解决思路就是同一个群的消息落到同一个发号service上面,消息seq通过service本地生成即可。
2)客户端如何保证顺序:
为什么要保证顺序?因为消息即使按照顺序到达服务器端,也会可能出现:不同消息到达接收端后,可能会出现“先产生的消息后到”“后产生的消息先到”等问题。所以客户端需要进行兜底的流量整形机制
如何保证顺序?可以在接收方收到消息后进行判定,如果当前消息序号大于前一条消息的序号就将当前消息追加在会话里。否则继续往前查找倒数第二条、第三条等消息,一直查找到恰好小于当前推送消息的那条消息,然后插入在其后展示。
相关资料可参考:
《零基础IM开发入门(四):什么是IM系统的消息时序一致性?》
《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》
《如何保证IM实时消息的“时序性”与“一致性”?》
《一个低成本确保IM消息时序的方法探讨》
整体消息推送和拉取的时序图如下:
本系统是通过推拉结合来进行服务器端消息的推送和客户端的拉取。我们知道单pull和单push有以下缺点。
对于单pull:
对于单push:
对于推拉结合:
为什么做隔离?
如果客户端一边正在拉取数据,一边有新的增量消息push过来。
如何做隔离?
本地设置一个全局的状态,当客户端拉取完离线消息后设置状态为1(表示离线消息拉取完毕)。当客户端收到拉取实时消息,会启用一个轮询监听这个状态,状态为1后,再去向服务器拉取消息。
如果是push消息过来(不是主动拉取),那么会先将消息存储到本地的消息队列中,等待客户端上一次拉取数据完毕,然后将数据进行合并即可。
相关资料可参考:
《阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化》
《阿里IM技术分享(七):闲鱼IM的在线、离线聊天数据同步机制优化实践》
以下是我设计的场景:
根据以上业务情况,来设计分布式ID:
优点:
缺点:当并发度不高的时候,时间跨毫秒的消息,区分不出来消息的先后顺序。因为时间跨毫秒的消息生成的ID后面的最后一位都是0,后续如果按照消息ID维度进行分库分表,会导致数据倾斜。
两种解决方案:
相关资料可参考:
《微信的海量IM聊天消息序列号生成实践(算法原理篇)》
《微信的海量IM聊天消息序列号生成实践(容灾方案篇)》
《解密融云IM产品的聊天消息ID生成策略》
《深度解密美团的分布式ID生成算法》
《开源分布式ID生成器UidGenerator的技术实现》
《深度解密滴滴的高性能ID生成器(Tinyid)》
实现思路大致如下:
分布式锁保证总未读数和会话未读数一致:
14.2群聊消息未读数的难点和优化思路
对于群聊来说,消息未读数的技术难点主要是:一个群聊每秒几百的并发聊天,比如消息未读数,相当于每秒W级别的写入redis,即便redis做了集群数据分片+主从,但是写入还是单节点,会有写入瓶颈。
我的优化思路是:按群ID分组或者用户ID分组,批量写入,写入的两种方式:定时flush和满多少消息进行flush。
本套IM系统在设计时,将网关分为了接入层网关和应用层网关两种。
我的设计目标是:
主要技术要点:
设计方案(一个Notify包的数据经网关的线程模型图):
我的设计目标是:
主要技术要点:
设计方案(一个请求包的数据经网关的架构图):
主要从以下几个方面入手:
技术难点主要是:消息扇出大,比如每秒群聊有50条消息,群聊2000人,那么光一个群对系统并发就有10W的消息扇出。
优化思路:
相关资料:
1.《网易云信技术分享:IM中的万人群聊技术方案实践总结》
2.《企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等》
3.《融云IM技术分享:万人群聊消息投递方案的思考和实践》
具体的代码优化思路就是:本地会话信息由一个hashmap保持,导致锁机制严重,按照用户标识进行hash,讲会话信息存在多个map中,减少锁竞争。同时利用双buffer机制,避免未读计数写入阻塞。
背景:消息下发到群聊服务后,需要发送拉取通知给接收者,具体逻辑是群聊服务同步消息到路由层,路由层发送消息给接收者,接收者再来拉取消息。
问题:如果消息连续发送或者对同一个接收者连续发送消息频率过高,会有许多的通知消息发送给路由层,消息量过大,可能会导致logic线程堆积,请求路由层阻塞。
解决:发送者发送消息到逻辑层持久化后,将通知消息先存放一个队列中,相同的接收者接收消息通知消息后,更新相应的最新消息通知时间,然后轮训线程会轮训队列,将多个消息会合并为一个通知拉取发送至路由层,降低了客户端与服务端的网络消耗和服务器内部网络消耗。
好处:保证同一时刻,下发线程一轮只会向同一用户发送一个通知拉取,一轮的时间可以自行控制。
主要是:
智能心跳策略:比如正在发包的时候,不需要发送心跳。等待发包完毕后在开启心跳。并且自适应心跳策略调整。
相关资料:
《为何基于TCP协议的移动端IM仍然需要心跳保活机制?》
《一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等》
《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》
《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》
《融云技术分享:融云安卓端IM产品的网络链路保活技术实践》
《移动端IM实践:实现Android版微信的智能心跳机制》
《万字长文:手把手教你实现一套高效的IM长连接自适应心跳保活机制》
背景:高峰期系统压力大,偶发的网络波动或者机器过载,都有可能导致大量的系统失败。加上IM系统要求实时性,不能用异步处理实时发过来的消息。所以有了柔性保护机制防止雪崩。
柔性保护机制开启判断指标,当每个指标不在平均范围内的时候就开启。
这些判断指标主要是:
当开启了柔性保护机制,那么会返回失败,用户端体验不友好,如何优化?
以下是我的优化思路:
gate层重启升级或者意外down机有以下问题:
解决方案如下:
Redis的作用背景:
如果Redis宕机,会造成下面结果:
Redis宕机兜底处理策略:
核心设计要点:
群用户消息表 t_group_user_msg:
群消息表 t_group_msg:
参考资料:
1.《一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》
2.《基于Netty,从零开发一个IM服务端》
抢红包的大致核心逻辑如下:
相关资料:
《社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等》
《社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进》
《社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节》
《社交软件红包技术解密(四):微信红包系统是如何应对高并发的》
《社交软件红包技术解密(五):微信红包系统是如何实现高可用性的》
《社交软件红包技术解密(六):微信红包系统的存储层架构演进实践》
《社交软件红包技术解密(七):支付宝红包的海量高并发技术实践》
《社交软件红包技术解密(八):全面解密微博红包技术方案》
《社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等》
《社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践》
《社交软件红包技术解密(十一):解密微信红包随机算法(含代码实现)》
《社交软件红包技术解密(十二):解密抖音春节红包背后的技术设计与实践》
假设是用户A发消息给用户B ,以下是完整的业务流程。
1)A打包数据发送给服务端,服务端接收消息后,根据接收消息的sequence_id来进行客户端发送消息的去重,并且生成递增的消息ID,将发送的信息和ID打包一块入库,入库成功后返回ACK,ACK包带上服务端生成的消息ID。
2)服务端检测接收用户B是否在线,在线直接推送给用户B。
3)如果没有本地消息ID则存入,并且返回接入层ACK信息;如果有则拿本地sequence_id和推送过来的sequence_id大小对比,并且去重,进行展现时序进行排序展示,并且记录最新一条消息ID。最后返回接入层ack。
4)服务端接收ACK后,将消息标为已送达。
5)如果用户B不在线,首先将消息存入库中,然后直接通过手机通知来告知客户新消息到来。
6)用户B上线后,拿本地最新的消息ID,去服务端拉取所有好友发送给B的消息,考虑到一次拉取所有消息数据量大,通过channel通道来进行分页拉取,将上一次拉取消息的最大的ID,作为请求参数,来请求最新一页的比ID大的数据。
假设是用户A发消息给群G,以下是完整的业务流程。
1)登录,TCP连接,token校验,名词检查,sequence_id去重,生成递增的消息ID,群消息入库成功返回发送方ACK。
2)查询群G所有的成员,然后去redis中央存储中找在线状态。离线和在线成员分不同的方式处理。
3)在线成员:并行发送拉取通知,等待在线成员过来拉取,发送拉取通知包如丢失会有兜底机制。
4)在线成员过来拉取,会带上这个群标识和上一次拉取群的最小消息ID,服务端会找比这个消息ID大的所有的数据返回给客户端,等待客户端ACK。一段时间没ack继续推送。如果重试几次后没有回ack,那么关闭连接和清除ack等待队列消息。
5)客户端会更新本地的最新的消息ID,然后进行ack回包。服务端收到ack后会更新群成员的最新的消息ID。
6)离线成员:发送手机通知栏通知。离线成员上线后,拿本地最新的消息ID,去服务端拉取群G发送给A的消息,通过channel通道来进行分页拉取,每一次请求,会将上一次拉取消息的最大的ID,作为请求参数来拉取消息,这里相当于第二次拉取请求包是作为第一次拉取的ack包。
7)分页的情况下,客户端在收到上一页请求的的数据后更新本地的最新的消息ID后,再请求下一页并且带上消息ID。上一页请求的的数据可以当作为ack来返回服务端,避免网络多次交互。服务端收到ack后会更新群成员的最新的消息ID。
主要是在线状态维护。
相比于HTTP请求的业务系统,接入层有状态,必须维持心跳和会话状态,加大了系统设计复杂度。
请求通信模型不一样。相比于HTTP请求一个request等待一个response通信模型,IM系统则是一个数据包在全双工长连接通道双传输,客户端和服务端消息交互的信令数据包设计复杂。
MQ作为解耦可以有以下好处:
但是缺点也有:
综上:是否考虑使用MQ需要架构师去考量,比如考虑业务是否允许、或者系统的流量、或者高可用设计等等影响因素。本项目基于使用成本、耦合成本和运维成本考虑,采用Netty作为底层自定义通信方案来实现,也能同样实现层级调用。
参考资料:《阿里IM技术分享(九):深度揭密RocketMQ在钉钉IM系统中的应用实践》。
可以有以下好处:
因为TCP Keepalive状态无法反应应用层状态问题,如进程阻塞、死锁、TCP缓冲区满等情况。
并且要注意心跳的频率,频率小则可能及时感知不到应用情况,频率大可能有一定的性能开销。
参考资料:《为何基于TCP协议的移动端IM仍然需要心跳保活机制?》、《彻底搞懂TCP协议层的KeepAlive保活机制》。
IM消息是非常庞大的,比如说群聊相关业务、推送,对于一些业务上可以忍受的场景,尽量使用MQ来解耦和通信,来降低同步通讯的服务器压力。
我的设计是存1份,读扩散。
存多份的话(也就是写扩散)下同一条消息存储了很多次,对磁盘和带宽造成了很大的浪费。可以在架构上和业务上进行优化,来实现读扩散。
当然,对于IM是使用读扩散还是写扩散来实现,这需要根据IM产品的业务定位来决定。比如微信就是写扩散(详见《企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等》),而钉钉却是读扩散(详见《深度解密钉钉即时消息服务DTIM的技术设计》)。
严格递增会有单点性能瓶颈,比如MySQL auto increments。
redis性能好但是没有业务语义,比如缺少时间因素,还可能会有数据丢失的风险,并且集群环境下写入ID也属于单点,属于集中式生成服务。
小型IM可以根据业务场景需求直接使用redis的incr命令来实现IM消息唯一ID。
本项目采用snowflake算法实现唯一趋势递增ID,即可实现IM消息中,时序性,重复性以及查找功能。
关于消息ID的生成,可以参考下面的系列文章:
《微信的海量IM聊天消息序列号生成实践(算法原理篇)》
《微信的海量IM聊天消息序列号生成实践(容灾方案篇)》
《解密融云IM产品的聊天消息ID生成策略》
《深度解密美团的分布式ID生成算法》
《开源分布式ID生成器UidGenerator的技术实现》
《深度解密滴滴的高性能ID生成器(Tinyid)》
gate会接收客户端的连接请求(被动),需要外网监听端口;entry会主动给logic发请求(主动);entry会接收服务端给它的通知请求(被动),需要内网监听端口。一个端口对内,一个端口对外。
维护在每个msg层内存中有状态:多级缓存避免和中间件多次交互,并发高。
维护在中央存储的redis中,msg层无状态,redis压力大,每次交互IO网络请求大。
业务初期为了减少复杂度,可以维护在Redis中。
网关层到服务层,只需要单向传输发请求,网关层不需要关心调用的结果。
而客户端想要的ack或者notify请求是由SDK发送数据到网关层,SDK也不需要关心调用的结果,最后网关层只转发数据,不做额外的逻辑处理。
SDK和所有的网关进行长连接,当发送信息给客户端时,根据路由寻址信息,即可通过长连接推送信息
本地TCP写操作成功,但数据可能还在本地写缓冲区中、网络链路设备中、对端读缓冲区中,并不代表对端应用读取到了数据。
如果你还不理解,可以读读这篇文章《从客户端的角度来谈谈移动端IM的消息可靠性和送达机制》。
主要是从以下方面考虑:
在保证消息实时性的前提下,对于单聊,直接推送。
对于群聊,由于群聊人数多,推送的话一份群消息会对群内所有的用户都产生一份推送的消息,推送量巨大。
解决办法是按需拉取,当群消息有新消息时候发送时候,服务端主动推送新的消息数量,然后客户端分页按需拉取数据。
IM协议简单最好,如果让其他的业务请求混进IM协议中,会让其IM变的更复杂,比如查找离线消息记录拉取走http通道避免tcp 通道压力过大,影响即时消息下发效率。
在比如上传图片和大文件,可以利用HTTP的断点上传和分段上传特性。
主要有:
《跟着源码学IM(一):手把手教你用Netty实现心跳机制、断线重连机制》
《跟着源码学IM(二):自已开发IM很难?手把手教你撸一个Andriod版IM》
《跟着源码学IM(三):基于Netty,从零开发一个IM服务端》
《跟着源码学IM(四):拿起键盘就是干,教你徒手开发一套分布式IM系统》
《跟着源码学IM(五):正确理解IM长连接、心跳及重连机制,并动手实现》
《跟着源码学IM(六):手把手教你用Go快速搭建高性能、可扩展的IM系统》
《跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天》
《跟着源码学IM(八):万字长文,手把手教你用Netty打造IM聊天》
《跟着源码学IM(九):基于Netty实现一套分布式IM系统》
《跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)》
《跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)》(* 本文)
《SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能》
[1]史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战
[2]强列建议将Protobuf作为你的即时通讯应用数据传输格式
[3]IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!
[4]微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
[5]探讨组合加密算法在IM中的应用
[6]从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
[7]IM消息送达保证机制实现(一):保证在线实时消息的可靠投递
[8]理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨
[9]融云技术分享:全面揭秘亿级IM消息的可靠投递机制
[10]IM群聊消息如此复杂,如何保证不丢不重?
[11]零基础IM开发入门(四):什么是IM系统的消息时序一致性?
[12]一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[13]如何保证IM实时消息的“时序性”与“一致性”?
[14]阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化
[15]微信的海量IM聊天消息序列号生成实践(算法原理篇)
[16]社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等
[17]网易云信技术分享:IM中的万人群聊技术方案实践总结
[18]企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
[19]融云IM技术分享:万人群聊消息投递方案的思考和实践
[20]为何基于TCP协议的移动端IM仍然需要心跳保活机制?
[21]一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等
[22]微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
[23]融云技术分享:融云安卓端IM产品的网络链路保活技术实践
[24]阿里IM技术分享(九):深度揭密RocketMQ在钉钉IM系统中的应用实践
[25]彻底搞懂TCP协议层的KeepAlive保活机制
[26]深度解密钉钉即时消息服务DTIM的技术设计
(本文已同步发布于:http://www.52im.net/thread-4257-1-1.html)