Skip to content

案例 04 · SyncRoom:给远程团队用的实时协同工作台

一句话点题:本案例练的是「实时协同里的顺序与收敛」——协同系统的难点不是把消息发出去,而是在断线、重连、多端、并发编辑、重复投递下,让每个人最终看到同一段可信的协作历史。


🧪 案例篇第 4 篇 · 本案例只练一件事

实时聊天 + 协同文档 + 通知推送下的架构判断:什么时候简单轮询够用,什么时候必须上长连接,消息顺序到底谁说了算,离线用户怎么补齐,多人同时编辑怎么不互相覆盖,以及哪些状态可以最终一致。

读完你应该能本案例靠什么练
说清实时系统为什么不能只靠请求响应用 WebSocket 长连接、连接路由和心跳解释实时投递
判断消息顺序、重复、离线补齐怎么兜住用服务端 seq、ack、重试、幂等去重和断点拉取
看懂协同编辑为什么不能最后保存覆盖用操作日志、单文档串行、OT / CRDT 解释冲突合并
区分强一致数据和可松弛状态把消息 / 文档当核心状态,把在线、正在输入、已读、通知当旁路状态

重要提醒:下面是教学化案例,不是某个协同产品的内部图纸。 数字用于数量级推理,目的是练判断,不是给出唯一答案。


开场:为什么「能发消息」不等于实时协同

因为远程团队真正需要的,不是一个会刷新的聊天框,而是一个让大家觉得「我们正在同一个房间里工作」的系统。

SyncRoom 是一个给远程团队用的实时协同工作台。一个项目房间里,成员可以聊天、@ 同事、共同编辑会议纪要、看到谁在线、收到离线推送。有人断网后回来,不能丢消息;两个人同时改同一段纪要,不能互相覆盖;手机、网页、桌面端要看到一致的未读和历史。

第一眼看,它像是几个普通功能拼在一起:

  • 房间聊天;
  • 在线状态;
  • 正在输入;
  • 已读 / 未读;
  • 会议纪要协同编辑;
  • @ 提醒和离线推送。

但真正上线后,最容易出事故的不是「消息晚了 1 秒」,而是:

消息乱序、重复、漏收;离线回来补不齐;多人同时编辑互相覆盖;未读数和已读状态在多端之间打架。

所以这一章不写「怎么做一个 WebSocket Demo」。它问一个更具体的问题:

如何在不可靠网络上,让聊天消息可靠有序,让协同文档最终一致,同时让在线状态和通知保持克制?

这章和前三章的压力源不同:

  • StarArena 怕的是高并发和库存错误。
  • PatchDesk 怕的是多租户边界和副作用失控。
  • DocuMind 怕的是答案不可信和证据链断裂。
  • SyncRoom 怕的是实时网络不可靠,但用户仍然期待所有人看到同一段协作历史。

读前小词典

这篇会反复出现几个词,先用人话对齐一下:

人话解释
WebSocket浏览器和服务器之间保持不断开的双向连接,服务器可以主动推消息给客户端。
SSEServer-Sent Events,服务器向浏览器单向推送事件。适合只下行推送,不适合复杂双向协作。
长连接连接建立后长期保持,不像普通 HTTP 请求那样用完就断。实时系统通常靠它做低延迟推送。
心跳客户端和服务器定期互相报平安。长时间没心跳,就认为连接断了。
路由表记录「用户现在连在哪台网关」。要推消息给某人,先查他在哪。
seqsequence number,序号。服务端给同一房间 / 会话里的消息分配递增序号,客户端按它排序。
ackacknowledgement,确认。客户端告诉服务端「这条我收到了」。
幂等同一条消息重复处理多次,最终只产生一次效果。重试一定会带来重复,所以要幂等。
离线补齐用户断网或离线后,回来按上次收到的位置继续拉取缺失消息。
位点 / cursor客户端记录「我已经收到 / 读到哪里了」的位置。
read watermark已读水位。可以理解成「这个用户在这个房间已读到哪条 seq」。未读数可以用它重新算。
Presence在线状态、正在输入、光标位置这类临场感状态。它们很有用,但通常不需要强一致。
OTOperational Transformation,操作转换。把并发编辑操作转换到同一个顺序下,避免互相覆盖。
CRDTConflict-free Replicated Data Type,无冲突复制数据类型。让不同端的并发修改最终自动合并到一致。
操作日志把每次编辑记录成一条 op,而不是只保存最终文本。它能回放、审计、做版本历史。
快照定期保存文档当前完整状态,避免每次打开都从第一条操作回放。

