OBServer啟動恢復解析

OceanBase開源社群發表於2021-10-09

作者:令川,一個在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啟動恢復解析


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啟動恢復解析


程式碼參考

後設資料快照和載入程式碼實現,可以參見 ObServerCheckpointWriterObServerCheckpointLogReader類。

slog的重啟回放程式碼主要在 ObStorageLogReplayer類中。

clog的重啟回放程式碼相對會複雜一些,有興趣的同學可以挖一下 ObLogScanRunnable這個類。

slog的讀寫庫參見 ObStorageLogReaderObStorageLogWriter

clog的讀寫庫參見 ObLogDirectReaderObClogWriter


今天我們隨著OBServer的啟動流程,探尋了OB的WAL和快照機制,瞭解了儲存引擎內部多個層次物件,以及它們是如何協同工作保證資料的完整性。過程中,還有許多點並沒有展開去講,其中有不少有趣之處可再細細介紹。歡迎你也加入OceanBase,探索資料庫的樂趣,一起做最先進的分散式資料庫!

最後的最後:如果您有任何疑問,可以通過以下方式與我們進行交流:

微信群:掃碼新增小助手,將拉你進群喲~



釘釘群:33254054



今日之星,明日之星都不如你留下的星星(⭐️️)

我們想讓  Github 上優質的開源專案被更多人看到。

文件都是我們精心整理。如果有幫助的話 求個star(◕ᴗ◕✿),鼓勵鼓勵我們喲!

也歡迎大家給我們   issue,請點選  這裡。運營小姐姐在此跪謝️️ ❥(^_-)

歡迎大家一起參與 社群貢獻,指南請參考看  這裡

社群答疑:請點選  這裡


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70005215/viewspace-2795140/,如需轉載,請註明出處,否則將追究法律責任。

相關文章