大家好,我是砸锅。一个摸鱼八年的后端开发。熟悉 Go、Lua。今天和大家一起学习 IM 系统😊
本文正在参加「金石计划」
心跳机制
心跳机制通过持续往连接上发送模拟数据来试探连接的可用性,也可以让连接在没有真正业务数据收发的时候,也持续有数据流通,不会被中间的运营商认为连接已经无用了
之所以可以实现消息的服务端推送,是因为针对每一台上线的设备,都会在 IM 服务端维护相应的用户设备和网络连接的映射关系。一般为了节省网络开销,会在服务端临时缓存一些没必要每次请求都携带的客户端信息(app 版本号、操作系统、网络状态),一旦建立长连接之后首次需要携带这些信息,后续都可以不携带
客户端发出心跳包,在一定的超时时间内(通常要大于一个心跳的间隔),都没有收到 IM 服务端的响应,客户端则可以认为和服务端的长连接不可用,客户端可以尝试断线重连
心跳检测的实现方式
TCP Keepalive
TCP 的 Keepalive 是操作系统的 TCP / IP 协议栈实现的一部分,对于本机 TCP 连接,会在连接空闲期按一定频次,自动发送不携带数据的探测报文,来探测对象是否存在。操作系统是默认关闭这个特性的,需要应用层来开启
默认三个配置:心跳周期 2 小时,失败后重试 9 次,超时时间 75s
TCP Keepalive 由于易用性好、网络消耗小等优势,在很多 IM 系统里都有开启使用,缺点在于心跳间隔灵活性比较差,一台服务器某一个时间只能调整为固定间隔的心跳,并且虽然 TCP Keepalive 可以用于连接层存活的探测,但是不代表真正的应用层处于可用状态,有可能 IM 系统已经出现异常了
应用层心跳
应用层心跳比 TCP Keepalive 更加灵活和准确,实际上就是客户端每隔一段时间间隔,向 IM 服务端发送一个业务层的数据包告知自身存活。如果 IM 服务端在一定时间内没有收到心跳包,就可以认定客户端由于某种原因不可达了,这时候 IM 服务器就可以把这个连接断开,清除相应分配的其他资源

由于网络数据传输有一定延迟,服务端判断连接是否空闲的超时时间一定要大于心跳间隔时间,避免由于网络传输延迟导致连接可用性的误判
智能心跳
由于每个地方运营商在不同网络类型下 NAT 超时时间差异性很大,如果采用固定频率的应用层心跳虽然实现简单,但是对于设备 CPU、电量、网络流量等资源无法可以做到最大程度的节约
智能心跳是让心跳间隔可以根据网络环境来自动调整,通过不断自动调整心跳间隔的方式,逐步逼近 NAT 超时临界点,在保证 NAT 不超时的情况下尽量节约设备资源
多终端漫游
多终端漫游有两个前置条件:一个是设备维度的在线状态,一个是离线消息存储
多端同时登录在线的用户,在发送消息给接收方时,也要发给发送方的其他登录设备。离线存储的消息在用户多端登录之后,就可以从存储中获取到离线期间收发的消息
离线消息的处理
消息索引表是收发双方的会话维度,而获取离线消息的时候是接收方或者发送方的单个用户维度来获取数据的,没必要按会话来存,只需要按 UID 来存储即可。此外,还有一个需要考虑的点,离线消息的存储成本是比较高的,而我们并不知道用户到底有几个设备,因此离线消息的存储一般都会有时效和条数的限制,比如保留 1 周时间,最多存储 1000 条,这样如果用户一台设备很久不登录然后某一天再上线,只能从离线消息存储中同步最近一周的历史聊天记录
用户离线重登之后,也不能全量获取离线消息。会造成流量资源浪费,还会导致消息重复以及信令重复执行。通常采取版本号来实现多终端和服务端的数据同步:
- 每个用户拥有一套自己的版本号序列空间
- 每个版本号在该用户的序列空间都具备唯一性,一般是 64 位
- 当有消息或者信令需要推送给该用户时,会为每条消息或者信令生成一个版本号,并连同消息或者信令存入离线存储中,同时更新服务端维护的该用户的最新版本号
- 客户端接收到消息或者信令后,需要更新本地的最新版本号为收到的最后一条消息或者信令的版本号。当离线的用户上线时,会提交本地最新版本号到服务端,服务端比对服务端维护的该用户的最新版本号和客户端提交上来的版本号,如不一致,服务端根据客户端的版本号从离线存储获取“比客户端版本号新”的消息和信令,并推送给当前上线的客户端

其实就是根据版本号来获取增量消息,重复的消息客户端可以利用消息 ID 去重
如果离线存储写入失败的话,会造成消息逻辑性错乱。所以可以将离线消息存储的格式改成不仅存储当前版本号,还存储上一条消息的版本号。客户端获取离线消息的时候,如果服务端发现离线消息版本号不连续,就可以从会话消息表里获取最近联系人的部分最新消息
一般针对离线消息的下推会采用整体打包的方式来把多条消息合并成一个大包推下去,同时针对合并的大包还可以进一步进行压缩,通过降低包的大小不仅能减少网络传输时间,还能节省用户的流量消耗
此文章为3月Day7学习笔记,内容来源于极客时间《即时消息技术剖析与实战》 这门课真的非常好,推荐大家看看
本文正在参加「金石计划」