尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Multi-Paxos核心优化解析:选主、日志连续性与幂等机制
前两篇把 Basic Paxos 和它的核心证明讲完之后评论区和私信里问得最多的一个问题就是光是一个值都要 Prepare Accept 两轮 RTT那生产环境里一份日志几千上万个条目总不能每一条都这么来回折腾吧问得没错。Basic Paxos 解决的是在多个提案者竞争下让一个值最终能够被确定的问题它牺牲了效率换正确性。而真正要拿去支撑一个分布式日志系统、存储系统、配置中心我们需要的是 Multi-Paxos——同一套协议思想但做了好几层工程上和算法上的优化。这一篇就把 Multi-Paxos 里最关键的几个优化拆开来讲选主、日志连续性、幂等去重、任期编号这些。我会尽量把每个优化背后的为什么讲透也会捎带一些我自己实现精简版 Multi-Paxos 时踩过的坑看完你应该能对这条演进路线有个完整的认识。1. 为什么 Basic Paxos 跑不了一个日志系统再次从起点出发1.1 Basic Paxos 的两轮 RTT 到底贵在哪先回顾一下 Basic Paxos 一次完整决策的流程Proposer 选择一个编号 n向 Acceptor 的多数派发 Prepare(n)。Acceptor 收到后承诺不再接受编号小于 n 的提案并且如果自己已经接受过某个值就把它返回给 Proposer。Proposer 收集多数派响应。如果有人返回过已接受的值就必须选择其中编号最大的那个值如果没有才能自己选新值。Proposer 发送 Accept(n, v) 给多数派。Acceptor 如果没收到更高编号的 Prepare就接受这个提案然后向 Proposer 回复 Accepted。这里的关键是Prepare 阶段是为了发现历史上是否已经存在一个可能被确定的旧值。如果不存在Proposer 才敢提交新值。存在就必须沿用旧值。这是 Basic Paxos 安全性的根基。如果把这套流程放到日志系统的场景里问题就暴露出来了。日志是一个按序号排列的多值序列每共识一个值理论上都要重新跑一遍 Prepare Accept。每次共识要两个 RTT1000 条日志就是 2000 次网络往返。集群里 3 个节点还好要是 5 个节点、跨机房部署这个延迟累积起来会让系统完全没法用。更重要的是Basic Paxos 本身不保证日志的连续性。不同 Proposer 可能会在不同时刻竞争不同序号有的序号已经决策出了值有的序号还是空洞新的 Proposer 还需要来回协调。协调不畅的时候整个系统会卡在不知道该往哪个槽位写什么的状态里。1.2 活锁Basic Paxos 在实际系统中的死法单纯分析 RTT 还只是性能问题更让人头疼的是活锁。假设两个 Proposer 同时想要推进共识P1 发送 Prepare(1) 给多数派得到批准。P2 发送 Prepare(2) 给多数派因为编号更高Acceptor 承诺忽略编号小于 2 的提案也批准了。P1 发送 Accept(1, v1)但 Acceptor 已经承诺不接收小于 2 的编号所以拒绝。P1 不甘心提高编号发送 Prepare(3)。P2 发送 Accept(2, v2)但 Acceptor 已经承诺不接收小于 3 的编号所以拒绝。P2 也提高编号发送 Prepare(4)。两个 Proposer 交替踩刹车谁也提交不了值这就是活锁。活锁不是死锁系统没完全卡死但永远在反复协商没有任何进展。Basic Paxos 论文明确说了如果不引入额外的机制让其中一个 Proposer 优先协议可能永远无法达成决定。Multi-Paxos 的第一个核心思想就是从这些竞争里面选出一个 Leader让大多数时间里只有这一个 Proposer 在干活。竞争从常态变成异常异常才付出多轮协商的代价。1.3 从一个值到一串值问题的维度变了还需要意识到一个问题维度的变化。Basic Paxos 做的是单值共识Multi-Paxos 做的是日志复制或者说序列共识。序列里的每个条目之间是有顺序关系的状态机必须按序应用它们所以不能只保证单个值一致还要保证整体顺序一致。这样一来光靠 Basic Paxos 那套每个值独立达成一致的思路是不够的。我们真正需要的是一个能持续运行的协同机制一个 Leader 持续产生日志条目其他节点持续跟进出现分歧时再回到共识算法去解决。所以 Multi-Paxos 的优化不是某一个点位的改进而是一套围绕 Leader 机制展开的组合优化选出一个稳定的 Leader平时只有它能发起共识。当 Leader 稳定时Phase 1Prepare可以一次性做完后续所有日志条目的提交只需要 Phase 2Accept。引入日志连续性约束让 Leader 的日志天然成为一个有序、紧凑的序列减少后续补齐的代价。引入任期编号epoch和幂等机制保证安全性不因为 Leader 切换而崩塌。这一篇接下来会逐个展开。2. 选主优化把两轮 RTT 收敛到一轮2.1 一个朴素但关键的观察多数派交集一次就够了我们先从最本质的观察说起。Basic Paxos 里每一轮共识都需要 Prepare是因为任何两个多数派之间必有交集新 Proposer 必须通过 Prepare 去访问这个交集才能知道之前是否已经有值被确定。但是如果系统中的 Proposer 是固定的、唯一的那一个它成功当选之后所有 Acceptor 都会承诺不再接受编号低于当前 Leader 任期编号的任何提案。在这个前提下Leader 对每个新的日志槽位其实可以直接发 Accept不需要再逐条 Prepare。为什么因为 Acceptor 已经向这个 Leader 的任期做出了承诺。任何旧任期的 Leader 发来的 Accept 都会被拒绝不会出现两个 Proposer 同时对同一个槽位提交不同值的情况。既然不会发生竞争Prepare 的探测历史值功能对这个 Leader 自身上下文来说就变得多余了。只有在切换 Leader、且新 Leader 不确定某些槽位历史值的时候才需要重新走一次 Prepare。这个优化把常见路径下每个日志条目的决策延迟从两轮 RTT 降到了一轮 RTT。如果在同机房内一轮 RTT 大约是 0.5~1ms 量级日志吞吐能提升一个数量级。2.2 选举之后准备阶段只发生一次具体怎么落地Multi-Paxos 中每个 Proposer 想要成为 Leader要先启动一轮选举Proposer 选择一个新的任期编号 E发 Prepare(E) 给所有 Acceptor。Acceptor 如果发现 E 大于自己见过的最大编号就记录 E并且承诺不再接受编号小于 E 的提案同时返回自己已接受的所有日志条目信息或者至少返回未确定部分的日志。Proposer 收到多数派的 Prepare 响应后就能确定自己是 Leader 了。这里要注意这个 Prepare 在最瘦的实现里可以只交换下一个可用的日志槽位和自己的日志信息。但如果这条日志本身很庞大全量交换开销很大所以工程上常用版本向量、哈希快照、分块拉取等方式来做增量同步。成功当选之后Leader 会记录当前任期号并对每个后续的日志序号直接执行 Accept。Acceptor 看到这个 Leader 的任期号等于自己承诺的任期号就正常接受。直到某个 Acceptor 发现有一个比当前 Leader 任期编号更高的 Prepare 来了它就会拒绝当前 Leader 的 Accept。当前 Leader 发现自己失去领导权就退到 Follower 状态等待新高任期周期的选举。这个过程有点像拿一个令牌轮流干活令牌丢了就重新抢。2.3 Leader 挂了以后新 Leader 怎么接手选主优化虽然省了 RTT但它带来了一个配套问题Leader 挂了新 Leader 怎么保证接手后不产生分叉在 Basic Paxos 里每个槽位的 Prepare 是在需要提交该槽位时才做的。Multi-Paxos 因为平时跳过了 Prepare切换 Leader 时就必须把之前跨过的步骤补上。具体来说新 Leader 当选时它必须向多数派询问在我没参与的那些槽位上是否有已经被决定或可能被决定的值这本质上是一个批量化的 Basic Paxos Prepare。一个务实做法是新 Leader 把本地缺失的日志区间找出来对每个缺失槽位发起一轮批量 Prepare查询该槽位的已接受值。如果返回了某个值就沿用如果多数派都说没值New Leader 就可以自由填值。这个过程的复杂度取决于旧 Leader 在职期间产生的日志量。旧 Leader 正常推进时它已经把自己的日志复制到了多数派所以新 Leader 只需要补上少数被截断的日志。真正的困难在于旧 Leader 可能已经将某些值提交给了客户端但还没来得及复制给所有节点。这时必须靠多数派交集来发现这个值绝不能擅自覆盖。我在实践中遇到过一种危险情况旧 Leader 在宕机前把槽位 100 的值 v1 提交给了客户端但只有两个节点保存了这个值总集群 3 节点另一个节点没跟上。新 Leader 当选后发现本地日志只到槽位 80于是向两个节点发 Prepare。此时上述两个保存了 v1 的节点会在响应中带上 v1新 Leader 发现槽位 100 已有值就沿用 v1。这个机制是可靠的。但如果新 Leader 只问了其中一个节点且这个节点恰好没保存 v1而另一个断连的节点保存了 v1那么新 Leader 就会误以为槽位 100 是空位填上自己的新值 v2。然后断连节点恢复把 v1 扩散出去两个节点各自认为自己持有已提交值状态就分叉了。所以新 Leader 的 Prepare 响应必须来自多数派这个多数派条件绝不能被省略即使在 Multi-Paxos 中能做大量优化这个安全底线也始终不能破。2.4 成本收益对比什么时候选主优化值得我把两种情况的成本做一个对比写代码的时候心里要有谱场景Basic PaxosMulti-Paxos含选主常规提交一个日志条目2 RTT1 RTT连续提交 1000 个条目2000 RTT1000 RTT 1 次选主开销Leader 切换无需特殊处理一次批量 Prepare开销与日志长度相关竞争激烈多个 Proposer可能活锁选主失败时仍有竞争但成功后消除得出的经验结论是如果你的系统只是偶尔提交一个配置项Basic Paxos 足够只要你会连续提交大量日志条目选主优化就值得做。现实中几乎所有生产级 KV、存储、配置中间件都会走这条路线因为网络 RTT 是分布式系统最贵的资源之一。3. 日志连续性与空洞补齐Multi-Paxos 最容易被低估的优化3.1 复制日志到多数派不只要决定还要可用Basic Paxos 只关心某个值被确定至于这个值是否存在于每个节点的本地磁盘它不管。Multi-Paxos 不能这么任性因为日志是要给状态机应用的而状态机要求日志按顺序、连续地被应用。所以 Multi-Paxos 加入了一个基本要求Leader 将每条日志条目发送给所有 Acceptor收到多数派确认后才向客户端回复成功。这个复制到多数派视为已提交的行为保证了最终所有节点都能通过日志复制获得一致的日志映像。在 Basic Paxos 里多数派的作用是为了未来访问时发现历史已提交值。在 Multi-Paxos 里多数派还有另一层含义让新 Leader 在切换后可以通过多数派交接收回所有已提交记录。这也是为什么 Multi-Paxos 的日志必须复制到多数派而不是复制到所有节点才算提交——复制到所有节点太慢只要有任何一个节点抖动系统就无法提交了。3.2 空洞问题Leader 的日志未必连续引入连续这个要求后新的问题来了旧 Leader 写入一批日志时可能某些槽位没能成功复制到多数派。比如槽位 5 的 Accept 被 Acceptor 因网络分区丢失了但槽位 6 成功了。作为新 Leader它看到自己本地日志可能是slot 1: v1 slot 2: v2 slot 3: (空洞) slot 4: v4 slot 5: (空洞) slot 6: v6如果把这条日志直接交给状态机应用状态机在应用完 slot 2 后就会卡住因为 slot 3 没有值。工程上最简单的处理是把这些空洞视为尚未决策的槽位新 Leader 必须用 Prepare 查询这批槽位判断是否可以自由填值。如果多数派说这个槽位在我这里没有值才可以将新的日志条目写入这个空洞如果返回了某个值必须沿用。针对空洞业界通常还有两种补充手段主动补齐Leader 对自己日志中缺失的槽位发起查询根据多数派返回结果填充它们然后才继续推进新的日志。这就保证了 Leader 的日志在可应用前缀上是连续的。流水线式补齐在准备阶段Leader 可以并行地发起多个槽位的 Prepare或者用一个批量消息携带多个槽位一次性把整段空洞填满避免每个空洞都来一次 RTT。实际操作中我更推荐逐段补齐加批量查询的组合。比如一次 Prepare 查询连续64个槽位而不是一条一条查这样当 Leader 日志空缺较大时能显著减少网络往返。3.3 nextIndex 和 matchIndex从 Leader 视角管理跟随者进度在 Leader 连续提交新日志的同时它还要维护每个节点复制进度。这通常用两个临时视图来跟踪nextIndex[i]表示 Leader 认为节点 i 下一个应该接收的日志序号。matchIndex[i]表示 Leader 已知节点 i 已经匹配的最新日志序号。当 Leader 向节点 i 发送日志条目时用的就是 nextIndex[i] 位置的日志。节点 i 成功追加后Leader 就把 matchIndex[i] 更新为这条日志的序号。如果节点 i 告诉 Leader这个序号我这里没有比如节点刚加入或者它的日志还停在旧位置Leader 就回退 nextIndex[i]找到双方匹配的位置后再补发。这个机制在 Multi-Paxos 论文里没有被细讲但它确实是工程实现的核心。它把空洞补齐和正常日志推送统一成同一个机制Leader 知道自己和每个节点之间的差异然后持续往差异处补发日志直到跟上为止。我实现时提过一个小优化当节点落后较大时不要一条一条回退那样可能要几十次 RTT。更好的是先通过 BundleRequest 让节点报告它现在拥有的最高序号Leader 直接从那个序号后续开始补发效率能快很多。3.4 连续性约束下的跳跃只提交前缀已满的日志还有一个容易踩的坑Multi-Paxos 并不要求把日志空洞填满才能推进新日志但要求提交新日志时必须保证新日志的槽位前面没有未提交的空洞。为什么因为状态机需要按序应用。假如你已经把槽位 100 复制到了多数派但槽位 90 还在空洞状态那槽位 100 虽然在多数派里存在也无法被应用。如果先回复客户端槽位 100 成功然后槽位 90 又突然被其他旧 Leader 的提案填上了不同的值那状态机的应用顺序就错乱了。所以在实现里我一直把能让状态机推进的提交最小值和日志在多数派里的最大值分开。前者是一个连续的前缀只有当前缀满足槽位 0 到 k 都已确认才能把 commitIndex 推进到 k。这算是一个独立于 Basic Paxos 正确性的层但对 Multi-Paxos 的实用性至关重要。你在读各种 Multi-Paxos 论文时会看到它们反复强调副本间日志连续性是 Paxos 的一个假设实际实现必须自己维护。这一句话到了工程里就是上面整套逻辑。4. epoch、幂等与旧主复活安全性兜底的三道锁4.1 为什么不能复用 Basic Paxos 的 Ballot NumberBasic Paxos 里每个提案都有一个全局唯一的编号Ballot Number用来打破竞争。Multi-Paxos 选定 Leader 后其实可以把它用到晋级机制里每个 Leader 拥有一个递增的任期编号epoch它大于之前所有 Leader 的编号。在 Multi-Paxos 的实现里通常不再用每个日志条目一个 Ballot Number而是每个日志条目引用当前 epoch加上该条目在 Leader 内的序号seq组成唯一标识。这个抽象足够简单而且为后续做幂等打下基础。为什么不用 Ballot Number 了因为 Ballot Number 只保护同一个槽位不被覆盖但 Multi-Paxos 还需要保护同一个槽位不能由不同的 Leader 决策出不同的值。epoch 天然具备全部作用所有 Acceptor 只认可当前最高 epoch 的 Leader 的决定旧 Leader 的所有操作在 Acceptor 看来都会被拒绝。这比为每个槽位单独比较编号要直观得多。4.2 幂等同样的请求不能重复生效如果只靠 Leader 主导一切重复请求的问题就会开始冒头。举个例子客户端向 Leader 发送了一个写请求请求里写的是Set(keyfoo, valuebar)。Leader 给它分配日志槽位 1然后向多数派复制成功回复客户端成功。但如果这条请求因为网络原因被客户端重试了好几次每次 Leader 都会分配新的日志槽位结果同一个 key 被执行了多次状态就错了。Multi-Paxos 处理这个问题的标准做法是为每个请求分配一个唯一的请求 ID并把这个 ID 记录在日志条目里。状态机应用一个日志条目时检查这个 ID 是否已经应用过如果应用过就直接丢弃重复结果返回之前记录的值。这里的坑在于请求 ID 必须全局唯一且不能只在客户端生成一个随机数了事。如果客户端崩溃重启它的随机数序列可能重来还是可能碰撞。我在实践中通常让客户端保留一个客户端 ID 自增序号的复合 ID服务端在应用时以这个复合 ID 为准去重。这样即使客户端重启只要它从持久化中恢复自增序号也不会产生重复。4.3 一个典型崩溃场景旧 Leader 复活后怎么办这是安全问题上最容易翻车的地方。我见过一个团队在初版实现里忽略了旧 Leader 复活后的处理结果出现了非常诡异的数据错乱。场景这样Leader L1 的 epoch 是 5。它成功向多数派提交了日志条目到槽位 50然后向客户端回复了成功。接着 L1 进程所在节点发生瞬间假死网络抖动、进程挂起、GC停顿都有可能导致集群里的其他节点认为 L1 失联发起选主选出了一个 epoch 为 6 的新 Leader L2。L2 正常提交了一批新日志。这时候 L1 恢复了它以为自己还是 Leader继续用 epoch 5 往 Acceptor 发 Accept。正是因为 Acceptor 承诺过不再接受编号小于当前 epoch 的提案L2 的 epoch 是 6所以 L1 的 Accept 会被大多数 Acceptor 直接忽略。但如果实现里 Acceptor 没有正确持久化当前最高 epoch这个信息那么节点重启后它的承诺就全部丢失。旧 Leader 带着一个低于当前 epoch 的编号发起 Accept一个刚重启的节点因为它本地没记录我已经承诺过更高的 epoch可能会误接受。为了堵住这个漏洞Acceptor 必须把当前最高 epoch 持久化到磁盘并且每次重启后恢复这个值。另一个需要防范的盲区是旧 Leader 在恢复后如果发现在发送 Accept 时收到了拒绝响应它不能立刻认为我还在领导位置它应该立刻进入 Follower 状态主动同步新 Leader 的日志。这个行为很多初版实现都忽略了——他们会认为我只是这一条日志失败了下一条重试就好结果在旧 Leader 视角下产生了一个断裂的日志视图。我处理这个场景时用的策略是旧 Leader 在收到任何来自 Acceptor 的拒绝 Accept原因epoch 太低响应时直接停止接受本地客户端的写请求并把请求重定向/转发给当前最可能的新 Leader。同时在状态机层面准备一个重新选举的入口让运维可以手动确认新 Leader 的身份。这套策略虽然看起来简单但它能把很多卡在半新半旧状态的集群问题提前消解掉。4.4 从安全性角度回看三个优化把刚才讲的三道锁串起来看它们其实是三个不同层面的兜底epoch 保证了旧 Leader 不能干扰新 Leader 的决策幂等保证了用户请求重复执行也不会产生副作用Acceptor 持久化承诺保证了即使节点重启承诺仍然有效。这三者合一Multi-Paxos 的安全性才能站得住。没有 epoch选主优化形同虚设没有幂等日志能同步但状态机不能复用没有持久化承诺之前的选主和日志复制全部白搭。在实现顺序上我建议先做幂等再做 epoch最后做持久化承诺。因为幂等是最好验证的把同样的日志条目应用两次检查状态是否和只应用一次一致。而 epoch 和持久化承诺必须在正确性测试里专门构造Leader 切换 旧 Leader 复活的场景才能充分验证。5. 实现 Multi-Paxos 时我踩过的坑与取舍5.1 日志压缩和快照不能截断到多数派之外Multi-Paxos 集群运行久了日志会无限增长。做快照压缩是必然选择。快照的本质是记录状态机在某个日志序号 K 时的完整状态。应用时直接加载快照然后应用 K 之后的日志。但这里有一个非常容易被忽略的坑如果某个节点落后太多它可能还没有 K 对应的日志这时向它发快照是没问题的。但如果 Leader 为了压缩空间把自己日志从 0 截断到了 K那么当它未来要把这个 K 之前的日志复制给一个新节点时就无能为力了。所以做日志压缩时必须保证截断操作只能截断已经被多数派持久化的部分也就是已经提交的日志未提交的日志绝对不能截断。否则万一这些日志是某个新 Leader 补空洞所需的而多数派里已经没有完整副本了整个共识过程就会失去可以追溯历史值的依据。我曾经见过一个实现用磁盘占用达到 80% 就做一次全量快照截断的策略但因为忘把未提交日志最后一小段排除在截断范围外导致分布式日志一致性测试在运行到某个时刻后出现概率性的失败。排查了很久最终发现就是这个截断边界没掐准。正确的做法是快照截断位置必须小于等于多数派节点已经 match 的最低下限同时要确保截断位置对应一个已提交的槽位。否则宁可多保留几个日志也不要冒丢失历史值的风险。5.2 成员变更多数派膨胀后如何避免双主大部分讲义讲 Multi-Paxos 就停在日志复制了但实际生产里集群一定会遇到节点扩缩容。成员变更的实现难度比所有人预想的都要高。经典的坑是新增节点还没追上日志就想直接把它加进投票集合里。假如集群原本是 3 节点A、B、C现在要扩容到 5 节点A、B、C、D、E如果 D、E 还没同步到当前已提交日志就直接把 Quorum 从3 个中的 2 个变成5 个中的 3 个那么理论上可能出现A、B 两个节点形成了旧 Quorum认为某值已提交C、D、E 三个节点形成了新 Quorum认为另一个值已提交而这两个 Quorum 的交集为空——分叉就此产生。安全做法通常是分两步走先把集群从 3 节点调整为旧集合 3 节点 新集合 2 节点的联合 QuorumJoint Consensus状态期间提交任何值都必须既得到旧集合的多数又得到新集合的多数。等新的 2 个节点追平日志后再把配置切成纯新集合的 5 节点 Quorum。这样设计其实是把成员变更本身当作一条日志记录下来每个节点应用这条日志时原子地切换进下一阶段配置。在实现 Multi-Paxos 时我建议把配置变更也放在日志里而不是用一个独立的配置服务去改。否则你很难保证配置变更和日志推进在时间上强一致。5.3 一个被低估的细节并发 Accept 的顺序保证在 Basic Paxos 里一个 Proposer 同一时间只发一个 Accept顺序天然一致。但 Multi-Paxos 为了吞吐通常会一个窗口内并发提交多个日志条目。这时候如果处理不好日志到达对端节点的顺序可能乱掉导致某个节点收到的日志序号不是递增的。有些实现选择直接要求「节点必须按序接收日志」否则拒绝。这样实现简单但吞吐受限于最慢节点。有些实现则把日志队里排序和提交点分开处理收到乱序日志先缓存再在后台重排。我自己更倾向于第二种。因为绝大多数复制失败都发生在少数慢节点上如果让它们阻塞整个集群的提交窗口代价太大。我会给 Leader 设置一个滑动窗口例如 128~512 个待提交条目窗口内允许并发 Accept底层消息里带上序号信息对端按窗口大小缓存乱序数据直到窗口内所有序号到齐后再交给状态机。同时还要记得给日志添加一个提交标记。只有当 Leader 确认某条日志已经被多数派接受后才会在跟随者上应用它。如果只是收到但没确认提交那它只能算暂存。5.4 如果只是做产品其实更推荐直接用 Raft这可能是最后一节里最实在的一条经验如果是为了给产品提供一个可靠的一致性日志库除非你有非常特殊的需求否则我会劝你直接用 Raft而不是自己实现 Multi-Paxos。Raft 本质上就是为了可理解性重新设计的 Multi-Paxos它把 Multi-Paxos 中隐式的选主、日志连续性、成员变更这些优化点全部显式地拆成了模块。社区里成熟的 Raft 实现非常多工程上的坑基本都被踩平了。Multi-Paxos 的价值更多在于理解共识算法本身以及在一些论文、实验、面试里展示你对一致性协议的深度认知。但如果你确实要实现一个接近 Multi-Paxos 的系统那本文提到的几个点选主、日志空洞补齐、幂等去重、旧 Leader 复活、成员变更、快照截断是无论如何都绕不开的。把这几个点都整理成测试用例逐个击破系统才敢拿到生产环境上去跑。我在自己的学习项目里是用 Python 写过一个精简版多节点模拟器来验证这些逻辑的。每轮模拟上万次随机 Leader 切换、节点宕机、网络延迟观察是否出现状态分叉。这种暴力验证虽然耗时很长但真的能逼出不少在理论上很难发现的问题。如果你也在实现 Multi-Paxos我非常推荐也写一个这样的 chaos simulator它比任何静态推理都能说明问题。写到这里有关 Multi-Paxos 的优化其实已经讲完了。从选主到日志连续性再到幂等每一步都是在不乱丢安全性的前提下把效率一点一点挤出来。希望这篇能帮你把 Multi-Paxos 这条链路的逻辑理顺。如果你正在实现自己的共识模块我建议先从最慢最简单的 Basic Paxos 起然后把 Multi-Paxos 的优化一层层往上加不要一上来就搞一个巨型系统那样出了问题会非常难调试。
RELATED

