拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

实时协同如何设计?Awesome Architecture案例SyncRoom完整推演(长连接+OT/CRDT+多端同步)

实时协同如何设计?Awesome Architecture案例SyncRoom完整推演(长连接+OT/CRDT+多端同步)

实时协同如何设计?Awesome Architecture案例SyncRoom完整推演(长连接+OT/CRDT+多端同步)

【免费下载链接】awesome-architecture🧭 Architecture-first system design: 26 bilingual tutorials, 25 architecture templates, and 6 end-to-end cases covering distributed systems, AI-native systems, RAG, coding Agents, and production trade-offs.项目地址: https://gitcode.com/gh_mirrors/awesomearc/awesome-architecture

做实时协同设计时,光会 WebSocket 远远不够。开源知识库 Awesome Architecture 的案例 SyncRoom 完整推演了一个远程团队协同工作台:从长连接网关搭建,到消息的服务端 seq 排序、断线离线补齐、多端未读同步,再到用 OT/CRDT 解决多人并发编辑互相覆盖的问题。这篇文章带你用最短路径读懂这套实时协同架构的完整决策链。

为什么"能发消息"不等于实时协同

很多团队做协同产品,第一步就能让消息"飞过去",但上线后事故几乎全部来自这些坏情况:

常见事故用户视角架构根因
消息乱序"收到"出现在"在吗"之前按客户端时间排序,没有服务端序号
消息丢失断网重连后少了中间几条没有持久化位点和离线补齐
消息重复弱网下同一条出现两次重试缺少幂等去重
多端未读打架手机 3 条未读,网页 0 条已读状态各端各算各的
纪要被覆盖自己写的段落消失了把协同文档当普通表单保存

💡 核心结论:实时只是体验,顺序、补齐、合并、幂等才是可信协作的底座。

SyncRoom 的完整推演过程见 cases/syncroom-collaboration/README.md,下面拆解它的五个关键设计层。

第一步:搭好长连接网关这个基本盘

实时协同的第一步不是堆功能,而是把"连接"这件事做对:

浏览器 / 移动端 │ WebSocket ▼ ┌──────────────────────────────────────────┐ │ 长连接网关:心跳、连接管理、上行转发、下行推送 │ └──────────────┬───────────────────────────┘ ▼ ┌──────────────────────────────────────────┐ │ 核心服务:消息(seq/ack) │ 文档(op合并) │ 路由表 │ └──────────────────────────────────────────┘

三个必须想清楚的点:

  • 连接是有状态的:用户此刻挂在哪台网关上,消息就必须推到那台。所以要有「user_id → gateway_id」的连接路由表,推消息前先查路由。
  • 网络一定会断:心跳定期报平安,长时间无心跳就判定断开;客户端断线用指数退避重连。
  • 留一条降级路径:企业代理、只读旁观等场景允许 SSE 下行 + HTTP 上行降级,主编辑通道仍是 WebSocket。

📎 完整的路由表、心跳与降级设计见 templates/realtime-chat/README.md

消息可靠性:服务端 seq + 先落库 + ack 去重

这是实时协同设计里最容易被 Demo 掩盖的一环。SyncRoom 的决策是:

  1. 顺序由服务端说了算:同一房间的消息由服务端分配递增的room_seq,客户端严格按 seq 展示,永不按客户端时间排序;
  2. 先持久化再投递:消息先写存储,再决定在线推送还是离线存位点。未落库的消息不允许确认成功;
  3. 投递可重复,展示必须幂等:弱网重试一定会产生重复,客户端和服务端都按message_id/room_seq去重。

断线重连的离线补齐怎么兜

跟一次完整链路:用户 B 断线 2 分钟,期间房间产生了seq=1043~1050的消息;重连时 B 带上last_seen_seq=1042,服务端返回大于该位点的所有消息,客户端按 seq 排序补齐。

⚠️ 常见误区:指望 Push 推送来补齐离线消息。Push 只负责"唤醒",真正补齐靠服务端消息历史 + 客户端位点。

多端同步:未读状态必须有服务端收敛点

手机、网页、桌面端同时在线时,未读数和已读状态不能各端本地计算——那永远打架。

