OB君:本文是 「 OceanBase 2.0 技術解析系列」 的第六篇文章。今天咱們來聊聊數據的持續可用,說說2.0中你們都很關心的「Flashback」閃回功能。更多精彩歡迎關注OceanBase公衆號持續訂閱本系列內容!
數據庫產品做爲信息系統的重要組成部分,除了要高效的處理用戶請求,還須要保證在各類異常狀況下故障業務7*24的持續可用和數據的零丟失,本文的主要目的是總結和回顧一下傳統數據庫的常見故障,並介紹一下OceanBase做爲分佈式數據庫在應對常見故障時的應對措施。mysql
系統故障指數據庫在運行過程當中,因爲硬件故障、數據庫軟件或操做系統的漏洞、忽然停電等狀況,致使系統異常,全部故障機器上正在運行的事務以非正常方式終止。sql
不一樣於傳統數據庫的單點故障所致使的系統可用性問題,OceanBase做爲分佈式數據庫爲保證可用性提供了多種級別的容災部署方案。針對機房級別容災能力提供了同城三機房或兩地三中心的部署方案,同時針對城市級別容災能力提供了三地五中心部署方案。數據庫
今年的雲棲大會演示的網商銀行三地五中心方案,模擬杭州城市級故障,26秒即完成容災切換即體現了OceanBase針對城市級別故障的自愈能力。bash
同時針對極小機率的多數派故障,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經過DatabaseSnapshot機制實現快照查詢,原理是首先在Database級別建立Snapshot,存儲粒度爲data-page級別,當Database快照對應的data-page第一次出現修改時,會將對應的前鏡像存儲於獨立的sparse file中,當快照查詢涉及到沒有修改的data-page直接複用原始page便可。性能
MySQL沒有單獨機制存儲數據塊的前鏡像,沒有實現相似SQL Server的快照功能。 針對用戶誤操做只能經過數據庫備份加上Binlog重放恢復到單一時間點,所以消耗的時間會比較久。有一些第三方工具好比binlog2sql , 能夠經過設置Mysql數據庫的binlog_format值爲row,而且binlog_row_image參數設置爲full,能夠經過解析誤Delete時間點的Binlog日誌生成回滾SQL,在生產庫中回放回滾SQL來實現數據庫誤操做恢復。
還有一種作法是經過備庫延遲應用Binlog日誌實現,這其實就是變相的使用離線備份加Binlog重放恢復,但能夠節省全量備份恢復的時間。歸根到底在數據庫原生不存儲數據前鏡像的條件下只能經過備份加Binlog重放恢復用戶數據。
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閃回功能和語法上總體上保持與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,線上誤刪數據庫不再須要跑路了。