1. CRDT 概念与课程项目结构
CRDT(Conflict-free Replicated Data Type)是一类能够在多副本环境中自动合并更新、无需中心协调的数据结构,其数学基础保证了副本间的最终一致性。本章从核心思想出发,拆解状态与操作两种模型,并完成课程示例项目(G-Counter 计数器)的目录搭建与构建配置。
1.1 CRDT 核心思想
CRDT 的设计目标是「无冲突收敛」:任意两个副本经过同步后,最终状态一致,且合并操作满足交换律、结合律、幂等律。这消除了传统分布式系统中冲突检测与回滚的复杂逻辑。
- 最终一致性:副本允许临时不一致,但所有合法更新最终会到达所有节点。
- 无中心协调:任何副本可在离线状态下修改数据,合并时无需全局锁或领导节点。
- 自动合并:合并结果由数据结构本身的性质决定,不依赖应用程序决策。
| 性质 | 含义 | CRDT 如何满足 |
|---|---|---|
| 交换律 | A ∘ B = B ∘ A | 合并操作与顺序无关 |
| 结合律 | (A ∘ B) ∘ C = A ∘ (B ∘ C) | 多副本可任意分组合并 |
| 幂等律 | A ∘ A = A | 重复传递同一更新不会改变结果 |
1.2 状态模型与操作模型
CRDT 按同步方式分为两类,课程将同时实现两种模型以对比差异:
- 基于状态(State-based / CvRDT):每个副本周期性地发送完整状态(或增量状态),接收方执行
merge()函数。适用带宽富余但网络可能中断的场景。 - 基于操作(Operation-based / CmRDT):每个副本广播仅本次更新操作,接收方在本地重放。适用低带宽、高频率更新的场景,但需要可靠广播通道。
关键区别:状态模型对网络质量要求低(允许丢包后重传),但状态体积可能较大;操作模型体积小,但要求操作不丢失且不重复传递(需配套因果序机制)。
1.3 课程项目目录规划与搭建
课程将实现一个完整的 G-Counter(Grow-Only Counter),支持状态与操作两种同步方式,并附带单元测试与基准测试。项目使用 CMake 构建,目录布局如下:
crdt-course/
├── CMakeLists.txt # 顶层构建文件
├── README.md # 课程项目简介与使用说明
├── .gitignore
├── src/
│ ├── gcounter_state.h # 基于状态的 G-Counter 声明
│ ├── gcounter_state.cpp # 实现
│ ├── gcounter_op.h # 基于操作的 G-Counter 声明
│ ├── gcounter_op.cpp # 实现
│ └── main.cpp # 演示与基准入口
├── tests/
│ ├── CMakeLists.txt
│ ├── test_state.cpp # 状态模型单元测试
│ └── test_op.cpp # 操作模型单元测试
└── benchmarks/
├── CMakeLists.txt
└── bench_sync.cpp # 同步性能基准
1.4 构建配置与首次编译
项目依赖 C++17 及符合 OpenMP 标准的编译器(用于性能测试)。顶层 CMakeLists.txt 核心配置:
cmake_minimum_required(VERSION 3.18)
project(crdt-course LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(crdt_demo src/main.cpp src/gcounter_state.cpp src/gcounter_op.cpp)
find_package(OpenMP)
if(OpenMP_CXX_FOUND)
target_link_libraries(crdt_demo PRIVATE OpenMP::OpenMP_CXX)
endif()
enable_testing()
add_subdirectory(tests)
add_subdirectory(benchmarks)
快速开始:在项目根目录执行以下命令即可编译并运行演示程序:
mkdir build && cd build
cmake .. && cmake --build .
./crdt_demo
1.5 常见错误与调试指引
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 未找到 OpenMP | 编译器未启用 OpenMP 或缺少库 | 安装 libomp-dev(Linux)或启用 MSVC 的 OpenMP 支持 |
| merge() 结果不符合预期 | 未正确实现偏序 lattice 操作 | 确认 max() 或 join 函数对所有副本向量逐元素处理 |
| 操作丢失导致状态不一致 | 重放操作未按因果序交付 | 添加版本向量(Version Vector)追踪依赖关系 |
注意:本章建立的目录结构是整个课程的基础。后续所有章节(GCounter → PN-Counter → LWW-Register → OR-Set → 分布式同步层)都会在此骨架中添加文件。请确保 CMake 版本 ≥ 3.18,否则无法使用
add_subdirectory 和 enable_testing 的正确行为。