顶层设计-IM系统架构
一、系统总体架构概览
即时通讯(IM)系统的核心目标,是让用户可以随时随地稳定地发送和接收消息。为了支撑成千上万用户同时在线交流,我们需要将整个系统划分成多个专职模块,每个模块只负责一件事情,彼此协同配合。
最基础的一层是 WebSocket 服务。WebSocket 是一种保持长连接的通信方式,可以让客户端和服务器随时互发消息。但一个 WebSocket 服务器的连接数是有限的,一般能同时维护几千个连接,因此我们通常会部署多个 WebSocket 服务实例,组成一个“集群”,来支撑海量在线用户。
在 WebSocket 服务之上,还有一系列专门的服务模块:
-
IM 服务:负责消息的收发与转发,也就是把你发的消息送到对方那里。
-
Logic 服务:处理登录后的操作,比如你上线、加好友、建群,这些都归它管。
-
Auth 服务:负责登录验证,确保你是你。
-
Router 服务:像导航员一样,决定消息该送去哪台服务器上的哪个用户。
除了模块分工,IM 系统还有一个重要设计:消息一定要先保存再发出去。这保证了即使网络出问题,消息也不会丢。保存之后,系统会通过消息队列把消息交给后续处理模块继续处理,比如发送到你好友的“信箱”里。
总的来说,整个系统像流水线一样,每一步都专注做好一件事,最终让消息安全、快速地送达每一位用户手中。
二、核心服务模块介绍
整个 IM 系统就像一个团队,每个成员负责不同的工作。下面我们来看看这些“成员”都做些什么。
1. WebSocket 服务
这是系统的“入口”。每个在线用户,都会通过 WebSocket 和服务器保持一个长连接。这个连接就像一条专属通道,方便用户随时发消息、收消息。
但一个 WebSocket 服务器能撑的连接数量有限,一般几千个就到头了。所以我们会部署很多台,组成一个“集群”,大家一起分担压力。
2. IM 服务
这是系统中最重要的“中转站”。
你发出一条消息后,IM 服务会先把它保存到数据库,然后丢进一个消息队列,再交给后面专门的模块去处理。为什么要这样?为了确保消息不会丢失,即使网络闪了一下,消息也还在。
它还负责把消息转发给接收方,比如你发了一句话给朋友,IM 服务就会负责把这句话送过去。
3. Logic 服务
Logic(逻辑)服务管的是用户行为。
比如:
-
登录后多久没动了,要不要认为你掉线了?
-
你加了一个好友,要不要让对方知道?
-
创建一个群聊,拉了谁进来?
这些操作都属于“逻辑事件”,由这个服务来处理。
4. Auth 服务
Auth 是认证服务,意思是“你是谁”的确认。
比如你输入账号密码登录,系统会调用 Auth 服务确认这个账号是否合法。如果你用的是第三方登录(比如微信、GitHub),Auth 也负责对接这些服务,确保只有通过验证的人才能进来。
5. Router 服务
Router(路由)服务的职责是找人。
比如你要给好友发消息,系统得先知道:他现在在哪台服务器上?连的是哪一个 WebSocket 实例?Router 服务会告诉你消息应该往哪发。
当然可以,这里是 “三、消息处理机制” 的内容,继续保持通俗、清晰、简洁的风格,面向小白讲解:
三、消息处理机制
当你在聊天窗口里按下“发送”按钮,背后其实触发了一连串操作。下面我们来看看,一条消息从你手里出去,到达对方的手里,中间到底经历了什么。
1. 消息先入库,再发送
你发的每一条消息,系统都会先保存起来,也就是“入库”。
为什么要先保存?这是为了防止消息丢失。比如你发完消息后,网络突然断了,如果没保存就直接发,很可能这条消息就彻底丢了。保存之后,就算后续出问题,也可以补发。
所以,IM 服务会:
-
把消息写入数据库(比如 MongoDB、MySQL 等)
-
然后告诉你:“发送成功!”
2. 消息写入队列
消息保存后,不会直接发给对方,而是先丢到一个“消息队列”中。
这个队列就像一个“中转仓库”,专门用来缓冲和调度消息。这样可以让处理流程更灵活,比如根据用户在线状态、网络条件、处理能力,安排合适的时间发消息。
3. 写扩散与用户信箱
消息进入队列后,有多个“消息处理器”来处理这些消息。
其中一个关键思路叫做 “写扩散”,意思是:
-
系统会主动把这条消息写到**目标用户的“信箱”**里,
-
每个用户都有自己的消息列表(就像邮箱收件箱),
-
登录时或收到推送时,系统会从信箱中取出消息送给你。
这样做的好处是:接收方什么时候来都能拿到消息,不怕错过。
4. 热点信箱的设计
对于一些经常聊天的热门用户(比如大 V 或群主),他们的消息非常多。
如果每个用户都维护完整的信箱,系统会变得很慢。因此我们会设计一个 “热点信箱”,专门处理这类高频用户,减少重复写入,提升效率。
比如一个群有几千人,系统不需要把同一条群消息复制几千遍,而是用热点信箱+聚合机制,智能分发。
四、聚合层设计
前面说过,每个用户都有一个自己的“信箱”,专门用来存放别人发给 TA 的消息。对于一些活跃用户,除了普通信箱外,还会有一个**“热点信箱”**,存放高频或群聊消息。
聚合层的作用,就是把这些分散的消息来源统一起来,给用户呈现一份最终的收件列表。
1. 为什么需要聚合层?
想象一下:
-
一部分消息在用户自己的信箱里;
-
一部分消息在群聊的热点信箱里;
-
还有一些可能来自系统通知、客服等。
如果客户端要自己去找这些消息,就像你自己跑到各个邮箱、微信群、通知中心去翻,麻烦又低效。
所以,我们引入聚合层:
-
它会自动去不同地方收集消息;
-
然后按时间顺序整理好;
-
最后一口气推送给用户。
2. 聚合层怎么工作?
流程其实不复杂:
-
用户上线后,客户端向聚合层请求“新消息”;
-
聚合层会去:
-
用户个人信箱取消息;
-
热点信箱查是否有该用户感兴趣的群消息;
-
-
将多个来源的消息合并在一起;
-
排好顺序,按页返回给用户。
这样一来,用户只需要调一次接口,就能拿到所有需要的消息,既快又省资源。
3. 推模式 vs 拉模式
聚合层支持两种方式:
-
拉模式:客户端主动问“有没有新消息?”
-
推模式:系统检测到有新消息,直接通知客户端来取。
实际使用时,两者会配合起来使用,确保消息不漏、不慢、不中断。
五、可靠推送与 ACK 策略
在 IM 系统中,“消息已送达”不代表“对方已经收到”。为了确保消息真正到达用户手里,并且对方确实收到了,系统需要一套可靠推送机制,其中一个关键环节就是 ACK(应答确认)。
1. 什么是 ACK?
ACK 是英文 Acknowledgement 的缩写,意思是“确认”。
举个例子:你给朋友发了一条消息,系统通过 WebSocket 把消息推到了朋友的手机上,这时候朋友的设备会给服务器回一个“我收到了”的信号,这个信号就是 ACK。
只有服务器收到这个 ACK,才说明消息真正送达了客户端。
2. 为什么需要 ACK?
如果没有 ACK,系统根本不知道消息有没有送到。可能你朋友网络不通、手机掉线,甚至消息被系统中的某个节点“弄丢了”,这些都需要系统感知并做补救。
所以,ACK 有两个核心作用:
-
确认送达:保证用户真的收到了消息。
-
触发下一步逻辑:比如更新“消息状态”,从“已发送”变成“已送达”。
3. 如果没有收到 ACK 怎么办?
系统会设置一个超时时间,比如 5 秒。如果超过这个时间还没收到 ACK,就认为“推送失败”。
这时候系统可能会:
-
重试推送:再次把消息发一遍。
-
切换推送通道:如果 WebSocket 不通,可以尝试发离线推送(比如通知栏提示)。
-
记录失败状态:方便后续排查或提醒用户“消息可能没送达”。
4. ACK 的流程总结一下:
-
服务器把消息推送到客户端
-
客户端收到消息,立刻回 ACK
-
服务器收到 ACK,标记消息为“送达成功”
-
如果长时间没收到 ACK,就重试或记录失败