一、起始状态:先把实时基本盘做对

SyncRoom 的第一版目标很朴素:让一个 20 人以内团队在项目房间里聊天、看消息历史、共同维护一份会议纪要。

起始阶段的约束大概是这样:

维度起始阶段
团队规模5~8 名工程师
房间数1,000 个以内
单房间成员5~30 人
同时在线用户1,000~5,000
峰值消息写入50~200 条/秒
协同文档每个房间 1~3 份纪要
核心目标聊天不丢不乱序,文档不互相覆盖
最不能错用户发过的消息丢了;两个人同时编辑导致一方内容消失

这时最合理的架构不是一上来多区域、多活、复杂 CRDT 平台,而是中心化长连接网关 + 消息服务 + 操作日志 + 简单协同引擎:

浏览器 / 移动端
      │ WebSocket

┌────────────────────────────────────────────┐
│ 长连接网关                                  │
│ 心跳、连接管理、上行消息、下行推送              │
└──────────────┬─────────────────────────────┘

┌────────────────────────────────────────────┐
│ SyncRoom 后端                               │
│ 房间消息 → 分配 seq → 落库 → 投递 / 离线补齐    │
│ 协同文档 → op 合并 → 操作日志 → 广播            │
│ Presence / 通知 → 旁路异步                    │
└──────────────┬─────────────────────────────┘

       ┌──────────────┐
       │ 消息 / op 存储 │
       │ 快照 / 位点    │
       └──────────────┘

这不是「先堆复杂度」。它只是把实时协同最基本的底线立住:核心历史要可靠,临场状态可以松弛。


二、量化假设:它不是被大请求压垮,而是被长连接和乱序压垮

先算一笔账。假设 SyncRoom 推广到中型远程团队市场半年后:

注册团队:2,000
活跃团队:500
日活用户:30,000
同时在线用户:8,000~20,000
人均设备:1.5~2.2 台
峰值长连接:15,000~40,000 条
房间总数:50,000
活跃房间:5,000
峰值聊天消息:1,000~3,000 条/秒
峰值 presence 事件:10,000~50,000 条/秒
协同文档操作:500~2,000 op/秒
单房间常见在线人数:5~50
大房间在线人数:200~1,000
目标:在线消息 P95 < 300ms,离线补齐 P95 < 2s
协同目标:本地编辑立即显示,远端同步 P95 < 500ms
Presence 目标:允许 5~15 秒内最终收敛
可靠性目标:核心消息不丢;重复消息不重复展示;同房间消息按服务端 seq 展示

这个系统的单条消息很小,但负载形态很特殊:

  1. 连接是有状态的:用户连在哪台网关,消息就必须推到哪台网关。
  2. 网络一定会断:移动端切后台、地铁弱网、电脑睡眠,都会让连接消失。
  3. 到达顺序不等于真实顺序:消息和编辑操作会因为网络抖动乱序到达。
  4. 状态更新极多:在线、正在输入、光标、已读变化比正式消息多得多。

所以 SyncRoom 的架构重心不是「怎么处理一个大请求」,而是:

把核心协作历史做成可靠有序,把易变临场状态做成可降级的最终一致。


三、触发信号:什么时候说明第一版开始不够用

第一版跑起来后,不要凭感觉升级。看这些信号:

信号表现为什么这是架构问题
消息偶发乱序「收到」出现在「你能看见吗」之前客户端按到达时间排序,没有服务端 seq
用户说消息丢了断网重连后少了几条中间消息没有持久化位点和离线补齐
消息重复展示弱网下同一条消息出现两次重试没有幂等去重
多端未读不一致手机显示 3 条未读,网页显示 0 条已读位点没有服务端统一收敛
大房间卡顿500 人房间里 presence 事件把网关打满临场状态没有限频 / 聚合 / 降级
会议纪要被覆盖A 写的段落被 B 后保存的版本覆盖把协同文档当普通表单保存,没有 op 合并
重连后文档跳变离线编辑回来后,本地内容被服务端快照覆盖没有 OT / CRDT 合并离线操作
@ 通知轰炸一次讨论触发多端、多渠道重复提醒通知没有去重、限频、在线 / 离线分流

