问题本质:创建与编辑的语义鸿沟
CRDT(Conflict-free Replicated Data Type)的核心承诺是:无论操作以何种顺序到达,各副本最终都能收敛到一致状态。这一特性在并发编辑场景下表现优异 —— 当两个用户同时修改文档的不同段落时,CRDT 能够自动合并这些变更,无需中心化协调。
然而,当场景切换到并发创建(Concurrent Creation)时,问题变得复杂。假设两个离线用户同时创建了一个名为 "project-alpha" 的项目,或者同时预订了同一时段的会议室。CRDT 的自动合并机制会忠实地保留两个创建操作,但这往往违背业务语义 —— 在大多数应用场景中,同一 ID 的资源应当唯一存在。
这种矛盾的根源在于:编辑操作具有可交换性,而创建操作涉及身份(Identity)的独占性声明。Loro 团队在文档中明确指出,当业务逻辑要求强不变量(如资源独占、严格排序)时,纯粹依赖 CRDT 可能导致状态违反预期。
并发创建的核心挑战
1. 不变量冲突
并发创建最常见的风险是破坏业务不变量。以会议室预订为例:两个用户同时提交对 "2026-06-10 14:00 会议室 A" 的预订请求。如果系统仅依赖 CRDT 合并,最终状态可能显示两个预订同时存在,这显然违背了 "同一时段只能有一个预订" 的业务规则。
2. 胜者选择的语义缺失
CRDT 本身不提供 "哪个创建应该胜出" 的语义判断。当两个创建操作在逻辑上冲突时,系统必须引入外部策略来决定最终结果。这种策略的选择直接影响用户体验和数据完整性。
3. 数据丢失风险
某些冲突解决策略(如 Last-Writer-Wins)在确定胜者时会丢弃另一方的创建数据。如果丢失的创建包含用户已投入大量工作的内容,这种静默丢失将造成严重体验问题。
工程化解策略对比
针对并发创建冲突,业界形成了几种主流策略,各有其适用场景与权衡。
策略一:Last-Writer-Wins(LWW)
机制:为每个创建操作附加复合时间戳(逻辑时钟 + 节点 ID),时间戳较高的操作获胜,另一创建被丢弃或标记为失效。
适用场景:对实时性要求高、可接受单一方数据丢失的场景,如临时草稿、缓存数据。
参数建议:
- 时间戳精度:毫秒级逻辑时钟配合节点 ID 去重
- 时钟漂移容差:设置最大可接受漂移阈值(如 5 秒),超出阈值触发冲突告警
- 数据保留:即使采用 LWW,也应在本地保留被覆盖方的数据 7 天,支持用户手动恢复
风险:可能丢失非胜方的完整创建内容,不适合高价值业务对象。
策略二:Add-Win / Remove-Win Set
机制:不立即选择胜者,而是将并发创建作为独立条目保留在集合中,后续通过业务规则或用户介入进行合并。
适用场景:协作编辑、目录管理等可接受临时存在多个候选对象的场景。
实现要点:
- 使用 OR-Set(Observed-Removed Set)变体跟踪添加操作
- 为每个候选对象维护创建元数据(创建者、时间、设备指纹)
- 设置自动合并超时:若冲突在 24 小时内未解决,触发管理员介入
优势:不丢失任何一方的创建数据,支持事后审计与恢复。
策略三:冲突日志 + 用户介入
机制:检测到并发创建时,系统记录冲突事件,向相关用户展示差异对比界面,由用户决定保留哪个版本或手动合并。
适用场景:高价值业务对象(合同、配置、关键项目)的创建冲突。
工程实现清单:
- 冲突检测:基于 Vector Clock 识别真正的并发操作(而非因果相关的顺序操作)
- 差异展示:并排对比冲突双方的字段级差异,高亮关键字段冲突
- 决策持久化:记录用户的冲突解决决策,用于后续审计
- 回滚支持:允许在 30 天内撤销冲突解决决策,恢复到冲突前的分支状态
策略四:混合架构(CRDT + 中心化协调)
机制:本地使用 CRDT 保证离线可用性与响应速度,关键创建操作(如资源分配、唯一标识分配)通过中心化服务或共识协议(Raft/Paxos)进行仲裁。
适用场景:需要同时满足离线优先与强一致性要求的生产系统。
架构参数:
- 本地 CRDT 层:处理 UI 状态、草稿编辑、非关键元数据
- 协调层:独占资源分配、全局唯一 ID 生成、关键业务规则校验
- 同步策略:本地操作立即响应,协调层异步验证;若验证失败,向用户展示冲突并回滚本地状态
- 降级方案:协调层不可用时,允许本地继续操作,但标记为 "待确认" 状态,限制后续依赖操作
Loro 的实践建议
Loro 作为高性能 CRDT 库,对并发创建问题提供了明确的工程指导:
-
区分场景:将操作分类为 "可自动合并"(文本编辑、列表追加)与 "需显式协调"(资源创建、身份分配)两类,分别采用不同处理路径。
-
延迟绑定:对于可能冲突的创建操作,先生成本地临时 ID,待与协调层确认后再映射为全局唯一 ID。这种 "延迟绑定" 策略避免了离线状态下的 ID 冲突。
-
冲突可视化:当检测到长期离线后的高冲突风险时,主动向用户展示差异视图(Diff View),将技术层面的合并决策转化为用户可理解的选择。
-
版本控制集成:利用 CRDT 的版本追踪能力,为冲突场景提供 "分支 - 合并" 语义,允许用户像处理代码冲突一样处理数据冲突。
可落地的检测与解决参数
基于上述策略,以下是可直接应用于生产环境的参数配置:
| 参数项 | 建议值 | 说明 |
|---|---|---|
| 冲突检测窗口 | 30 秒 | Vector Clock 差异超过此阈值视为并发冲突 |
| LWW 数据保留期 | 7 天 | 被覆盖方的创建数据在本地保留时长 |
| 自动合并超时 | 24 小时 | Add-Win 策略下未解决冲突触发告警的时限 |
| 用户决策持久化期 | 90 天 | 冲突解决决策的审计日志保留期 |
| 协调层超时降级 | 5 秒 | 等待中心化协调响应的最大时长,超时切换为本地模式 |
| 冲突回滚窗口 | 30 天 | 允许撤销冲突解决决策的时间范围 |
总结
CRDT 的自动合并能力为分布式协作带来了巨大便利,但开发者必须清醒认识到其边界:并发创建涉及身份与所有权的独占性声明,无法通过纯 CRDT 机制自动化解。工程实践中,应根据业务语义选择合适的策略组合 —— 对于可交换的编辑操作,充分信任 CRDT 的自动合并;对于涉及资源独占的创建操作,引入 LWW、Add-Win 或混合架构进行显式处理。最终目标是在技术收敛性与业务正确性之间找到平衡点,让离线协作既流畅又可靠。
参考来源
- Loro 官方文档:When Not to Rely on CRDTs
- CRDT 冲突解决策略综述:Conflict Resolution Strategies - OneNoughtOne
- Hacker News 讨论:Loro's rich text CRDT (ID 39102577)
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。