相关推荐

Canvas 2D 实时渲染心电波形:高频数据流可视化与性能优化实践

Canvas 2D 实时渲染心电波形:高频数据流可视化与性能优化实践

简介:这份资源面向前端开发者与医疗健康类应用开发者,聚焦如何用HTML5 Canvas实现动态心电图绘制,解决浏览器端实时展示ECG波形、模拟监护仪效果的问题。包内共7个文件,以js脚本、html页面、css样式为主,另含txt说明与…

📅 2026/10/18 8:17:23
零基础编程学习路线:从第一行代码到完整项目实战

零基础编程学习路线:从第一行代码到完整项目实战

我到现在还记得第一次在终端里敲下那行代码时的感觉,说不上激动,更多是不确定。光标闪了两下,屏幕上跳出一句"Hello, World",我盯着它看了很久,心里只有一个念头:这件事好像没有想象中那么难。就…

📅 2026/10/18 8:12:22
从模糊缩写到可执行方案:拆解“rea”背后的技术选型与工程落地

从模糊缩写到可执行方案:拆解“rea”背后的技术选型与工程落地

1. 从“rea”这个标题说起:一个被低估的缩写背后藏着什么第一次看到“rea”这个标题的时候,我脑子里蹦出来的第一反应是——这大概率又是一个被缩写玩坏了的项目名。做技术的人都有这个毛病,喜欢把长名字砍成三四个字母,图省事&am…

