TiDB Binlog的增量恢復

語言: CN / TW / HK

本文作者為 運維保障中心-王寧

1.TiDB Binlog介紹

2. TiDB Binlog架構與原理

3.叢集擴容Drainer

3.1 編輯drainer的配置檔案

3.2 執行擴容命令

3.3 檢查叢集狀態

3.4 檢查binlog目錄下是否有binlog檔案

4.Reparo解析TiDB binlog

4.1 安裝Reparo

4.2 編輯reparo配置檔案

4.3 啟動reparo

4.4 檢視解析文字

5.實驗利用全備+Binlog恢復資料

5.1 獲取備份中的TSO

5.2 到備用環境進行恢復

5.3 編輯reparo配置檔案

5.4 啟動reparo

5.5 找到恢復TSO點

5.6 在備用Tidb環境編輯reparo source配置檔案

5.7 啟動reparo source

背景:作為DBA最關心的就是資料的安全,在最初使用TiDB的時候,就考慮到萬一資料有誤操作或者其他危險狀況,我們應該怎麼來恢復資料,保障TiDB的資料像MySQL資料庫一樣可以恢復到任意時間點。TiDB的Binlog就是一個類似MySQL Binlog的工具,既可以進行資料同步,又可以儲存成檔案。大部分DBA可能都使用過它的資料同步功能,但是TiDB的binlog儲存成檔案這樣才能保障我們的資料安全。這篇文章主要涉及的就是將TiDB的binlog儲存下來,並且使用TiDB的Reparo工具進行解析及恢復資料。

0 1

TiDB Binlog介紹

TiDB Binlog工具可以收集TiDB資料庫的日誌binlog,並且提供資料同步和準實時備份的功能。

(一)TiDB Binlog支援以下功能場景:

資料同步:同步TiDB叢集資料到其他資料庫

實時備份和恢復:備份TiDB叢集資料,同時可以用於 TiDB 叢集故障時恢復。

(二)TiDB資料庫的Binlog格式:

1.與MySQL Binlog的Row格式類似,按照事務提交的時間記錄的,只記錄增刪改,只記錄提交的事務。

2.以每一行資料的變更為最小單位進行記錄。

3.只有被提交的事務才會被記錄,且記錄的是完整事務。

(1)在Binlog中會記錄主鍵和開始的時間戳。

(2)在Binlog中會記錄提交的時間戳。

0 2

TiDB Binlog架構與原理

TiDB Binlog 叢集由 Pump 和 Drainer 兩個元件組成。一個 Pump叢集中有若干個 Pump 節點。TiDB 例項連線到各個 Pump節點併發送 binlog 資料到 Pump 節點。Pump叢集連線到 Drainer節點,Drainer將接收到的更新資料轉換到某個特定下游(例如 Kafka、另一個 TiDB 叢集或 MySQL 或 MariaDB Server或者是直接儲存日誌)指定的正確格式。

Pump:Pump用於實時記錄 TiDB 產生的 Binlog,並將 Binlog 按照事務的提交時間進行排序,再提供給 Drainer 進行消費。Pump 的叢集架構能確保 TiDB 或 Pump 叢集中有新的例項加入或退出時更新資料不會丟失。

Drainer:Drainer 從各個 Pump 中收集 Binlog 進行歸併,再將 Binlog 轉化成 SQL或者指定格式的資料,最終同步到下游。

03

叢集擴容Drainer節點儲存日誌

(一)編輯drainer的配置檔案

如果 TiDB Binlog 用於增量恢復,可以設定配置項 db-type="file",Drainer 會將 binlog 轉化為指定的 proto buffer

的資料,再寫入到本地檔案中。

#編輯擴容的配置檔案
cd /home/tidb/scale_task
vim scale_out_drainer.yaml
#儲存為本地檔案


drainer_servers:
- host: 10.***.***.8
# drainer meta data directory path
data_dir: "/data1/tidb-data/drainer-8249"
deploy_dir: "/data1/tidb-deploy/drainer-8249"
log_dir: "/data1/tidb-deploy/drainer-8249/log"
config:
syncer.db-type: "file"
# directory to save binlog file,
# default same as data-dir(save checkpoint file) if this is not configured.
# syncer.to.dir: "/path/to/save/binlog"
syncer.to.dir: "/data1/tidb-data/drainer-8249/binlog"


#擴容drainer節點之前,需要檢查如下配置是否新增開啟
tiup cluster edit-config <cluster-name>


server_configs:
tidb:
binlog.enable: true
binlog.ignore-error: true


pump_servers:
- host: 10.***.***.1
ssh_port: 22
port: 8250
deploy_dir: /data1/tidb-deploy/pump-8249
data_dir: /data1/tidb-data/pump-8249
log_dir: /data1/tidb-deploy/pump-8249/log
config:
gc: 14
arch: amd64
os: linux

