OB君:本文是 「OceanBase 2.0 技術解析系列」 的第六篇文章。今天我們來聊聊數據的持續可用,說說2.0中大家都很關心的「Flashback」閃回功能。更多精彩歡迎關注OceanBase公眾號持續訂閱本系列內容!

前言

資料庫產品作為信息系統的重要組成部分,除了要高效的處理用戶請求,還需要保證在各種異常情況下故障業務7*24的持續可用和數據的零丟失,本文的主要目的是總結和回顧一下傳統資料庫的常見故障,並介紹一下OceanBase作為分散式資料庫在應對常見故障時的應對措施。

常見資料庫故障

分類系統故障

系統故障指資料庫在運行過程中,由於硬體故障、資料庫軟體或操作系統的漏洞、突然停電等情況,導致系統異常,所有故障機器上正在運行的事務以非正常方式終止。

不同於傳統資料庫的單點故障所導致的系統可用性問題,OceanBase作為分散式資料庫為保證可用性提供了多種級別的容災部署方案。針對機房級別容災能力提供了同城三機房或兩地三中心的部署方案,同時針對城市級別容災能力提供了三地五中心部署方案。

今年的雲棲大會演示的網商銀行三地五中心方案,模擬杭州城市級故障,26秒即完成容災切換即體現了OceanBase針對城市級別故障的自愈能力。

同時針對極小概率的多數派故障,OceanBase和傳統資料庫一樣提供全量+增量的備份恢復機制,當出現資料庫異常故障時可以使用離線備份恢復到全量備份到當前時間區間的任一時間點。為保障已提交事務數據不丟失,OceanBase採用和傳統資料庫一樣的WAL(Write-Ahead Logging)方案,通過多數派先持久化事務日誌的方式,保證提交事務不丟失。

介質故障

介質故障也稱為硬故障,主要指資料庫在運行過程中,由於磁碟損壞、強磁干擾、天災人禍等情況,使得資料庫中的數據部分錯誤或數據丟失的一類故障。

應對方案:針對介質故障導致的數據不一致問題,OceanBase會做兩方面的校驗。由於OceanBase是一個分散式資料庫,同一份數據會有多個副本,大版本全量合併時會做多副本的一致性校驗,每個SSTable內部會拆分成2MB大小宏塊,每個宏塊會計算Checksum。

當發現不一致時自動進行異常副本的替換。另一方面主表和索引表的數據同樣會做一致性校驗,保障數據在主表和索引表之間的一致性。出於對數據正確性的敬畏,數據校驗是OceanBase內部對自己的一道防火牆。

用戶誤操作

常見錯誤包括誤連線上庫後drop業務表, delete操作由於where條件缺失導致誤刪業務數據。

應對方案:OceanBase通過多副本機制保證單點故障不影響業務,但僅有以上機制無法防範用戶的誤操作。常見的誤刪Database和Table方式,可以通過OceanBase的回收站機制實現恢復操作,而對於delete等dml方式的誤操作,OceanBase可以通過資料庫Flashback Query方式獲取刪除前快照實現誤刪數據恢復。下面會專門介紹傳統數據和OceanBase應對用戶誤操作所做的工作。

主流資料庫如何應對用戶誤操作

SQL Server 之 Database Snapshot

SQL Server通過DatabaseSnapshot機制實現快照查詢,原理是首先在Database級別創建Snapshot,存儲粒度為data-page級別,當Database快照對應的data-page第一次出現修改時,會將對應的前鏡像存儲於獨立的sparse file中,當快照查詢涉及到沒有修改的data-page直接復用原始page即可。

MySQL 時間點恢復

MySQL沒有單獨機制存儲數據塊的前鏡像,沒有實現類似SQL Server的快照功能。 針對用戶誤操作只能通過資料庫備份加上Binlog重放恢復到單一時間點,因此消耗的時間會比較久。有一些第三方工具比如binlog2sql , 可以通過設置Mysql資料庫的binlog_format值為row,並且binlog_row_image參數設置為full,可以通過解析誤Delete時間點的Binlog日誌生成回滾SQL,在生產庫中回放回滾SQL來實現資料庫誤操作恢復。

還有一種做法是通過備庫延遲應用Binlog日誌實現,這其實就是變相的使用離線備份加Binlog重放恢復,但可以節省全量備份恢復的時間。歸根到底在資料庫原生不存儲數據前鏡像的條件下只能通過備份加Binlog重放恢復用戶數據。

Oracle Flashback 機制

Oracle作為功能最為完善的商業關係型資料庫產品,提供了多種粒度的資料庫閃回功能。

