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

发布时间:2026/10/4 18:02:45
实时协同如何设计?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 的决策是顺序由服务端说了算同一房间的消息由服务端分配递增的room_seq客户端严格按 seq 展示永不按客户端时间排序先持久化再投递消息先写存储再决定在线推送还是离线存位点。未落库的消息不允许确认成功投递可重复展示必须幂等弱网重试一定会产生重复客户端和服务端都按message_id/room_seq去重。断线重连的离线补齐怎么兜跟一次完整链路用户 B 断线 2 分钟期间房间产生了seq1043~1050的消息重连时 B 带上last_seen_seq1042服务端返回大于该位点的所有消息客户端按 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.mdPresence 与通知旁路化允许松弛在线状态、正在输入、光标位置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),仅供参考