OBServer 启动恢复解析
作者:令川,一个在 OceanBase 专注打造稳定可靠好用存储引擎的研发同学。
OceanBase 是一个单进程软件,进程名叫:observer。
本文简单介绍进程 observer 启动后的逻辑,里面包含进程恢复的逻辑。本文对排查进程 observer 启动失败原因有一定参考作用。
目录结构
在标准配置下,observer 进程的执行目录结构如下所示,介绍其中几个比较关键的目录和其中的文件内容。
1.bin 目录下存放是 observer 以及一些其他工具的二进制文件
2.etc 目录下最主要的是的配置项文件,尤其是进程的一些启动参数
3.log 目录下是进程运行日志,通常用于排查问题或反映系统运行的记录。
4.store 目录下存放的是存储引擎关系最紧密的日志和数据文件了。它们的目录通常会是一个软连接,用于单独挂载磁盘。
日志目录有 3 个,分别是 clog/ilog/slog。clog 是数据的 commit log 或 redo log。ilog 是 clog 的索引,暂时可以不用了解。slog 是存储引擎的 redo log,是元数据的日志。三种日志的文件都是一组以单调递增序号为名字的文件。
sstable 目录顾名思义,存放的就是我们的数据啦。OceanBase 和其他多文件数据库不同,使用统一的 2M 块来组织和管理数据和元数据。因此在 sstable 目录下,会看到一个名为 block_file 的大文件。
OB 的 WAL
在介绍启动恢复流程前,简单介绍下 OceanBase 的 WAL 机制。WAL 机制的原理就不重复展开了。在 OceanBase 里,元数据和数据的 WAL 日志是分开的,即上一节在目录结构下看到的 slog 和 clog。
slog 是单机引擎日志,当在节点上创建修改或是销毁分区、生成新 sstable、移除旧 sstable 等元数据结构修改发生时,都会先写 slog,而后修改内存中的元数据。后台定期会将分区和 sstable 的元数据以快照的形式写在 2M 块上,也就是 slog 的 checkpoint 机制。
clog 是数据的 redo log。当有数据修改发生时,请求会到达 leader 副本所在节点,leader 会通过 paxos 协议先将日志同步写到其他 follower 的副本节点上。当有多数派节点的日志写盘成功后,数据修改成功,会再插入到内存中的 memory table 上。LSM Tree 架构下,当 memory table 到达阈值后,会触发冻结和转储,数据会以 sstable 的形式写在 block_file 的宏块内。而此时的 clog 回放位点会推进,类似于做了 checkpoint。
因为 clog 涉及了事务和 paxos 协议,需要在多个副本间协商和同步。而 slog 是单机引擎的元数据日志,不涉及多节点的同步和一致性问题。因此 clog 和 slog 在物理和实现上是分开的两套日志。
数据恢复流程解析
用一句话简单描述 OBServer 的启动恢复,就是要将 store 目录下的日志和数据一字不差的还原到内存中,将进程的状态恢复到宕机前的状态。在介绍具体的流程前,我们先了解下元数据和数据在磁盘上的组织格式。
快照组织格式
在内存中,observer 进程是以 partition-table store-sstable 这三层对象来管理数据的。因为一些历史原因,目前 partition 对象在代码中以ObPartitonGroup
来实现;table store 是分区内的 memory table 和 sstable 集合,代码实现在ObTableStore
。SSTable 则对应一组数据宏块(ObSSTable
类)。
前面我们提到 OceanBase 在磁盘上使用 2M 大小的宏块来存放元数据和数据。当触发元数据快照时,每个分区都会调用各自的serialize
接口,将序列化数据写到宏块内,这些块我们称之为 meta block。一个 meta block 只有 2M,不一定能存下所有分区的元数据。因此所有 meta block 都会以链表的形式串联起来,直到最后一个块,我们称之为入口块ObSuperBlockMetaEntry
。入口块最终会持久化在 block_file 的第 1 和第 2 个宏块上,这两个宏块我们称为 super block。super block 上还会记录一些其他信息,例如 slog 的起始回放位点等等。
因此,当 server 启动时,会先从 block_file 的第 1 和第 2 个 super block 中读出上一次快照的元数据入口块,接着从这些入口块中,逐个调用 partition、table store 和 sstable 的deserialize
接口,将对象恢复到内存中去。
启动流程
observer 进程的启动代码从 main 函数里一目了然,分为三个阶段:初始化、启动、运行。看过或熟悉 OB 代码的同学对于 init/start/wait 这三个接口不会陌生。最主要的几大组件都会有这三个接口,分别在上述的三个阶段中被调用。
每个组件的 start 流程就不展开讲了。数据和日志恢复的代码入口在ob_partition_service.cpp
文件的ObPartitionService::start()
方法内。主要流程参见下图,1)加载元数据的快照点,即将分区和 sstable 的信息还原进内存。2)接着,回放 slog,将分区和 sstable 的信息更新到最新状态。3)然后,从分区的元信息中获取 clog 的回放位点,开始回放 clog 日志生成 memory table。上述三步完成后,单机数据的恢复流程就告一段落了。
因此 OceanBase 利用 WAL 和快照机制相结合,保证了节点在宕机后,仍然能够从磁盘的持久化信息中心恢复出宕机前的状态,保证了数据的完整性。
代码参考
元数据快照和加载代码实现,可以参见ObServerCheckpointWriter
和ObServerCheckpointLogReader
类。
slog 的重启回放代码主要在ObStorageLogReplayer
类中。
clog 的重启回放代码相对会复杂一些,有兴趣的同学可以挖一下ObLogScanRunnable
这个类。
slog 的读写库参见ObStorageLogReader
和ObStorageLogWriter
。
clog 的读写库参见ObLogDirectReader
和ObClogWriter
。
今天我们随着 OBServer 的启动流程,探寻了 OB 的 WAL 和快照机制,了解了存储引擎内部多个层次对象,以及它们是如何协同工作保证数据的完整性。过程中,还有许多点并没有展开去讲,其中有不少有趣之处可再细细介绍。欢迎你也加入 OceanBase,探索数据库的乐趣,一起做最先进的分布式数据库!
最后的最后:如果您有任何疑问,可以通过以下方式与我们进行交流:
微信群:扫码添加小助手,将拉你进群哟~
钉钉群:33254054
今日之星,明日之星都不如你留下的星星(⭐️️)
我们想让 Github 上优质的开源项目被更多人看到。
文档都是我们精心整理。如果有帮助的话求个 star(◕ᴗ◕✿),鼓励鼓励我们哟!
也欢迎大家给我们提 issue,请点击 这里。运营小姐姐在此跪谢️️ ❥(^_-)
欢迎大家一起参与社区贡献,指南请参考看 这里
社区答疑:请点击 这里
版权声明: 本文为 InfoQ 作者【OceanBase 开源社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/4d75e4cd3e97570cd081d209d】。未经作者许可,禁止转载。
评论