Flashback Query,FlashbackTable,Flashback Transaction Query和Flashback Versions Query都是通過直接從UNDO中讀取數據前鏡像構造歷史快照,因為UNDO段是循環使用的,只要事務提交,之前的UNDO信息就可能被覆蓋,從而導致閃回出現快照過舊的報錯。

Flashback Drop是通過內部將原始Database或者Table重命名,並沒有物理刪除。Flashback Database和FlashbackData Archive通過專有的數據前鏡像來實現回滾操作。

整個Flashback家族中比較常用的功能為Flashback Query,Flashback Table和 Flashback Drop 。其中Flashback Table和Flashback Query 用於誤Delete數據恢復, Flashback Drop 主要用於誤Drop表的恢復。Flashback Database可能影響業務和丟失數據,一般只會在業務備庫上開啟,線上庫很少使用。

OceanBase Flashback 功能介紹

OceanBase閃回功能和語法上整體上保持與Oracle兼容,但提供傳統數據缺失的分散式容災及多活能力。OceanBase 1.4版本已實現Table和Database級別的FlashbackDrop功能,在2.0版本實現Flashback Query功能,額外實現了Oracle缺失的Truncate Table的閃回功能。因為OceanBase和Oracle在設計思想方面的不同,故實現方式上有本質的區別,下文具體介紹OceanBase的Flashback原理。

Flashback Query

OceanBase的閃回依賴於大版本合併的基線數據,和每次多版本的轉儲數據及內存MemTable中的所有事務修改記錄,可閃回時間範圍類似Oracle通過設置undo_retention最早可恢復時間,OceanBase會強制保留最早恢復時間點前一個大版本基線數據及後續所有的多版本轉儲SSTable。先簡單介紹使用OceanBase Flashback Query的使用用例。

mysql> create table flash_query_table (id int);
Query OK, 0 rows affected (0.17 sec)

