OBServer启动恢复解析

2024年 5月 7日 40.8k 0

作者:令川,一个在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_dir
├── bin
│   ├── ob_admin
│   ├── obproxy
│   └── observer
├── etc
│   ├── io_resource.conf
│   └── observer.config.bin
├── lib
│   ├── libmysqlclient.so.18
│   └── libstdc++.so.6
├── log
│   ├── election.log
│   ├── observer.log
│   └── rootservice.log
└── store
    ├── clog -> /data/1/clog
    │   └── 1
    ├── ilog -> /data/1/clog
    │   └── 1
    ├── slog -> /data/2/clog
    │   └── 1
    └── sstable -> /data/2/clog
        └── 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的起始回放位点等等。

OBServer启动恢复解析-1

struct ObSuperBlockMetaEntry {
  blocksstable::MacroBlockId macro_block_id_;  // first entry meta macro block id
};

struct ServerSuperBlockContent {int64_t create_timestamp_;  // create timestampint64_t modify_timestamp_;  // last modified timestampint64_t macro_block_size_;int64_t total_macro_block_count_;
  int64_t total_file_size_;

  common::ObLogCursor replay_start_point_;
  ObSuperBlockMetaEntry super_block_meta_;
  ObSuperBlockMetaEntry tenant_config_meta_;
};

struct ObServerSuperBlock {
  ObSuperBlockHeaderV2 header_;
  ServerSuperBlockContent content_;
};

因此,当server启动时,会先从block_file的第1和第2个super block中读出上一次快照的元数据入口块,接着从这些入口块中,逐个调用partition、table store和sstable的deserialize接口,将对象恢复到内存中去。

启动流程

observer进程的启动代码从main函数里一目了然,分为三个阶段:初始化、启动、运行。看过或熟悉OB代码的同学对于init/start/wait这三个接口不会陌生。最主要的几大组件都会有这三个接口,分别在上述的三个阶段中被调用。

ObServer& observer = ObServer::get_instance();
if (OB_FAIL(observer.init(opts, log_cfg))) {
    LOG_ERROR("observer init fail", K(ret));
} else if (OB_FAIL(observer.start())) {
    LOG_ERROR("observer start fail", K(ret));
} else if (OB_FAIL(observer.wait())) {
    LOG_ERROR("observer wait fail", K(ret));
}

每个组件的start流程就不展开讲了。数据和日志恢复的代码入口在ob_partition_service.cpp文件的ObPartitionService::start()方法内。主要流程参见下图,1)加载元数据的快照点,即将分区和sstable的信息还原进内存。2)接着,回放slog,将分区和sstable的信息更新到最新状态。3)然后,从分区的元信息中获取clog的回放位点,开始回放clog日志生成memory table。上述三步完成后,单机数据的恢复流程就告一段落了。

因此OceanBase利用WAL和快照机制相结合,保证了节点在宕机后,仍然能够从磁盘的持久化信息中心恢复出宕机前的状态,保证了数据的完整性。

OBServer启动恢复解析-2

代码参考

元数据快照和加载代码实现,可以参见ObServerCheckpointWriterObServerCheckpointLogReader类。

slog的重启回放代码主要在ObStorageLogReplayer类中。

clog的重启回放代码相对会复杂一些,有兴趣的同学可以挖一下ObLogScanRunnable这个类。

slog的读写库参见ObStorageLogReaderObStorageLogWriter

clog的读写库参见ObLogDirectReaderObClogWriter

今天我们随着OBServer的启动流程,探寻了OB的WAL和快照机制,了解了存储引擎内部多个层次对象,以及它们是如何协同工作保证数据的完整性。过程中,还有许多点并没有展开去讲,其中有不少有趣之处可再细细介绍。欢迎你也加入OceanBase,探索数据库的乐趣,一起做最先进的分布式数据库!

最后的最后:如果您有任何疑问,可以通过以下方式与我们进行交流:

微信群:扫码添加小助手,将拉你进群哟~

OBServer启动恢复解析-3

钉钉群:33254054

OBServer启动恢复解析-4

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论