SyncRoom 的做法是给每个用户在每个房间维护一个已读水位(read watermark):即"这个用户在这个房间读到了哪条 seq"。各端把已读位点上报到服务端,未读数由服务端统一计算后下发,多端最终收敛到同一个值。

这就是多端同步的本质:状态可以存在各端,但收敛点必须唯一在服务端。

协同编辑:操作日志 + OT/CRDT 替代"最后保存覆盖"

两个人同时改会议纪要,"谁后保存谁赢"会直接丢内容。正确姿势是把协同文档的数据模型从"最终文本"变成"操作序列":

  • 客户端发送操作(op):比如"在位置 10 插入'结论'",而不是整篇保存;
  • 同一文档串行合并:所有 op 路由到同一处理者,分配doc_seq,由 OT 或 CRDT 引擎转换合并,保留每个人的编辑意图;
  • 操作日志 + 定期快照:op 不可变地写入日志,支持回放、版本历史和审计;定期生成完整快照,避免每次打开都从第一条 op 回放;
  • 离线编辑也能并:重连时带上last_doc_seq,补齐断线期间的文档操作再合并。

OT 还是 CRDT 怎么选?中心化协作场景下 OT + 单文档单写入者更好控制;离线编辑占比高、跨端并发复杂时,优先选成熟 CRDT 库。

📎 协同文档的合并引擎与全景图见 templates/collaborative-doc/README.md

Presence 与通知:旁路化,允许松弛

在线状态、正在输入、光标位置(Presence)这类"临场感"数据变化极频繁,但允许短暂不准:

状态类型一致性要求处理方式
聊天消息强可靠有序服务端 seq + 落库 + ack/重试/去重
协同文档最终收敛一致op 日志 + OT/CRDT 合并
在线/正在输入5~15 秒内收敛即可带 TTL 的高速存储 + 限频 + 聚合
@ 提醒/离线推送不轰炸即可异步入队,按事件 ID 去重,在线走长连接,离线才 Push

大房间(几百人在线)里,Presence 事件量会远超正式消息,必须限频、采样、只推给正在看房间的人,否则会先把网关打满。

📎 通知去重、限频与多渠道投递设计见 templates/notification-system/README.md

故障兜底速查:实时系统先想"坏了怎么办"

故障架构兜底
网关宕机客户端指数退避重连,路由带 TTL 自动过期,网关水平扩展
消息先推送后落库严禁——先持久化再投递,未落库不允许 ack
大房间 presence 打满限频、采样、聚合、降级
并发编辑丢内容操作日志 + OT/CRDT,禁止整篇覆盖式保存
通知重复轰炸事件 ID 去重 + 限频 + 在线/离线分流

更完整的故障-兜底对照表在案例原文 cases/syncroom-collaboration/README.md 的"坏了怎么办"一节。

带走这份设计:一张自检清单

设计自己的实时协同系统时,逐条过一遍:

  • 消息顺序是否由服务端 seq 决定,而非客户端时间?
  • 消息是否先持久化再投递?
  • 断线重连是否有位点(last_seen_seq / last_doc_seq)可补齐?
  • 重试链路是否按 message_id 幂等去重?
  • 多端未读/已读是否收敛到服务端统一计算?
  • 协同文档是否保存操作日志而非整篇文本?
  • 是否有定期快照,避免 op 无限回放?
  • Presence 和通知是否旁路化、限频、可降级?

延伸阅读

  • 案例原文(含量化假设、ADR 决策记录、触发信号):cases/syncroom-collaboration/README.md
  • 实时通讯架构模板:templates/realtime-chat/README.md
  • 实时协同文档模板:templates/collaborative-doc/README.md
  • 方法论补课:08-架构决策记录与演进、10-分布式系统的硬道理、11-数据一致性工程、12-为失败而设计
  • 全部案例入口:cases/README.md

【免费下载链接】awesome-architecture🧭 Architecture-first system design: 26 bilingual tutorials, 25 architecture templates, and 6 end-to-end cases covering distributed systems, AI-native systems, RAG, coding Agents, and production trade-offs.项目地址: https://gitcode.com/gh_mirrors/awesomearc/awesome-architecture

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表