一条IM消息的分布式之旅:从发送到已读

一条消息从发送到送达, 中间到底经历了什么。 表面上用户只是点了一下"发送", 实际上后端已经开始了一场分布式协作。 个人项目:github.com/w3777/xigua...

1. 消息从客户端出发

用户在客户端输入内容后,消息会先通过 WebSocket 长连接发送到接入节点。

这里的接入层,本质上更像一个"网关"。

它不负责真正处理消息,只负责:

  • 维护连接
  • 心跳检测
  • 用户在线状态
  • 转发消息

所以接入节点收到消息后,会通过 Dubbo RPC 把消息转发到 Center 消息中枢。

这时候,真正的消息链路才刚开始。


2. Center 开始接管消息

Center 服务收到消息后,

这里会完成几件事情:

  • 生成 messageId
  • 开启事务
  • 消息持久化
  • 更新会话状态

消息会先进入 MySQL。

因为只有真正落库成功,这条消息才算存在。

否则客户端看到"发送成功",结果服务重启后消息没了,这其实是最严重的问题。


3. ACK 为什么很重要

很多人以为:

客户端点发送后,服务端回个 success 就结束了。

实际上不是。

IM 里的 ACK,更像一种"确认机制"。

只有消息真正完成持久化后,服务端才会把 ACK 返回给发送者。

客户端收到 ACK 后:

  • 消息状态变成"发送成功"
  • 本地 loading 消失
  • 消息进入正常展示状态

如果 ACK 超时没回来,客户端就会认为发送失败。

这里有个细节:

ACK 不能回太早。

因为:

如果 ACK 已经返回,但事务实际上失败了,客户端会误认为消息发送成功。

这也是为什么很多 IM 系统,会把 ACK 放在事务后面。


4. Redis 开始发挥作用

消息落库后,系统会开始查接收者在线状态。这里不会查数据库。

因为数据库扛不住高频在线查询。

在线状态、会话状态、未读数量这些数据, 都会放进 Redis。

Redis 在 IM 里,其实更像一个"实时状态中心"。

系统会根据 Redis 中记录的:

  • 用户在线节点
  • 当前连接机器
  • 会话状态

去定位:

"这个人现在到底连在哪台机器上。"


5. 定向投递开始

找到接收者所在节点后,Center 会再次通过 Dubbo RPC:

把消息定向投递到对应机器。

这里有个关键点:

发送者和接收者,可能根本不在同一台服务器。

比如:

发送者连接的是节点 A, 接收者连接的是节点 B。

所以消息一定会经过:

接入层 → Center → 另一台接入层

这也是 IM 分布式架构里,最核心的一层:

消息中枢。


6. 消息真正送达

接收节点收到消息后,

会通过 WebSocket:

把消息推送给接收者客户端。

这时候用户终于看到消息。

但其实流程还没结束。

因为:

"收到消息"

不等于

"已读消息"。


7. 已读回执才是最后一步

当用户真正打开聊天窗口后,

客户端会发送已读回执。

服务端收到后:

  • 更新消息已读状态
  • 同步会话状态
  • 更新未读数量
  • 通知发送方"对方已读"

至此, 一条消息的生命周期才真正结束。


8. 消息系统真正难的地方

真正复杂的是:

  • ACK 一致性
  • 在线状态同步
  • 分布式路由
  • 消息可靠性
  • 会话状态维护
  • 未读数量计算
  • 已读同步
  • 多端登录
  • 节点故障恢复

很多时候,

聊天窗口只是表象。

底层其实是一套实时分布式系统。

相关推荐
ZhengEnCi15 小时前
Q01-高并发点赞系统架构设计
架构
笨鸟飞不快18 小时前
从 MVC 到 DDD:一次真实的渐进式迁移实录
后端·架构
这个DBA有点耶1 天前
GROUP BY优化全解:如何写出既不丢数据又飞快的分组查询
数据库·mysql·架构
锋行天下1 天前
我试图优化 Vite 的拆包,结果首屏慢了 10 倍
前端·vue.js·架构
小鼻子的猫2 天前
独立开发 30 天:2.5 万行代码,23 个 Bug,5 次重构——一个 AI 社区的诞生
架构
咖啡八杯2 天前
GoF设计模式——命令模式
java·设计模式·架构
candyTong2 天前
阿里开源 AI Code Review 工具:ocr review 的执行链路解析
javascript·后端·架构
doiito2 天前
【Agent Harness】TPS的“自工程完结”教会了我一件事:别把Bug留给下一道工序
架构·rust
烬羽2 天前
中英文 token 数量差一倍?两段 JS 代码搞懂 LLM 底层是怎么"读"文字的
javascript·程序员·架构