这些信号不是在说「加机器就行」。它们在说:实时系统缺少可靠投递、顺序和合并协议。


四、核心矛盾:用户要实时感,系统要可信历史

SyncRoom 的核心对象有三组:

  1. 房间 / 成员 / 连接:谁在房间里,现在连在哪台网关。
  2. 消息 / 位点 / 通知:发了什么,谁收到哪里,谁读到哪里,谁需要提醒。
  3. 文档 / 操作 / 快照:编辑意图是什么,如何合并,如何重建最终文档。

如果只看最简单路径,它像这样:

用户发消息 → 服务器转发 → 其他人显示
用户改文档 → 保存最新文本 → 其他人刷新

但真实系统必须在每一步都回答:

  • 这条消息的服务端顺序是多少?
  • 收方在线吗?连在哪台网关?
  • 断线重连后从哪个位点补齐?
  • 这条重试消息是不是已经处理过?
  • 多端已读状态以谁为准?
  • 两个人同时改同一段文字,谁的意图应该保留?
  • 在线状态和正在输入能不能丢?能不能延迟?

所以新的架构命题变成:

核心历史必须可靠有序;协同编辑必须合并意图;临场状态和通知必须克制降级。

这里最容易混淆的是:聊天消息和协同文档不是同一种一致性问题。

聊天消息:追加历史 → 重点是服务端顺序、投递、补齐、去重
协同文档:多人改同一状态 → 重点是操作合并、收敛一致、不覆盖
Presence:临场感状态 → 重点是快、轻、可过期、可降级

把这三类状态混成一套强一致模型,会又慢又贵;把三类状态都当临时消息,又会丢历史、乱顺序、覆盖编辑。


五、方案推演:实时协同到底靠什么兜住

这是本案例最重要的决策。很多实时 Demo 能跑,但一到弱网、多端、离线和并发编辑就崩。

方案 A:轮询 + 最后保存者覆盖

客户端每 3 秒拉一次新消息
文档每次保存整篇文本
最后保存的人覆盖前一个版本
优点代价
实现最简单,普通 Web 栈就能做不够实时,服务端被轮询浪费打满
文档保存逻辑简单并发编辑会丢内容,离线合并基本不可控

方案 B:WebSocket 推消息,但顺序靠客户端

客户端发消息 → 网关广播 → 客户端按本地时间 / 到达时间展示
优点代价
实时感明显提升网络抖动会乱序,重试会重复
适合小房间 Demo断线补齐、多端同步、未读位点没有可靠基础

方案 C:服务端 seq + 持久化 + ack / 重试 / 去重

发送消息
  └─▶ 服务端分配 room_seq
      └─▶ 先持久化
          └─▶ 在线投递 / 离线存位点
              └─▶ 客户端 ack,按 seq 去重和排序
优点代价
同房间消息有服务端统一顺序要维护发号、ack、重试和位点
离线重连可按 last_seen_seq 补齐协议复杂度明显上升
重复投递不会重复展示客户端和服务端都要存消息 ID / seq

方案 D:协同文档用操作日志 + OT / CRDT

用户编辑不是保存整篇文本
而是发送操作:在位置 10 插入「结论」
服务端 / CRDT 引擎合并操作
所有端最终收敛到同一份文档
优点代价
不会因为最后保存覆盖别人OT / CRDT 理解和实现成本高
支持离线编辑后合并需要操作日志、快照、冲突测试
能做历史版本和审计文档模型要从「最终文本」变成「操作序列」

SyncRoom 第一阶段选择:聊天用服务端 seq + ack / 重试 / 去重;文档用中心化 OT 或成熟 CRDT 库;presence 和通知走最终一致旁路。

关键不在「有没有 WebSocket」,而在于:

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


六、关键架构决策:用 ADR 把为什么留下来

ADR 是 Architecture Decision Record,可以理解成「架构决策记录」。实时系统最容易在后面被人问:「为什么不按客户端时间排序?为什么要先落库再投递?为什么文档不直接保存全文?为什么在线状态可以不准?」这些都应该提前写下来。

