1. 程式人生 > >2.0 解析系列 | OceanBase 2.0 之 Flashback功能

2.0 解析系列 | OceanBase 2.0 之 Flashback功能

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

____2018_10_30

前言

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

常見資料庫故障

分類系統故障

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

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

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

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

2_0_6_2

介質故障

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

應對方案:針對介質故障導致的資料不一致問題,OceanBase會做兩方面的校驗。由於OceanBase是一個分散式資料庫,同一份資料會有多個副本,大版本全量合併時會做多副本的一致性校驗,每個SSTable內部會拆分成2MB大小巨集塊,每個巨集塊會計算Checksum。
當發現不一致時自動進行異常副本的替換。另一方面主表和索引表的資料同樣會做一致性校驗,保障資料在主表和索引表之間的一致性。出於對資料正確性的敬畏,資料校驗是OceanBase內部對自己的一道防火牆。

2_0_6_3

使用者誤操作

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

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

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

SQL Server 之 Database Snapshot

2_0_6_4

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中儲存邏輯結構如下:

2_0_6_5

說明:Han--> 4:s:2000000 表示4號事務修改行主鍵Han對應行的欄位s值為2000000
MemTable在記憶體中維護了轉儲之後到最新時點的事務歷史,將歷史事務針對該行的操作按照事務提交時間組織成行操作鏈,新事務提交時會往行操作鏈尾部追加新的行操作。如果行操作鏈儲存的歷史事務過多,將影響讀取效能,此時需要觸發Compaction操作,融合這些歷史事務並生成新的行操作鏈。但不會刪除老的行操作鏈。因此Flashback Query只需要順著記憶體中的反向指標往前回溯即可讀取任一時點歷史快照,根據Flashback Query閃回的位點分兩種情況分析:

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

2_0_6_6

  • 閃回到基線之後轉儲之前的位點
    需要合併基線+多版本轉儲對應閃回位點快照

2_0_6_7

回收站機制——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,線上誤刪資料庫再也不需要跑路了。