(二)執行擴容命令

tiup cluster scale-out <cluster-name> scale_out_drainer.yaml --user tidb -p

(三)檢查叢集狀態

tiup cluster display <cluster-name>

(四)檢查binlog目錄下是否有binlog檔案

$$ cd /data1/tidb-data/drainer-8249/binlog
$ ll -h
總用量 525M
-rw-------. 1 tidb tidb 513M 7月 13 15:46 binlog-0000000000000000-20220713110333
-rw-------. 1 tidb tidb 13M 7月 13 15:53 binlog-0000000000000001-20220713154625

04

Reparo解析TiDB binlog

如果 TiDB Binlog 用於增量恢復,可以設定配置項 db-type="file",Drainer 會將 binlog 轉化為指定的 proto buffer格式的資料,再寫入到本地檔案中。這樣就可以使用 Reparo 恢復增量資料。

Reparo 是 TiDB Binlog 的一個配套工具,用於增量的恢復。使用 TiDB Binlog 中的 Drainer 將 binlog 按照 protobuf格式輸出到檔案,通過這種方式來備份增量資料。當需要恢復增量資料時,使用 Reparo 解析檔案中的 binlog,並將其應用到 TiDB/MySQL 中。

(一)安裝Reparo

#在drainer所在的伺服器上安裝
su - tidb
wget https://download.pingcap.org/tidb-binlog-cluster-latest-linux-amd64.tar.gz
tar -xvf tidb-binlog-cluster-latest-linux-amd64.tar.gz
mv tidb-binlog-cluster-latest-linux-amd64 tidb-binlog-cluster
cd /home/tidb/tidb-binlog-cluster/bin
$ ll -h
總用量 204M
-rwxr-xr-x 1 tidb tidb 47M 3月 3 2020 arbiter
-rwxr-xr-x 1 tidb tidb 23M 3月 3 2020 binlogctl
-rwxr-xr-x 1 tidb tidb 50M 3月 3 2020 drainer
-rwxr-xr-x 1 tidb tidb 41M 3月 3 2020 pump
-rwxr-xr-x 1 tidb tidb 44M 3月 3 2020 reparo

(二)編輯reparo配置檔案

由於dest-type = "print"這個配置,此配置檔案只是將binlog解析成文字檔案,方便檢視。

cd /home/tidb
vim reparo.toml


#Drainer 輸出的 protobuf 格式 binlog 檔案的儲存路徑。
data-dir = "/data1/tidb-data/drainer-8249/binlog"


#日誌輸出資訊等級設定:debug, info, warn, error, fatal (預設值:info)。
log-level = "info"


#使用 start-datetime 和 stop-datetime 來選擇恢復指定時間範圍內的 binlog,
#格式為 “2006-01-02 15:04:05”。
start-datetime = "2022-07-27 16:42:00"
stop-datetime = "2022-07-27 16:51:00"


#start-tso、stop-tso 分別對應 start-datetime 和 stop-datetime,
#也是用於恢復指定時間範圍內的 binlog,用 tso 的值來設定。
#如果已經設定了 start-datetime 和 stop-datetime,
#就不需要再設定 start-tso 和 stop-tso。
#在從全量或者上次增量位置繼續同步時,start-tso 應當指定為全量 tso + 1
#或者上次增量的 stop-tso + 1
#start-tso = 0
#stop-tso = 0


#下游服務型別。 取值為 print, mysql(預設值:print)。
#當值為 print 時,只做解析列印到標準輸出,不執行 SQL;
#如果為 mysql,則需要在 [dest-db] 中配置 host、port、user、password 等資訊。
dest-type = "print"
#dest-type = "mysql"


#輸出到下游資料庫一個事務的 SQL 語句數量(預設 20)。
#txn-batch = 20


#同步下游的併發數,該值設定越高同步的吞吐效能越好(預設 16)。
#worker-count = 16


#安全模式配置。取值為 true 或 false(預設值:false)。
#當值為 true 時,Reparo 會將 update 語句拆分為 delete + replace 語句。
safe-mode = false


# replicate-do-db 和 replicate-do-table 用於指定恢復的庫和表,
# replicate-do-db 的優先順序高於 replicate-do-table。
# 支援使用正則表示式來配置,需要以 '~' 開始宣告使用正則表示式。
# 注:replicate-do-db 和 replicate-do-table 使用方式與 Drainer 的使用方式一致。
# replicate-do-db = ["~^b.*","s1"]
# [[replicate-do-table]]
# db-name ="test"
# tbl-name = "log"
# [[replicate-do-table]]
# db-name ="test"
# tbl-name = "~^a.*"