ADR-01:采用 WebSocket 长连接网关 + 用户连接路由表,SSE / HTTP 作为降级

  • 背景:实时体验要求服务端能主动推送;普通 HTTP 请求响应无法低延迟通知在线用户。
  • 选择:客户端通过 WebSocket 接入长连接网关;连接建立 / 断开时更新 user_id -> gateway_id 路由表;投递消息前先查路由。企业代理、弱网或只读旁观场景允许 SSE 下行 + HTTP 上行降级。
  • 放弃:放弃用短轮询支撑核心实时体验。
  • 换来:在线消息低延迟,服务端能精准找到用户当前连接;只读场景仍有可用降级路径。
  • 风险:长连接是有状态的,网关故障会导致其上用户同时重连,路由表也会高频变化。
  • 复审条件:当连接数超过单集群承载或跨地域延迟明显时,再做就近接入、多区域网关和连接迁移;如果只读旁观远多于编辑,可以扩大 SSE 使用范围。

ADR-02:聊天消息由服务端分配房间内 seq,先持久化再投递

  • 背景:客户端时间不可信,网络到达顺序不可信,投递也可能重复。
  • 选择:每个房间的消息由服务端分配递增 room_seq;消息先写入持久存储,再在线投递或离线补齐;客户端按 room_seq 排序,按 message_id 去重。
  • 放弃:放弃按客户端时间 / 到达时间展示消息。
  • 换来:同房间历史有统一顺序,断线后可从 last_seen_seq 补齐,重复投递不会重复展示。
  • 风险:热点大房间的 seq 分配和写入可能成为瓶颈。
  • 复审条件:当单房间写入过高时,考虑房间分片、频道拆分或大房间共享流 + 位点读取。

ADR-03:协同文档保存操作日志 + 快照,不用最后保存覆盖

  • 背景:多人会同时编辑同一份纪要,保存最终文本会丢掉并发意图。
  • 选择:客户端发送编辑操作 op;同一文档路由到同一合并处理者串行处理;服务端为 op 分配 doc_seq / 文档版本;用 OT 或 CRDT 合并操作;持久化操作日志,定期生成快照。
  • 放弃:放弃「每次保存整篇文档,最后写入者获胜」。
  • 换来:并发编辑不互相覆盖,离线操作能按 last_doc_seq 补齐和合并,历史版本和审计天然存在。
  • 风险:OT / CRDT 边界复杂,富文本、表格、图片等结构会放大算法难度。
  • 复审条件:如果离线编辑占比高、跨端并发复杂,优先考虑成熟 CRDT 库;如果中心化协作足够,OT + 单文档单 writer 更容易控制。

ADR-04:presence、正在输入、已读和通知走旁路,不压住核心链路

  • 背景:在线状态、正在输入、光标、已读和推送提醒变化频繁,但允许短暂不准。
  • 选择:presence 放带 TTL 的高速存储;正在输入限频广播;已读以服务端位点收敛;通知异步入队,在线时尽量站内 / 长连接提醒,离线时走 Push / 邮件。
  • 放弃:放弃把所有临场状态都做成强一致事务。
  • 换来:核心消息和文档链路不被高频状态拖慢,状态可降级,通知不轰炸。
  • 风险:用户会短暂看到不准确的在线 / 已读状态。
  • 复审条件:如果已读状态成为合规或业务承诺,再提高它的持久化与确认级别;presence 仍不应强一致化。

七、演进后的结构与数据流

下面只画 SyncRoom 的核心结构。它不是一个 WebSocket 接口,而是一套消息、文档、临场状态分层处理的协作系统。

起始路径

用户发消息
  └─▶ 网关广播
      └─▶ 客户端显示

用户改纪要
  └─▶ 保存整篇文本
      └─▶ 覆盖旧版本

问题是:消息没有统一顺序,断线没有补齐基础,协同文档会被最后保存覆盖。

演进后的结构

客户端 Web / Mobile / Desktop
      │ WebSocket

┌──────────────────────────────────────────────┐
│ 长连接网关层                                  │
│ 心跳、连接管理、上行转发、下行推送               │
└───────────────┬──────────────────────────────┘

┌──────────────────────────────────────────────┐
│ SyncRoom 核心服务                              │
│                                              │
│  ┌──────────────┐   ┌──────────────┐         │
│  │ 消息服务       │   │ 协同文档服务    │         │
│  │ room_seq/ack │   │ op merge     │         │
│  └──────┬───────┘   └──────┬───────┘         │
│         │                  │                 │
│  ┌──────▼───────┐   ┌──────▼───────┐         │
│  │ 消息存储       │   │ op 日志 + 快照 │         │
│  └──────────────┘   └──────────────┘         │
│                                              │
│  ┌──────────────┐   ┌──────────────┐         │
│  │ 路由表         │   │ Presence/通知 │         │
│  │ user->gateway│   │ TTL/队列/限频  │         │
│  └──────────────┘   └──────────────┘         │
└──────────────────────────────────────────────┘

