系统设计练习 - 全球实时协同文档平台
背景设计一个支持多人实时协作编辑的文档系统不仅支持文本还支持- 表格- 富文本 嵌入组件图片代码块图表- 简单的设计组件类似Figma的block-based layout- 支持API和自动化类似Notion integration系统需求和范围定义功能需求- 多人实时写作编辑100ms perceived latency)- 支持离线编辑自动同步- 支持评论mention版本历史- 支持权限模型文档级block级- 支持嵌入式结构block tree/graph- 支持API/webhook/integration非功能需求- 全球低延迟- 高可用99.99%- 海量文档 10B docs1B DAU)- 多租户隔离- 安全ACL审计加密API设计系统架构设计整体系统分为三个layerclient实时同步orchestratorsnapshotoffline。整体架构图如下所示详细说明1. client拥有local DB和ops log。对于文档的每一个操作生成ops存入ops log同时将修改应用到本地文档上。并且将ops发送到service端的stream。2. orchestrator service接收所有client发送的ops做OT。关于OT的详细讨论后面会讲到。将转换过的ops发送到redis pub/sub。每个document在pub/sub创建自己的topic。client通过websocket和pub/sub建立订阅关系这个client可以快速获得一个document的所有ops然后应用到本地的版本上。3. 关于存储。orchestrator service将ops存入到ops DB。相当于service端的ops log。在后端启动一个cron job定期合并ops到document上建立document的snapshot。并通过sync service同步到全球主要的CDN上。这样一个client需要从零同步一个document时可以同步snapshot再从service端读取为应用到snapshot的ops来建立最新的document。4. 对于跨region的情况每个client和自己所在的region的service进行通信但是我们设立一个primary region所有的update都发送到primary region进行处理。这样全球只有一个region处理document更改解决一致性的问题。5. 权限管理。我们基于document ACL进行权限管理。对于更细粒度的block权限建立block tree。遵循子节点的权限设定覆盖父节点的权限设定。最终可以fallback到document ACL上。6. comment管理。comment和document分开存储。comment使用lazy load加载策略。也就是在user load到某部分document再从service query该部分的comments进行加载。这样减少一次性load的负载降低latency。讨论1. OT和CRDT。 OT和CRDT是两种协作operation的方法。具体来说OT基于一个中心进行ops的转换来解决ops之间的相互影响。例如对于文档的内容”12345“进行两个ops1在2后插入62将5改为7.两个ops可以分别为: 1) insert 6 at 2; 2change (4) to 7. 经过OT两个ops变为1) insert 6 at (2); 2) change (5) to 7. CRDT基于分布式的粒度更细的ops方式。比如对于每一个字符进行标记。这样上面的对于不同字符的操作就可以互相独立互不影响了。2. 系统性能的瓶颈最可能出现在orchestrator service。当有多个client同时更新一个文档时orchestrator会有大量的ops进行处理和fanout。我们的策略是每个document处于一个shard。在有多个document需要频繁更新时它们可以做horizontal scale。如果一个document的更新仍然可能成为瓶颈的话我们可以考虑进一步让一个document里的每一个chunk使用一个shard。3. 整个系统的source of truth为ops DB。如果系统其他部分break比如blob DB或者redis pub/sub我们可以replay ops DB里的ops对系统其他部分的信息进行恢复。4. client和service之间的websocket连接期望通过connection gateway或者proxy进行。在connection gateway可以对client进行traffic control恢复broken connection。这样可以简化后端service的设计也可以更好地维护client connection。