# 如果 dest-type 設定為 mysql, 需要配置 dest-db。
# [dest-db]
# host = "127.0.0.1"
# port = 3309
# user = "****"
# password = "*****"

(三)啟動reparo

#這樣啟動,內容會列印到binlog_parse.log這個日誌中
reparo -config /home/tidb/reparo.toml >/home/tidb/binlog_parse.log

(四)檢視解析文字

DDL及增刪改的解析文字如下:

[2022/07/27 16:53:55.748 +08:00] [INFO] [config.go:153] ["Parsed start TSO"] [ts=434873649070080000]

[2022/07/27 16:53:55.749 +08:00] [INFO] [config.go:160] ["Parsed stop TSO"] [ts=434873774899200000]

[2022/07/27 16:53:55.749 +08:00] [INFO] [version.go:50] ["Welcome to Reparo"] ["Release Version"=v4.0.0-beta.1-2-g20397869] ["Git Commit Hash"=20397869d35a5bc8a130f615ceb669322fa8600e] ["Build TS"="2020-03-02 09:50:53"] ["Go Version"=go1.13] ["Go OS/Arch"=linux/amd64]

[2022/07/27 16:53:55.768 +08:00] [INFO] [reparo.go:38] ["New Reparo"] [config="{\"data-dir\":\"/data1/tidb-data/drainer-8249/binlog\",\"start-datetime\":\"2022-07-27 16:42:00\",\"stop-datetime\":\"2022-07-27 16:50:00\",\"start-tso\":434873649070080000,\"stop-tso\":434873774899200000,\"txn-batch\":20,\"worker-count\":16,\"dest-type\":\"print\",\"dest-db\":null,\"replicate-do-table\":null,\"replicate-do-db\":null,\"replicate-ignore-table\":null,\"replicate-ignore-db\":null,\"log-file\":\"\",\"log-level\":\"info\",\"safe-mode\":false}"]

[2022/07/27 16:53:56.247 +08:00] [INFO] [file.go:77] ["after filter files"] [files="[/mysqldata/tidb-data/drainer-8249/binlog/binlog-0000000000000011-20220525054234]"] ["start tso"=434873649070080000] ["stop tso"=434873774899200000]

