《用 算法与数据结构 重新拆解 Raft:共识的本质不是状态,而是日志》
看到 ruanyf 老师的每周更新产生的思考, 我们常说算法 数据结构,但是是否真正的想过什么是算法? 什么是数据结构? 二者的联系是什么?
算法:
程序的逻辑核心 算法是一组定义 明确的操作步骤 ,用于 解决特定问题或完成特定任务。它是程序的“灵魂”,决定了如何处理输入数据以产生期望的输出。
例如,排序算法(如快速排序)描述了如何将一组无序数据排列为有序序列。算法的效率直接影响程序的性能。
数据结构:
数据的组织方式 数据结构是 数据的存储和组织方式,为算法提供的基础。常见的数据结构包括数组、链表、树、图等。选择合适的数据结构可以显著优化算法的执行效率。例如,哈希表适合快速查找,而树结构适合层次关系的管理。数据结构是程序的“骨架”,决定了数据的访问和操作方式。
数据结构定义了数据的组织形式(例如,顺序、层次、映射) 数据结构支持特定的操作(如插入、删除、查询)。 数据结构可以是抽象的(如队列、栈)或具体的(如数组、哈希表)。
我们拥有了 算法的执行步骤 但是 我们无法快速的获取数据,而数据结构帮了我们
数据结构是数据的组织、管理和存储格式,其目的是为了高效地访问和修改数据。 数据结构决定了数据是如何组织的,而算法则是在这个组织之上定义的操作步骤。
选择不同的数据结构,会导致实现同一个任务的算法发生根本性的变化,从而极大地影响程序的效率。
结合最近的分布式探索
如何探索 Raft 算法?
Raft 试图解决的那个 问题 是什么? 为了让算法解决这个问题,它必须操纵什么数据? 那些数据被组织成了什么结构? 算法要保证它们满足哪些不变量?
(1) 让分布式环境中的一群节点,对“输入序列”达成一致。
状态最终都是由输入序列推出来的, 只要有一个稳定的输入序列,各节点最终状态一致就是必然结果 强制每个节点拥有一模一样的日志(Log Entries)
(2) 数据结构
一个全序日志(Log)
entries: []Entry
Entry {
term int
command []byte // 给状态机的指令
}
Raft 需要保证: 所有节点的 entries 最终一致, entries 的顺序保持一致, 每条 entry 的 term 是合法的、相容的, 旧的 entry 永远不会被覆盖(除非它未提交)
一个确定性状态机(State Machine)
日志是命令序列, 状态机是命令执行器, 所以这个状态机就是数据本体。
元数据(term、commitIndex、lastApplied)
currentTerm votedFor commitIndex lastApplied
Raft 在保证日志一致性时,需要维护的一些“不变量约束”。这些不变量本身就是数据结构的一部分。
Raft 的“算法” , 对刚才的数据结构施加的一套规则、不变量、限制、流程、状态转移。
- Leader 选举(决定谁来写 Log)
- 日志复制(确保 Followers 拷贝 Leader 的 Log)
- 日志匹配规则(term + index 的不变量)
- 提交规则(某条 entry 在多数派落盘即认为安全)
- 快照规则(压缩日志)
我们应该以什么样的思维 去看待 Raft ? 并不是我们看了一遍论文, 跟着实验做了一遍就叫我理解 Raft算法了?
Raft 的数据结构是 分布式日志。 Raft 的算法是 维护分布式日志一致性的不变量 。 状态机只是日志的消费者,不是 Raft 算法本身的部分。
如何抽象出职责
什么是 算法职责 ? 什么是 业务职责?
Raft 的职责不是处理业务数据(余额、KV、用户表)。 Raft 的职责是保证每个节点收到相同的“操作序列”。
1)业务状态(余额、KV)不属于 Raft;属于“状态机”
state = {
accountA: 100,
accountB: 50,
}
这是业务数据 , Raft 不会读取它,不会写它,更不会理解它。
2)Raft 只管一件事:维护日志
[
{term:1, command:"transfer A B 20"},
{term:1, command:"deposit A 30"},
{term:2, command:"withdraw B 10"},
]
日志是 Raft 负责的数据结构 状态机是 业务负责的数据结构