mysql> insert into flash_query_table(id) values (1),(2),(3);
Query OK, 3 rows affected (0.05 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> select now(),* from flash_query_table;

+---------------------+------+
| now() | id |
+---------------------+------+
| 2018-10-09 17:01:39 | 1 |
| 2018-10-09 17:01:39 | 2 |
| 2018-10-09 17:01:39 | 3 |
+---------------------+------+
3 rows in set (0.03 sec)

mysql> delete from flash_query_table where id<2;
Query OK, 1 row affected (0.04 sec)

mysql> select now(),* from flash_query_table;
+---------------------+------+
| now() | id |
+---------------------+------+
| 2018-10-09 17:01:56 | 2 |
| 2018-10-09 17:01:56 | 3 |
+---------------------+------+
2 rows in set (0.02 sec)

mysql> select now(),* from flash_query_table
as of timestamp to_timestamp(2018-10-09 17:01:40,
yyyy-mm-dd hh24:mi:ss);

+---------------------+------+
| now() | id |
+---------------------+------+
| 2018-10-09 17:02:01 | 1 |
| 2018-10-09 17:02:01 | 2 |
| 2018-10-09 17:02:01 | 3 |
+---------------------+------+
3 rows in set (0.03 sec)

Flashback Query實現原理

OceanBase採用基線+增量的存儲方式,內存中保存最新的行數據修改歷史及對應的事務時間戳。同時當內存寫滿時會觸發轉儲或者合併,轉儲的數據會保留上一次基線數據到當前轉儲時間點和每個數據行的所有版本事務修改。MemTable同樣會保留最新的事務多版本修改。

抽象下MemTable中存儲邏輯結構如下:

說明:Han--> 4:s:2000000 表示4號事務修改行主鍵Han對應行的欄位s值為2000000

MemTable在內存中維護了轉儲之後到最新時點的事務歷史,將歷史事務針對該行的操作按照事務提交時間組織成行操作鏈,新事務提交時會往行操作鏈尾部追加新的行操作。如果行操作鏈保存的歷史事務過多,將影響讀取性能,此時需要觸發Compaction操作,融合這些歷史事務並生成新的行操作鏈。但不會刪除老的行操作鏈。因此Flashback Query只需要順著內存中的反向指針往前回溯即可讀取任一時點歷史快照,根據Flashback Query閃回的位點分兩種情況分析:

  • 閃回到轉儲之後的位點

需要合併基線+轉儲多版本+MemTable閃回位點對應快照

  • 閃回到基線之後轉儲之前的位點

需要合併基線+多版本轉儲對應閃回位點快照

回收站機制——flashback drop table / database,truncate table

OceanBase實現了回收站機制,從而防止用戶誤 drop table/database 的時候能快速恢復表數據。通過全局系統變數recyclebin 變數控制回收站功能的打開和關閉,on為打開(默認), off 為關閉。

索引單獨drop進回收站比較特殊,當用戶刪除唯一索引後,對主表繼續插入數據時,由於缺少唯一性約束而導致當索引從回收站Flashback時,會出現唯一性衝突。針對此場景OceanBase替代方案為使用alter index invisible/visible, 設置索引在SQL層對用戶不可見,存儲層不受影響,唯一索引仍然做數據的唯一性檢查。不支持drop索引進回收站。索引數據依賴主表,單獨drop索引後通過重建恢復更方便。

OceanBase針對truncatetable特殊設計為truncate table=drop table+ create table,當開啟回收站的情況下和drop table機制類似,但Flashback時需要採用rename to子句保證表名不衝突。而Oracle執行truncate table是不會保存undo信息,也不會挪進回收站,只能通過資料庫備份恢復,此為OceanBase的一個設計優化點。

//還原回收站中的DATABASE
FLASHBACK DATABASE db_name TO BEFORE DROP [RENAME TO db_name];

//還原回收站中的TABLE, 注意這裡db_name 可以將表flash到一個新的庫下
FLASHBACK table_name TO BEFORE DROP [RENAME TO db_name.table_name];

//租戶級別打開回收站機制
set global recyclebin=on

MySQL [test]> create table tb_drop(id int primary key,name varchar(5));
Query OK, 0 rows affected (0.07 sec)

MySQL [test]> insert into tb_drop values(1,a),(3,c);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0

MySQL [test]> drop table tb_drop;
Query OK, 0 rows affected (0.02 sec)

MySQL [test]> select * from tb_drop;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 3 | c |
+----+------+
2 rows in set (0.00 sec)

MySQL [test]> select gmt_create,
tenant_id,object_name,original_name
from oceanbase.__all_recyclebin
where ORIGINAL_NAME=tb_drop;
+-----------------+-----------+------------------------+---------------+
| gmt_create | tenant_id | object_name | original_name |
+-----------------+-----------+------------------------+---------------+
| 2018-10-16 14:31:01.102840 | 1 | __recycle_$_10023_1_1539671461102752 | tb_drop |
+-----------------+-----------+------------------------+---------------+
1 row in set (0.03 sec)

MySQL [test]> flashback table __recycle_$_10023_1_1539671461102752 to before drop;
Query OK, 0 rows affected (0.02 sec)
MySQL [test]> select * from tb_drop ;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 3 | c |
+----+------+

2 rows in set (0.00 sec)

實現原理如下

在開啟回收站功能後,在原始的「DROP操作」的基礎上會加一層包裝。DROP涉及的對象會進入回收站,主要操作為修改對象的schema信息及在__all_recyclebin新增相關記錄。

(1)被drop的表是系統表,那麼直接刪除,不進入回收站,否則進入步驟2;

(2)把被drop對象的schema信息中的OBJECT_NAME 改成__recycle$_gen_id ,其中gen_id的生成規則如下:

GEN_ID = cluster_id + tenant_id + schema_version 的方式組合

例如:__recycle_$_10023_1004_1539604687557424

(3)在__all_recyclebin表中插入被drop對象的信息。

還原操作涉及到兩點,分別是對象的schema信息修改和刪除內部表 __all_recyclebin 中的記錄,具體步驟如下:

(1)檢查用戶是否具備相應的許可權;

(2)從schema信息中OBJECT_NAME裡面提取出原有對象的相關信息,修改對象的schema信息,主要是修改對象的名稱,如果使用了RENAME TO語句指定了NEW_OBJECT_NAME,那麼把名稱改成NEW_OBJECT_NAME,否則改成ORIGINAL_NAME;

(3)如果發現當前TABLE所在的DATABASE已經被DROP掉,則FLASHBACK失敗。如果成功則刪除__all_recyclebin中相關的行記錄。

總結OceanBase通過分散式多副本機制實現單點及少數派故障業務無感知,對於介質故障OceanBase通過多層Checksum機制保證數據的一致性,並自動實現數據修正。

對用戶疏忽導致的誤操作,OceanBase可以通過Flashback的輕量級方式實現數據快速恢復,或者通過資料庫離線備份實現恢復到故障發生之前的位點。擁有OceanBase,線上誤刪資料庫再也不需要跑路了。

2.0解析系列文章

  • 一文詳解新一代OceanBase雲平台(1)
  • 如絲般順滑!一線運維人員談如何實現資料庫的平滑在線升級(2)
  • OceanBase的重要基礎設施 —— DBReplay(3)
  • OceanBase負載均衡的魅力(4)
  • 如何在分散式架構下完美實現「全局數據一致性」?(5)

推薦閱讀:

相关文章