这张图的核心变化不是「用了 WebSocket」,而是结构变清楚了:

  • 长连接网关只负责连接和转发,不决定业务顺序。
  • 消息服务分配房间内 seq,先落库再投递,用 ack / 重试 / 去重兜可靠性。
  • 协同文档服务处理编辑操作,用 OT / CRDT 合并,并保存操作日志和快照。
  • 路由表解决「用户现在连在哪台网关」。
  • Presence / 通知走旁路,可限频、可过期、可降级。

跟一次「断线后重连补齐」走到底

1. 用户 A 在房间 R 里发消息。
2. 消息服务给它分配 room_seq=1042,写入消息存储。
3. 用户 B 此时在线,路由表显示 B 连在 gateway-7,消息被推过去。
4. B 的网络抖动,没有及时 ack。
5. 服务端重试投递;B 客户端用 message_id / room_seq 去重,只展示一次。
6. B 断线 2 分钟,期间房间又产生 seq=1043~1050。
7. B 重连时带上 last_seen_seq=1042。
8. 服务端返回 seq > 1042 的消息,客户端按 seq 排序补齐。
9. 未读位点更新到服务端,手机和网页最终收敛到同一未读状态。

这里的关键点:

  • 消息顺序由服务端 seq 决定,不是客户端时间。
  • 投递可以重复,展示必须幂等。
  • 离线补齐靠位点,不是靠「推送一定成功」。
  • 未读和已读最终以服务端位点收敛,不要让每个端各算各的。

跟一次「两人同时改会议纪要」走到底

1. 文档当前版本是 v10。
2. 用户 A 在标题下插入「结论:继续推进」,生成 opA。
3. 用户 B 同时删除同一段旧结论,生成 opB。
4. 两个 op 通过 WebSocket 到达协同文档服务,到达顺序可能不同。
5. 同一文档的 op 被路由到同一处理者串行处理。
6. 服务端为合并后的 op 分配 doc_seq,OT / CRDT 引擎保留两人的编辑意图。
7. 合并后的 op 写入操作日志,更新当前版本 v11。
8. 服务端把最终 op 广播给所有协作者。
9. 每个客户端应用同一批 op,最终看到同一份纪要。
10. 定期快照保存 v11 的完整文档,下次打开不用从第一条 op 回放。

这里的关键点:

  • 协同编辑保存的是操作,不是只保存最终文本。
  • 同一文档要有一个确定顺序,否则并发操作无法稳定合并。
  • 客户端重连时也要带 last_doc_seq,用来补齐断线期间缺失的文档操作。
  • OT / CRDT 的目标不是谁赢,而是保留意图并最终收敛。
  • 操作日志既是合并基础,也是历史版本和审计基础。

八、坏了怎么办:故障场景与兜底

故障直接后果检测方式架构兜底
网关宕机这台网关上的用户全部掉线连接数突降、重连峰值客户端指数退避重连;路由表过期;网关水平扩展
路由表过期消息投到错误网关或投不出去投递失败率、路由 miss路由带 TTL;投递失败后查最新连接;客户端重连刷新
消息未先落库就推送推送成功但服务端历史缺失,或服务故障后丢消息消息 ID 对账、用户投诉先持久化再投递;未落库消息不允许 ack 成功
按客户端时间排序弱网下消息乱序乱序率、客户端日志服务端分配 room_seq;客户端按 seq 展示
重试无去重同一消息重复出现duplicate message_id客户端和服务端按 message_id / seq 幂等
离线补齐只靠 Push用户点开后历史仍缺消息last_seen_seq 缺口Push 只负责唤醒;上线后按位点拉取缺失消息
未读由各端本地计算手机、网页、桌面未读数不一致多端状态差异服务端保存 read watermark / read_cursor,各端最终收敛
未读计数只做缓存增减漏减或重复减后长期错误未读数和 seq 差异计数可缓存,但要能用 read watermark + 消息 seq 重算
大房间 presence 全量广播网关被在线 / 光标 / 正在输入事件打满presence QPS、广播量限频、采样、聚合;只发给正在看房间的人
最后保存者覆盖文档并发编辑丢内容文档 diff、用户反馈操作日志 + OT / CRDT;禁止整篇覆盖式保存
协同 op 重放失败打开文档状态不一致快照校验、op 回放测试操作日志不可变;定期快照;坏 op 隔离和修复
CRDT / OT 冲突边界没测富文本、表格、图片编辑出现错位协同 fuzz test、回放测试建立并发编辑测试集;复杂结构分块协同
SSE 被当成万能双向通道上行仍靠 HTTP,协同编辑体验受限降级链路延迟、重试量SSE 适合作只读 / 降级,主编辑通道仍用 WebSocket
通知重复轰炸@ 提醒在多端、多渠道重复到达通知去重率、退订率通知异步队列;按事件 ID 去重;在线优先站内,离线再 Push

