Raft节点快速重启方案 #247
longfar-ncy
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
基于 log index 与 sequence number 映射的快速重启方案(望哥提出)
使用该方案的原因
pikiwidb raft 层面之下的状态机实际通过 RocksDB 做存储,RocksDB 是个基于 LSM 树的存储引擎,即便写入成功,也有可能是存在内存中而不是磁盘上,若这个时候服务器宕机,在关闭WAL的前提下,将会丢失内存中的数据。
如果要重启后保证 rocksdb 内存数据不丢失,就需要保证快照和快照之后的追加日志能够覆盖 rocksdb 内存中的数据。一种解决方案是快照时必须 flush,保证没有内存数据,但是对性能影响较大;另一种是保证追加日志能覆盖内存数据,也是本方案的核心思想。
为避免频繁 flush,提出了新的快照方案:在快照时不 flush,只对已经持久化的数据做快照,但是在截断日志时,保证不会截掉内存中数据对应的日志。后续服务器宕机后重启时,通过 braft 日志恢复 rocksdb 内存中丢失的数据和 raft 落后的日志,与原本 raft 协议有所不同的是,raft 从落后的日志开始回放,本项目应该从 rocksdb 丢失内存数据中对应的最早的日志处重放。
方案概述
一个宕机的节点重新启动时,丢失的数据分为两部分:
对于第一种,raft 协议本身就可以保证同步;对于第二种,想要通过 braft 的日志找到rocksdb内存中的数据(rocksdb的WAL被关闭),需要本地做一些支持:在重新启动后通过日志恢复数据时,保证回放的日志点在原本内存数据对应的日志点之前,最理想的情况是刚好找到原本内存数据对应的最小日志索引。本方案的设计是,在持久化时写入已持久化的最大日志索引,重启时读取磁盘上这个最大持久化日志索引,在它的基础上 + 1 就得到最理想的日志回放点。
具体来说,Pikiwidb 中的每个 rocksdb 实例都有9个列族存储数据,不同列族 flush 的进度也不同,因此需要找到最落后的列族中原内存中最旧的操作(最小 sequence number)对应的 log index。内存的数据重启后不能直接找回了,但可从落盘后的最新数据入手,即 flush 进度最慢的列族的已持久化数据中最后的写操作(最大 seqno)对应的 log index,从这个日志的后一个日志开始回放。
需要做的具体工作:
在运行时维护 applied log index 与 sequence number 的关系:
每个 Redis 实例维护一个存放所有列族 logidx 与 seqno 映射的链表,在每次异步写成功后,在该链表后添加最新的映射—— applied log index(刚刚解析的 binlog 在 braft 中的 idx)和 本次 WriteBatch 之前的 latest seqno + 1。这样就可以在 flush 时通过本次 flush 最大的 seqno 找到不超过该 seqno 的最新日志索引,flush 成功后就可以确认该索引以及之前的日志操作都是 rocksdb 已经持久化过的。
出于性能考虑,并不会每次都添加新映射,而是有一定周期地更新。
Flush 时将 log index 存入 SST 文件:
(存seqno只是为了debug,未来可删去)这里通过 rocksdb table property 特性,在每次 Flush 时将本列族的 logidx 与 seqno 的映射持久化到 SST 文件;具体来说,每次 Flush 时会对每个 key 遍历检查,我们可以保存最大的 seqno,最后利用最大的 seqno 在上述维持 seqno 与 logidx 的链表中,找到不大于该 seqno 的最大 seqno 与 logidx 的映射,这个映射中的 logidx 就是本次持久化对应的已知最新的 logidx,然后将该 logidx 写入SST,以供重启时提取。
在每次 Flush 完后,需要清理该链表:
通过 rocksdb 提供的 event listener 特性实现,在每次 flush 完毕后触发清理操作,清理掉链表中已经持久化的最新映射之前的映射,主要要保留已持久化的最新的映射。
重启后如何恢复数据:
重启后需要通过 table property 特性,从已有的 SST 文件中读取之前保存的最大的 logidx。得到所有列族中最小最新 logidx,我们应当从 logidx + 1 处开始回放 braft 操作日志。
Beta Was this translation helpful? Give feedback.
All reactions