11# WW-RaftKV
22
3- 基于Raft共识算法的分布式 KV 存储
3+ 基于Raft共识算法的分布式` KV ` 存储
44
55## 一、简介
66
7- 该项目是一个基于 ` Raft ` 共识算法实现的分布式` KV ` 存储系统,支持节点容错、高可用部署和一致性日志复制。是 ` WW ` 系列中学习分布式系统知识后关于 ` Raft ` 的简易实现 。
7+ ` WW-RaftKV ` 是一个基于 ` Raft ` 共识算法实现的分布式` KV ` 存储系统,支持节点容错、高可用部署和一致性日志复制。该项目为 ` WW ` 系列的分布式学习项目 。
88
9- ## 二、依赖
9+ ## 二、环境
1010
11- + 系统: ` Linux ` (for ` muduo ` )
12- + 第三方库: ` Protobuf3 `
11+ + 系统:64位` Linux ` 操作系统
12+ + ` C++ ` 版本:` C++14 `
13+ + 第三方库:
14+ + ` Protobuf3 `
15+ + ` muduo `
16+ + ` concurrentqueue `
1317
1418## 三、模块
1519
16- 该实现包含了几个核心模块: ` KVStore ` ` RaftRpc ` ` Raft `
20+ 该实现包含了几个核心模块: ` KVStore ` , ` Logger ` , ` Memory-Pool ` , ` Raft-Rpc ` , ` Raft-Core ` 和 ` Raft-App `
1721
1822### 1. KVStore
1923
20- 该模块位于` raftkv/kvstore/ ` ,用于提供存分布式存储系统所需要的` KV ` 存储功能,它的底层实现是跳表。
24+ + 位于:` raftkv/kvstore/ `
25+ + 功能:是使用跳表实现的` KV ` 存储,用于提供存分布式存储系统所需要的` KV ` 存储功能,提供常见的` get ` ,` put ` ,` update ` 和` remove ` 操作。
2126
22- ### 2. RaftRpc
27+ ### 2. Logger
2328
24- 该模块用于提供` Raft ` 实现中所需要的` Rpc ` 功能,模块是基于` Google Rpc ` 框架的扩展。在该框架中,服务端由` Dispatcher ` 和` ServiceImpl ` 组成,并用` Server ` 封装,` ServiceImpl ` 提供具体方法实现,` Dispatcher ` 提供` TcpServer ` 和服务方法表,处理客户端请求;客户端由` Channel ` 组成,并用` Client ` 封装,` Channel ` 提供具体的` TcpClient ` 连接实现。
29+ + 位于:` raftkv/logger `
30+ + 功能:是一个轻量化的异步日志库,支持自定义格式化输出、同步和异步日志、轮转日志等,用于提供` Raft ` 运行时必要的日志输出。
2531
26- #### 服务端
32+ ### 3. Memory-Pool
2733
28- 服务端由以下组件组成:
34+ + 位于:` raftkv/memory-pool `
35+ + 功能:是一个三级缓存的内存池。它由线程缓存、中心缓存、页缓存三层构成,用于在高频的` Rpc ` 网络通信中,减小` new ` /` delete ` 动态分配带来的内存碎片和开销。
36+ + 应用场景:在本项目中,内存池用于` Raft ` 节点的客户端部分内存管理;服务端部分由于本` Raft ` 实现的异步设计,请求和响应并不在一个线程中,因此暂不使用内存池,交由` Protubuf ` 的` Arena ` 管理。
2937
30- + ` ServiceImpl ` : 封装` Raft ` 协议中各类` RPC ` 方法的具体处理逻辑,包括` RequestVote ` 、` AppendEntries ` 、` InstallSnapshot ` ,以及客户端操作` KV ` 存储所需要的` RaftOperate ` 方法;
31- + ` Dispatcher ` : 维护服务方法注册表,并内置一个` TcpServer ` ,用于监听连接并分发请求;
32- + ` Server ` : 对外提供统一的服务端启动接口,整合` Dispatcher ` 与` ServiceImpl ` 。
38+ ### 4. Raft-Rpc
3339
34- #### 客户端
40+ + 位于:` raftkv/raft-rpc `
41+ + 功能:用于提供` Raft ` 实现中所需要的` Rpc ` 功能,该模块是基于` Google Rpc ` 框架的扩展。
3542
36- 客户端由以下组件组成:
43+ ### 5. Raft-Core
3744
38- + ` Channel ` : 封装对某个` Raft ` 节点的连接与通信逻辑,内部使用` TcpClient ` 实现持久连接和异步消息发送;
39- + ` Client ` : 管理` Channel ` 实例,提供面向` Raft ` 协议调用的高层封装,便于发送` RequestVote ` 、` AppendEntries ` 和` InstallSnapshot ` 请求。
45+ + 位于:` raftkv/raft-core `
46+ + 功能:实现了` Raft ` 的核心算法,包括状态机切换、选举、日志复制和推进、心跳等。其核心功能包括:
47+ + 节点状态管理:支持` Follower ` 、` Candidate ` 、` Leader ` 三种角色的状态切换;
48+ + 选举机制:实现了基于任期的投票逻辑,支持随机超时选举触发与投票限制;
49+ + 日志复制:` Leader ` 将客户端请求转化为日志条目并同步给其他节点;
50+ + 日志一致性保障:通过` prevLogIndex ` 和` prevLogTerm ` 保证日志匹配性;
51+ + 日志提交与应用:日志在被大多数节点确认后提交,并推送给状态机应用;
52+ + 心跳机制:` Leader ` 定期发送心跳保持领导地位并触发空日志复制;
53+ + 任期与投票状态持久化:防止重启后错误行为;
54+ + 快照与日志压缩支持:适用于长时间运行场景下的日志膨胀问题。
4055
41- ### 3 . Raft
56+ ### 6 . Raft-App
4257
43- 该模块位于` raftkv/raft-core ` ,是关于` Raft ` 的核心算法实现,它采用状态机模式,不关心网络行为,通过上下文与应用层(` RaftClerk ` )通信。它负责处理节点间的选举、日志复制、日志提交以及状态同步等关键流程。该模块遵循` Raft ` 协议的规范设计,具备良好的可读性与可维护性,核心功能包括:
44-
45- + 节点状态管理: 支持` Follower ` 、` Candidate ` 、` Leader ` 三种角色的状态切换;
46- + 选举机制: 实现了基于任期的投票逻辑,支持随机超时选举触发与投票限制;
47- + 日志复制: ` Leader ` 将客户端请求转化为日志条目并同步给其他节点;
48- + 日志一致性保障: 通过` prevLogIndex ` 和` prevLogTerm ` 保证日志匹配性;
49- + 日志提交与应用: 日志在被大多数节点确认后提交,并推送给状态机应用;
50- + 心跳机制: ` Leader ` 定期发送心跳保持领导地位并触发空日志复制;
51- + 任期与投票状态持久化: 防止重启后错误行为;
52- + 快照与日志压缩支持: 适用于长时间运行场景下的日志膨胀问题。
58+ + 位于:` raftkv/raft-app `
59+ + 功能:实现了` Raft ` 的应用层,负责节点间的网络通信,并与` Raft ` 算法层交互。
5360
5461## 四、测试
5562
56- 测试代码位于` example/ ` 中,包含了用于模拟启动集群的` raft_example ` ,使用方法:
63+ 测试代码位于` example/ ` 中,包含了以下程序和脚本:
64+
65+ + ` raft_example ` :用于模拟启动集群;
66+ + ` raft_client ` :用于模拟客户端操作;
67+ + ` run.sh ` :启动节点` 2-6 ` ;
68+ + ` stop.sh ` :关闭所有` raft_example ` 进程;
69+ + ` clean.sh ` :清理上一次运行痕迹。
70+
71+ ` raft_example ` 使用方法:
5772
5873``` bash
5974./raft_example n
6075```
6176
62- 其中` n ` 为节点号,该集群中包含` 0-8 ` 共9个节点 。` example/ ` 中还有两个` shell ` 脚本,` run.sh ` 和` stop.sh ` ,其中,` run.sh ` 用于启动` 2-8 ` 共7个节点 ,其日志会重定向到` logs/ ` 中;` stop.sh ` 强制关闭所有` raft_example ` 进程。
77+ 其中` n ` 为节点号,该集群中包含` 0-6 ` 共7个节点 。` example/ ` 中还有两个` shell ` 脚本,` run.sh ` 和` stop.sh ` ,其中,` run.sh ` 用于启动` 2-6 ` 共5个节点 ,其日志会重定向到` logs/ ` 中;` stop.sh ` 强制关闭所有` raft_example ` 进程; ` clean.sh ` 清理上一次运行产生的痕迹 。
6378
64- ` example/ ` 中还包含了用于模拟客户端操作请求的 ` raft_client ` , 使用方法:
79+ ` raft_client ` 使用方法:
6580
6681``` bash
6782./raft_client put a b
6883./raft_client get a
84+ ./raft_client update a c
85+ ./raft_client remove a
6986```
7087
7188` raft_client ` 默认连接` node 0 ` ,确保在启动集群时,先启动该节点,再启动剩余节点,以保证` node 0 ` 能够当选` Leader ` ,当` node 0 ` 不为` Leader ` 时,` raft_client ` 请求会返回当前` Leader ` 的` IP ` 地址和端口用于重定向。
7289
73- 当前存储系统支持的操作有:
90+ 当前存储系统支持的操作有:
7491
75- + ` put ` : 不允许重复的插入键值对,使用方法为` put {key} {value} `
76- + ` update ` : 更新或插入键值对,使用方法为` update {key} {value} `
77- + ` get ` : 读取已存在的键值对,使用方法为` get {key} `
78- + ` remove ` : 删除已存在的键值对,使用方法为` remove {key} `
92+ + ` put ` : 不允许重复的插入键值对,使用方法为` put {key} {value} `
93+ + ` update ` : 更新或插入键值对,使用方法为` update {key} {value} `
94+ + ` get ` : 读取已存在的键值对,使用方法为` get {key} `
95+ + ` remove ` : 删除已存在的键值对,使用方法为` remove {key} `
7996
8097## 五、快速启动
8198
82- 这是一个快速使用` Raft ` 测试集群的示例。
83-
8499### 1. 编译
85100
86101``` bash
@@ -91,51 +106,39 @@ make -j4
91106
92107### 2. 启动集群
93108
94- 以下按顺序启动 。
109+ 以下需按顺序启动 。
95110
96- 终端1 ,启动用于观察` Leader ` 日志的节点:
111+ + 窗口1 ,启动用于观察` Leader ` 日志的节点:
97112
98113``` bash
99114cd build/example/
100115./raft_example 0
101116```
102117
103- 终端2 ,启动用于观察` Follower ` 日志的节点:
118+ + 窗口2 ,启动用于观察` Follower ` 日志的节点:
104119
105120``` bash
106121cd build/example/
107122./raft_example 1
108123```
109124
110- 终端3 ,启动剩余节点:
125+ + 窗口3 ,启动剩余节点:
111126
112127``` bash
113128cd build/example/
114129./run.sh
115130```
116131
117- 终端4,进行想要的操作:
132+ + 窗口4,进行客户端操作:
118133
119134``` bash
120135cd build/example/
121136./raft_client put hello ww-raftkv
122137./raft_client get hello
123138```
124139
125- ### 3. 运行示例
126-
127- + node 0
128-
129- ![ node 0] ( doc/img/node%200.png )
130-
131- + node 1
132-
133- ![ node 1] ( doc/img/node%201.png )
134-
135- + node 2-8
136-
137- ![ node 2-8] ( doc/img/node%202-8.png )
140+ ## 六、性能
138141
139- + client
142+ 使用 ` perf ` 工具测试 ` Leader ` 节点的性能,测试基于 ` Debug ` 模式, ` -O2 ` 优化,火焰图如下:
140143
141- ![ client ] ( doc/img/client.png )
144+ [ flamegraph-raftkv.svg ] ( doc/svg/flamegraph-raftkv.svg )
0 commit comments