实时协同的成熟度,不是看 Demo 里消息多快飞过去,而是看弱网、重连、重复、并发编辑这些坏情况有没有协议兜住。


📌 拿模板验证这次推演

本案例不是重写实时聊天或协同文档模板,而是把「远程团队协作」里最容易混在一起的几类状态拆开推演。

可复用模板 / 章节本案例复用什么本案例重点补什么
实时通讯长连接、路由表、服务端序号、ack / 重试 / 去重、离线补齐把聊天消息放进团队房间和多端未读场景
实时协同文档操作日志、单文档串行、OT / CRDT、快照把协同编辑和聊天、presence、通知放在同一产品里取舍
通知 / 推送系统异步通知、去重、限频、多渠道投递说明在线走长连接,离线才需要 Push / 邮件唤醒
分布式系统的硬道理网络不可靠、部分失败、重试把断线、重连、重复投递作为默认情况
数据一致性工程幂等、重试、最终一致、补偿把消息投递和已读位点做成可恢复协议
为失败而设计降级、隔离、熔断presence 和通知可降级,不要拖垮核心消息与文档

读法建议:先读本章,再回看 实时通讯模板实时协同文档模板。你会更容易看懂:聊天和协同文档都实时,但它们要解决的可靠性问题不是同一个。


🎯 随堂检验

🤔SyncRoom 里同一房间的聊天消息为什么不应该按客户端时间排序?
  • A因为客户端时间可能不准,网络到达也会乱序,应该由服务端分配房间内 seq
  • B因为客户端不能显示时间
  • C因为所有消息都需要全局唯一顺序
🤔为了让消息不丢又不重复展示,通常要组合哪些机制?
  • A只要 WebSocket 就够了
  • B先持久化、ack、重试、按 message_id / seq 幂等去重
  • C只靠 Push 推送
🤔多人同时编辑会议纪要时,为什么不能用最后保存者覆盖?
  • A因为保存整篇文本太占磁盘
  • B因为并发编辑会丢掉别人的意图,应该用操作日志 + OT / CRDT 合并
  • C因为文档只能一个人编辑
🤔在线状态、正在输入、光标位置这类 presence 数据应该怎么处理?
  • A和消息一样强一致持久化
  • B放在可过期的高速状态里,限频广播,允许短暂不准
  • C完全不做任何限制,每次变化都全量广播

本案例小结

  • 实时不是核心,可信协作历史才是核心。 WebSocket 只是通道;服务端 seq、落库、ack、补齐、去重才让聊天可靠。
  • 聊天和协同文档不是同一种问题。 聊天是追加历史,重点是有序投递;文档是多人修改同一状态,重点是 OT / CRDT 合并和收敛。
  • 离线补齐不能靠 Push。 Push 只负责唤醒,真正补齐要靠服务端消息历史和客户端位点。
  • 多端状态要有服务端收敛点。 未读 / 已读不能各端各算,否则永远打架。
  • Presence 可以松弛。 在线、正在输入、光标位置可以短暂不准,需要限频和降级,不要和核心消息链路抢资源。
  • 操作日志比最终文本更适合协同。 它支持合并、回放、版本历史和审计,是协同编辑的地基。

承上启下:这一章把 实时通讯实时协同文档通知系统 放进同一个产品里。下一章如果继续写内容 Feed / 视频分发,压力会再次变化:重点会从实时收敛,转向扇出放大、热点内容、推荐、搜索和 CDN 分发。


相关链接

💬 评论