AI时代中,知道什么 VS 能解决什么,怎么解决(一:分布式系统设计:收敛 、不丢意图、低延迟)
“A、B 同时改同一条线的颜色,不是“谁后保存谁覆盖”的 UI 问题,而是分布式复制状态下的并发写冲突。要同时做到收敛、不丢意图、低延迟,核心是:操作化 + 因果排序 + 冲突合并/变换 + 本地乐观更新 + 异步广播”。
1. 人话版:图纸就像多人同时编辑的 Google Docs
A 和 B 各自手里有一份图纸副本。
A 把线从红改蓝,B 把同一条线从红改绿。
网络不会按你点鼠标的顺序到达服务器,甚至可能延迟、重复、乱序、断线。
所以你不能靠“最后保存覆盖”。你要设计一套规则:
- 最终所有人看到的图纸一样:收敛性。
- 不能因为网络乱序,把不该丢的修改丢掉:不丢意图。
- A 一画,B 很快看到,不能等保存:低延迟。
关键认知:
收敛性不等于不丢意图。
LWW,也就是 Last-Writer-Wins,最后写入赢,可以保证收敛,但它会丢并发输家的意图。
CRDT 可以保证收敛,但它不自动理解业务意图。
OT 可以做意图变换,但复杂、依赖中心服务器和正确变换函数。
2. 把问题形式化:线、操作、时钟、因果
一条线可以表示为:
1 | |
A 的操作:
1 | |
B 的操作:
1 | |
判断并发还是因果:
- 如果 B 的操作依赖里包含 A 的
opA,说明 B 是在看到 A 改成蓝色之后才改绿色。
这不是并发,B 是后续操作,最终必须绿色。 - 如果 A、B 都基于红色,互相不知道对方,说明是并发同属性写。
这时两个颜色不可能同时成为最终单值颜色。必须选策略。
时钟推荐用 HLC,混合逻辑时钟:(physicalTime, logicalCounter, actorId)。
它比纯物理时间可靠,又接近人类时间,适合 LWW。
3. 三个目标到底是什么意思
3.1 收敛性
最终所有副本状态一致。
数学上要求你的合并/应用函数满足:
- 交换律:先应用 A 再 B,和先 B 再 A,结果一样。
- 结合律:分组顺序不影响结果。
- 幂等:同一个操作重复应用多次,结果一样。
或者你用一个中心服务器给所有操作排全序,然后广播。
这样大家按同一个顺序应用,也能收敛。
3.2 不丢意图
不是“蓝色和绿色都显示出来”才叫不丢意图。
不丢意图至少包含四层:
因果后续必须赢:
B 看到 A 改蓝后,再改绿,最终必须绿。非冲突并发都保留:
A 改颜色,B 改线宽,最终颜色是 A 的,线宽是 B 的。并发同冲突有确定性策略:
A 改蓝,B 改绿,最终按规则选一个,比如 LWW、优先级、图层锁、用户投票。冲突可解释、可恢复:
如果产品要求不丢,可以用多值寄存器保留{blue, green},UI 提示“有冲突”,让用户选。
所以面试时你要说:
“不丢意图”不是数学性质,而是业务语义。协议保证收敛,业务定义冲突怎么解。
3.3 低延迟
目标:A 改完,本地立刻变蓝,B 在 100ms 内看到。
不能等服务器保存。
做法:
- 本地乐观更新:先改 UI。
- 同时生成操作,放进 pending 队列。
- WebSocket 长连接发服务器。
- 服务器排序、广播。
- 客户端收到远程操作,和本地 pending 做变换/合并,再重放。
4. 方案一:中心服务器 + OT
OT,Operational Transformation,操作变换。
Google Docs 经典方案。
流程:
- A 本地先改蓝,发
OpA。 - B 本地先改绿,发
OpB。 - 服务器先收到 A,应用后文档颜色是蓝。
- 服务器收到 B,发现 B 基于红色,但现在已经是蓝色。
- 服务器对 B 做变换:
1 | |
- 服务器广播变换后的 B。
- A 收到后,本地从蓝变绿。
- 最终 A、B 都看到绿色,收敛。
这里 A 的蓝色意图被覆盖了。
如果业务认为“并发同属性写,最后写入赢”,这是合理的。
如果业务要求“不丢意图”,就不能只做 LWW,要用多值或冲突提示。
OT 的关键难点:
- 变换函数必须正确。
- 要满足 TP1/TP2 性质。
- 复杂操作,比如移动、删除、分组、撤销,变换会爆炸。
- 通常需要中心服务器做权威排序。
面试加分说法:
“OT 强在意图变换和中心权威,弱在变换函数复杂、离线差。CRDT 强在自动收敛和离线,弱在元数据大、业务冲突不自动解决。”
5. 方案二:CRDT
CRDT,Conflict-free Replicated Data Type,无冲突复制数据类型。
它通过数据结构本身保证合并收敛。
常见类型:
5.1 LWW Register
最后写入赢寄存器。
值:
1 | |
合并规则:
1 | |
对 A 蓝、B 绿:
假设 B 的 HLC 更大,最终绿色。
所有人一致。
缺点:A 的蓝色被丢掉。适合“最后编辑赢”的属性,比如颜色、线宽、标题。
5.2 MV Register
多值寄存器。
规则:
- 如果一个值因果依赖另一个值,新的覆盖旧的。
- 如果两个值并发,两个都保留。
对 A 蓝、B 绿并发,最终值集合:
1 | |
UI 可以显示:
1 | |
这就是“不丢意图”的强方案。
缺点:产品体验复杂,需要冲突解决 UI。
5.3 Yjs / Automerge
Yjs 是工业界常用 CRDT 库。Y.Map 对同一个 key 的并发 set 通常是 LWW。Y.Array、Y.Text 用 RGA/YATA 这类序列 CRDT。
Automerge 也类似。
图形编辑器常见做法:
- 对象 ID 用稳定 ID。
- 属性如颜色、线宽用 LWW。
- 点序列、文本用 CRDT 序列。
- 删除用墓碑。
- 存在感、光标不持久化,节流广播。
6. A/B 同线改色的完整推演
场景:A 改蓝,B 改绿,都是并发。
方案 1:LWW
最终取 HLC 最大:
1 | |
B 赢,最终绿色。
A、B 都看到绿色。
收敛性满足。
不丢意图:非冲突不丢,并发同属性冲突按规则丢一个。
低延迟:本地先变,最终一致。
方案 2:MV Register
最终:
1 | |
A、B 都看到冲突。
收敛性满足。
不丢意图满足。
低延迟满足。
但产品需要用户选择。
方案 3:OT
服务器先应用 A,蓝。
B 到达后变换为 blue -> green。
最终绿。
收敛性满足。
意图:如果产品规则是“后到覆盖”,合理。
如果产品要求保留 A,需要额外冲突日志。
方案 4:业务优先级
比如:
- 图层锁:锁定图层的人赢。
- 角色权限:设计师赢过访客。
- 手动冲突:进入待解决列表。
协议只保证收敛,业务定义谁赢。
7. 低延迟架构怎么设计
一个可落地的实时协同架构:
1 | |
关键工程点:
- WebSocket / WebTransport,二进制协议,protobuf/flatbuffers。
- 增量操作,不要每次传整张图。
- 批量、压缩、心跳、断线重连。
- 状态向量同步:新客户端先拉快照,再拉缺失 op。
- 操作日志定期压缩成快照。
- 光标、选区、在线状态用临时消息,不写 op log。
- 本地乐观更新,服务器确认后清理 pending。
- 冲突提示 UI。
目标延迟:
- 本地:0ms 感知。
- 同区域远端:50-150ms。
- 跨区域:150-300ms,可用边缘节点优化。
8. 面试回答模板:这样讲,面试官知道你不是背题
如果面试官问:“A、B 同时把同一条线从红改蓝、红改绿,怎么保证收敛、不丢意图、低延迟?”
你可以这样答:
我会先把它定义成分布式复制状态的并发写问题。
文档模型是对象树,每个对象有稳定 ID。操作带opId、actorId、HLC、因果依赖deps。
传输用 WebSocket 二进制增量,服务器权威排序并持久化 op log,定期快照。客户端本地乐观更新,先改 UI,再异步发操作。
对 A/B 同线颜色,先判断因果:如果 B 依赖 A,则 B 是后续,最终绿。
如果 A、B 并发,同属性单值冲突。默认策略可以用 LWW Register,按 HLC + actorId 打破平局,最终选一个,所有人收敛。
如果产品要求不丢意图,就用 MV Register 保留{blue, green},UI 提示冲突让用户选。
非冲突操作,比如 A 改颜色、B 改线宽,会字段级合并,都保留。
低延迟靠本地乐观更新、WebSocket 广播、服务器全序和客户端重放 pending。
如果选型:中心权威 + OT 适合复杂文本和强服务端控制;CRDT 适合离线、多端、P2P、自动合并。实际项目常用混合:结构用 CRDT,属性用 LWW,存在感不持久化。
这个回答里有:定义、模型、协议、冲突语义、低延迟、选型、工程落地。
这就是 25k+ 的味道。
9. 高薪加分点
你要能继续往下讲:
- OT 的 TP1/TP2:变换函数正确性,保证不同顺序应用结果一致。
- CRDT 的半格:merge 满足交换、结合、幂等。
- HLC:解决物理时钟不可靠。
- 因果一致性:版本向量、状态向量。
- 撤销重做:OT inverse,CRDT undo manager。
- 权限与审计:op log 天然可审计。
- 性能:快照、日志压缩、增量同步、二进制协议。
- AI 结合:AI 可以生成操作、建议冲突解决,但 AI 操作也必须走同一套一致性层,不能绕过协议。
- 失败模式:网络分区、重复消息、乱序、离线编辑、恶意客户端、时钟漂移。
10. 常见坑
- 只背“CRDT 解决冲突”:错。CRDT 只保证收敛,不保证业务意图。
- 认为 LWW 一定错:不一定。颜色、标题这类单值属性,LWW 很常见。
- 认为收敛就等于体验一致:不是。UI 延迟、撤销、冲突提示都影响体验。
- 用纯物理时间戳排序:客户端时钟不可靠,要用 Lamport/HLC。
- 忽略因果:B 看到 A 后改绿,和 B 没看到 A 就改绿,语义完全不同。
- 忽略离线:CRDT 更适合离线,OT 通常依赖中心服务器。
- 忽略操作日志和快照:没有它们,新用户同步和恢复会很慢。
11. 最终学习检验:你能做到这些,就算精通
- 能白板画出:客户端、WebSocket、服务器、op log、快照、广播、pending 重放。
- 能写出 Op 结构:
opId、actor、hlc、deps、target、prop、old、new。 - 能写出 LWW merge 和 MV Register merge。
- 能讲清 OT 对 A/B 同线改色的变换过程。
- 能对比 OT 和 CRDT 的优缺点。
- 能解释:收敛、不丢意图、低延迟分别靠什么保证。
- 能回答追问:离线怎么办?撤销怎么办?冲突 UI 怎么做?服务器单点怎么办?
- 能说出:协议保证收敛,业务定义冲突语义。
一句话总结:
收敛靠全序或 CRDT 半格;不丢意图靠因果检测、非冲突合并和冲突策略;低延迟靠本地乐观更新和异步增量广播。
A 改蓝、B 改绿,最终要么 LWW 选一个,要么 MV Register 保留冲突,要么 OT 变换后覆盖。没有银弹,只有权衡。你能把权衡讲清楚,面试就能拿高薪。