DDL query : use `wangn_test`; CREATE TABLE `t_random_t` (

`id` bigint(20) NOT NULL  COMMENT 'id',

`code` varchar(30) NOT NULL,

`create_time` datetime DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

[2022/07/27 16:54:14.207 +08:00] [INFO] [reparo.go:83] ["sync binlog success"] [ts=434873689486917637] [datetime=2022/07/27 16:44:34.178 +08:00]

schema: wangn_test; table: t_random_t; type: Insert

id(bigint): 5577006791947779410

code(varchar): et impedit voluptatem et in fa

create_time(datetime): 2022-05-08 08:08:02

[2022/07/27 16:54:14.207 +08:00] [INFO] [reparo.go:83] ["sync binlog success"] [ts=434873731705208833] [datetime=2022/07/27 16:47:15.228 +08:00]

schema: wangn_test; table: t_random_t; type: Update

id(bigint): 1732098207891296284 => 1732098207891296284

code(varchar): consequuntur quasi error volup => error volup

create_time(datetime): 2022-04-18 18:06:04 => 2022-04-18 18:06:04

[2022/07/27 16:54:14.207 +08:00] [INFO] [reparo.go:83] ["sync binlog success"] [ts=434873750474719235] [datetime=2022/07/27 16:48:26.828 +08:00]

schema: wangn_test; table: t_random_t; type: Delete

id(bigint): 4045349876957839238

code(varchar): vel ut quia enim ut qui.

create_time(datetime): 2021-07-30 16:04:26

[2022/07/27 17:19:10.453 +08:00] [INFO] [reparo.go:83] ["sync binlog success"] [ts=434873755219525633] [datetime=2022/07/27 16:48:44.928 +08:00]

DDL query : use `wangn_test`; alter table t_random_t add column address varchar(30) NOT NULL;

[2022/07/27 17:19:10.455 +08:00] [INFO] [reparo.go:83] ["sync binlog success"] [ts=434873779376095235] [datetime=2022/07/27 16:50:17.078 +08:00]

[2022/07/27 17:19:10.455 +08:00] [INFO] [read.go:123] ["read file end"] [file=/data1/ti db-data/drainer-8249/bi nlog/binlog-0000000000000011-20220525054234]

05

實驗-利用全備+Binlog恢復資料

實驗背景:凌晨都會例行備份。一天的業務增刪改。某張表因操作失誤被delete掉了。需要恢復回來。

其實如果是MySQL資料庫的話,我們可以利用MySQL的binlog,使用工具,反向解析binlog,把delete語句解析成insert語句,但是目前TiDB的reparo這個工具並沒有這個功能。

在不考慮GC的情況下,我們只能用備份+TiDB的binlog進行恢復。

(一)獲取備份中的TSO

如果是br備份的話,從備份日誌中檢視

[BackupTS=433311088594911234]

或者可以使用 validate 指令獲取上一次備份的時間戳,示例如下:

br validate decode --field="end-version"  \
-s local:///bak/data1/wangn/tidb_test/7120519| tail -n1
Detail BR log in /tmp/br.log.2022-05-19T18.15.34+0800
433311088594911234

(二)到備用環境進行恢復

安全恢復單表資料,利用全備及br工具將單表資料恢復出來, 恢復的時候,目標叢集內不能有相同庫名的庫,否則會報錯。

#恢復單表wangn_test.tt
br restore table --pd "10.***.***.104:2379" --db "wangn_test" --table "tt" \
--ratelimit 128 --storage "local:///bak/data1/wangn/tidb_test/7120519" \
--log-file /tmp/restorefull.log

(三)編輯reparo配置檔案

這個是要檢視誤操作之前的最後一個tso的, 先解析binlog成文字 ,找到操作的tso時間點 需要開發提供誤刪除的大概時間,庫,表等資訊

vim reparo.toml


data-dir = "/data1/tidb-data/drainer-8249/binlog"
log-level = "info"
start-datetime = "2022-05-19 20:24:00"
stop-datetime = "2022-05-19 20:30:00"
dest-type = "print"
safe-mode = false
db-name ="wangn_test"
tbl-name = "tt"

(四)啟動reparo

reparo -config /home/tidb/reparo.toml  >/home/tidb/binlog_parse_0519.log

(五)找到恢復TSO點

less binlog_parse_0519.log


[2022/05/19 20:43:19.591 +08:00] [INFO] [reparo.go:83] ["sync binlog success"]
[ts=433314381739589634] [datetime=2022/05/19 20:26:27.178 +08:00]
schema: wangn_test; table: tt; type: Delete

從上面日誌中找到了Delete操作之前最後一個事務結束的時間點,ts=433314381739589634。

我們需要從全量或者上次增量位置繼續同步時,start-tso 應當指定為全量 tso + 1 或者上次增量的 stop-tso + 1,那麼現在我們就有了恢復的起始tso與結束tso。

起始tso:433311088594911235。即[BackupTS=433311088594911234+1]

結束tso:[ts=433314381739589634]

(六)在備用Tidb環境編輯reparo source配置檔案

因為binlog在生產環境的drainer/binlog下,我們的測試環境沒有這些binlog, 所以需要拷貝到共同的儲存中,許可權所屬是tidb使用者的,拷貝到/bak/data1/wangn/binlog下。

這個配置檔案是要把資料恢復到目標測試庫的配置檔案。

vim reparo_source.toml


# Drainer 輸出的 protobuf 格式 binlog 檔案的儲存路徑。
data-dir = "/bak/data1/wangn/binlog"


# 日誌輸出資訊等級設定:debug, info, warn, error, fatal (預設值:info)。
log-level = "info"


# 在從全量或者上次增量位置繼續同步時,start-tso 應當指定為全量 tso + 1
# 或者上次增量的 stop-tso + 1
start-tso = 433311088594911235
stop-tso = 433314381739589634


# 下游服務型別。 取值為 print, mysql(預設值:print)。
# 如果為 mysql,則需要在 [dest-db] 中配置 host、port、user、password 等資訊。
dest-type = "mysql"


# 安全模式配置。取值為 true 或 false(預設值:false)。
# 當值為 true 時,Reparo 會將 update 語句拆分為 delete + replace 語句。
safe-mode = false


# replicate-do-db 和 replicate-do-table 用於指定恢復的庫和表,
# replicate-do-db 的優先順序高於 replicate-do-table。
# 支援使用正則表示式來配置,需要以 '~' 開始宣告使用正則表示式。
# 注:replicate-do-db 和 replicate-do-table 使用方式與 Drainer 的使用方式一致。
# replicate-do-db = ["~^b.*","s1"]
[[replicate-do-table]]
db-name ="wangn_test"
tbl-name = "tt"


# 如果 dest-type 設定為 mysql, 需要配置 dest-db。
[dest-db]
host = "10.***.***.104"
port = 4000
user = "******"
password = "******"

(七)啟動reparo source

reparo -config /home/tidb/reparo_source.toml  >/home/tidb/binlog_parse_source.log

檢視資料已經恢復回來了。把測試環境中恢復的資料匯出來,匯入到生產環境中,就OK了!

參考文獻均來自PingCap官網:

https://docs.pingcap.com/zh/tidb/v5.3/tidb-binlog-overview

https://docs.pingcap.com/zh/tidb/v5.3/tidb-binlog-reparo

END