📅 2026/10/18 8:12:22
MORE NEWS

更多资讯

📰

AI编程工具范式收敛:TRAE双端合并背后的协议对齐

1. 这不是功能叠加,而是AI编程工具的范式收敛“TRAE 合并双端之后,AI 编程工具正在走向同一个方向”——这句话初看像一句行业观察,细想却是一把解剖刀,精准切开了过去三年AI原生开发工具演进的底层逻辑。我从2021年就开始跟踪这类…

📰

YOLO边缘端部署实战:C#上位机与工业缺陷检测系统架构解析

1. 项目整体思路:为什么把YOLO放到边缘端跑1.1 场景痛点:传统上位机方案卡在哪去年年中接到一条产线的视觉检测改造需求,我当时最开始的想法是沿用过去的套路:工业相机拍照,图像传到工控机的上位机软件里,上…

📰

HTML5响应式简历模板:单文件交付与绿色语义设计

简介:这是一款专为求职者打造的绿色主题HTML5响应式个人简历模板,面向前端初学者与正在准备求职作品集的开发者,解决在线简历缺乏专业性、适配性差及技术展示力不足的问题。资源包共50个文件,包含20张高清图片(用于头像…

📰

从模糊标题到技术落地:以rea为例的项目拆解与选型方法论

1. 从“rea”这个标题说起:一个被低估的万能缩写第一次看到“rea”这个标题的时候,我脑子里蹦出来的第一反应是——这到底是个啥?是某个工具的缩写?某个项目的代号?还是某个技术栈的简称?说实话&#xff0c…

📰

前后端分离餐厅管理系统实战:Flask+Vue+PyCharm全栈开发与踩坑解析

前后端分离做餐厅后台管理系统,这个名字一看就是典型的实战型全栈项目。标题里Flask、Vue、PyCharm、Django挤在一起,信息量不小,大概也说明这个项目经历了一段技术选型的折腾路。作为一个做过不少类似管理系统的开发者,我今天就围…

📰

从召回、排序到重排:X平台For You推荐算法全链路解析

聊算法的人很难不注意到X平台那套“For You”信息流。它是目前社交平台里少有的把推荐系统全链路公开讨论过的案例,从候选生成、排序到重排都值得拆一拆。不管你是做推荐系统的新人,还是已经在信息流业务里摸爬滚打多年,把这条链路的每个环节…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