TiDB Binlog用于收集TiDB的binlog并准实时的同步给下游数据库如TiDB、MySQL等,在功能上类似于MySQL的主从复制,可以实现数据准实时同步以及准实时的备份和恢复。本文简要介绍TiDB Binlog的架构及实现原理,并进行测试验证。
1、整体架构
TiDB Binlog 主要包括Pump和Drainer两个组件,以及binlogctl工具:
- Pump用于实时记录TiDB产生的binlog,并将binlog按照事务的提交时间进行排序,再提供给Drainer进行消费
- Drainer从各个Pump中收集binlog进行归并,再将binlog转化成SQL或者指定格式的数据,最终同步到下游
- binlogctl工具:TiDB binlog配套的运维工具,可以获取TiDB集群当前的TSO、查看修改Pump/Drainer状态、暂停/下线Pump/Drainer等
TiDB binlog主要有以下特性:
- 多个Pump形成一个集群,可以水平扩容,各个Pump可以均匀地承担业务的压力
- TiDB通过内置的Pump Client将binlog分发到各个Pump,即使有部分Pump出现故障也不影响TiDB的业务
- Pump内部实现了简单的kv来存储binlog,方便对binlog数据的管理
- Pump对binlog排序后提供给Drainer,因为Pump是可扩展的,能提高整体的同步性能
- Drainer只需要依次读取各个Pump的binlog进行归并排序,这样可以大大节省内存的使用,同时也更容易做内存控制
- Drainer支持relay log功能,通过relay log保证下游集群的一致性状态
1.1 TiDB写binlog
TiDB的事务使用的是two-phase-commit算法,一个事务的提交分为prewrite和commit提交。在TiDB实现中,TiDB在每个阶段会分别写一条binlog:prewrite binlog和commit binlog,以下简称为p-binlog和c-binlog,具体写入流程如下:
- Prepare阶段,TiDB会把Prewrite的数据发送到TiKV,同时并发写一条p-binlog到其中一个pump,两个操作全部成果后才会进入commit阶段
- Commit阶段写C-binlog是在TiKV提交事务后异步发送的,通知Pump事务是提交还是回滚状态。在提交事务的时候可以确定P-binlog已经保存成功了。
- 写binlog是事务延迟的影响
在Prepare阶段,TiDB会并发写P-binlog到Pump和Prewrite data到TiKV,如果写P-binlog到Pump的速度比写数据到TiKV快,则对延迟没有影响。在Commit阶段,由于是异步写C-binlog,对延迟也没有影响。一般而言,写入Pump比写入TiKV的速度更快。
- 写binlog失败
- 写P-binlog失败,那么交易不会commit,不会对系统有任何影响
- 写C-binlog失败,Pump会等待最多max transaction timeout的时间(这是一个TiDB/Pump的配置,默认为10分钟),然后向TiKV去查询transaction的提交状态来补全C-binlog,但是此时同步延迟也等于max transaction timeout。这种情况经常发生于TiDB进程重启或者挂掉的场景。
- 写P-binlog成功,但是Prewrite失败,那么也会和2类似
1.2 Pump Client
在Pump cluster中有多个Pump构成一个集群,共同承担写binlog的请求。Pump Client的工作主要是保证TiDB能够将写binlog的请求尽可能均匀分发到各个Pump,并需要及时的获取Pump的状态信息,识别不可用的Pump以及新加入的Pump信息。Pump的信息主要来自PD中保存的Pump状态信息,这些状态包括:online、pausing、paused、closing、offline。
Pump Client根据Pump上报到PD的信息以及写binlog请求的实际情况将Pump划分avaliable和unavailable两种状态,划分的策略如下:
- 初始化时从PD中获取所有Pump的信息,将状态为online的Pump加入到可用 Pump 列表中,其他 Pump 加入到非可用列表中。
- Pump每隔固定的时间会发送心跳到PD,并更新自己的状态。Pump Client监控PD中Pump上传的状态信息,及时更新内存中维护的Pump信息,如果状态由非online转换为online则将该Pump加入到可用Pump列表;反之加入到unavailable列表中。
- 对于每个Pump,在Pump client中都维护了一个变量ErrNum来记录该Pump写binlog 失败次数,当ErrNum超过一定的阈值,则判断该Pump不可用,如果写binlog成功,则 重置ErrNum。
- 定时发送探活请求到unavailable状态的Pump,如果返回成功,则把该Pump状态更新为avaliable
通过上面的措施,Pump Client可以及时地更新Pump集群信息,保证将binlog发送到可用的Pump中。
- Pump Client分发到不同Pump的路由策略
- Range:以轮询的方式按照顺序依次选取Pump发送binlog
- hash:对binlog的start_ts进行hash,然后选取hash值对应的Pump
- score:根据Pump上报的分数按照加权平均算法选取Pump发送binlog。分数是由节点的负载、磁盘使用率、存储的数据量大小等因素计算得来的
1.3 Pump Server
Pump主要用来承担binlog的写请求,维护binlog数据,并将有序的binlog提供给Drainer。可以将Pump抽象成一个简单的kv数据库,key为binlog的start _ts(Priwrite binlog)或者commit_ts(Commit binlog),value为binlog的元数据,binlog的数据则存在数据文件中。Drainer像查数据库一样的来获取所需要的binlog。
一条binlog在Pump中的写处理流程如下所示:
1)vlog
在Pump收到binlog的写请求时,会首先将binlog数据以append的形式写到ValueLog组件中。Valuelog是Binlog Event持久化到logFiles的组件,包含一系列对logFiles进行的操作,logFile文件在Pump指定数据目录下会以类似 “000001.log” 的命名保存。
2)KV
Pump内置了leveldb用于存储binlog的元信息,key为binlog的tso,如果为Prewrite binlog,则以start_ts作为key;如果是Commit binlog,则以commit_ts作为key。
3)sorter
由于TiDB使用的是2PC算法,一个成功的事务会写两条binlog:prewrite binlog和commit binlog。要完整的还原事务,需要对Prewrite binlog和Commit binlog进行配对,才能知晓某个事务是否被commit成功。Sorter就是完成这样的功能,逐条读出binlog,对于P-binlog则暂时存放在内存中等待配对,对于C-binlog则与内存中未配对的P-binlog进行匹配。如果某一条P-binlog长期没有C-binlog与之匹配上,Sorter将反查TiKV确认P-binlog是否写入。
当Drainer向Pump请求获取指定ts之后的binlog时,Pump则查询leveldb中大于该ts的binlog的元数据,如果当前数据为Prewrite binlog,则必须找到对应的Commit binlog;如果为Commit binlog则继续向前推进。这里存在一个问题是某些情况下发生异常导致Pump没有接收到Commit binlog,那么Pump中就会一直找不到对应的Commit binlog。出现这种情况的时候,Pump设置超时机制,如果某个Prewrite binlog超过了十分钟都没有找到对应的Commit binlog,则通过binlog数据中的prewrite_key去查询TiKV该事务是否提交,如果已经提交成功,则TiKV会返回该事务的commit_ts;否则Pump就丢弃该条Prewrite binlog。
1.4 Drainer Server
Drainer从各个Pump中获取binlog,归并后按照顺序解析binlog、生成SQL或者指定格式的数据,然后再同步到下游。Drain通过PD中存储的Pump状态信息来维护Pump信息,及时获取新增加的Pump以及识别出不可用的Pump。同时,新增加的Pump需要通知到Drainer自己已经上线,这样才能保证不会丢失数据。Drainer的处理过程如下所示:
2、部署使用
2.1 环境准备
Pump和Drainer可以部署和运行在x86-64服务器上,服务器信息如下:
服务 | 部署数量 | 主机IP |
---|---|---|
Pump | 1 | 192.168.112.101 |
Drainer | 1 | 192.168.112.10 |
2.2 使用Binary部署TiDB Binlog
1)下载官方binary
[root@tango-centos01 src]# wget https://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz
[root@tango-centos01 tidb-toolkit]# mv tidb-binlog-latest-linux-amd64 tidb-binlog
[root@tango-centos01 bin]# ls
arbiter binlogctl drainer pump reparo
2)部署Pump
- Pump配置文件
# Pump Configuration
# Pump 绑定的地址
addr = "192.168.112.101:8250"
# Pump 对外提供服务的地址
advertise-addr = "192.168.112.101:8250"
# Pump 只保留多少天以内的数据 (默认 7)
gc = 7
# Pump 数据存储位置路径
data-dir = "data.pump"
# Pump 向 PD 发送心跳的间隔 (单位 秒)
heartbeat-interval = 2
# PD 集群节点的地址 (英文逗号分割,中间不加空格)
pd-urls = "http://192.168.112.101:2379,http://192.168.112.102:2379,http://192.168.112.103:2379"
# [security]
# 如无特殊安全设置需要,该部分一般都注解掉
# 包含与集群连接的受信任 SSL CA 列表的文件路径
# ssl-ca = "/path/to/ca.pem"
# 包含与集群连接的 PEM 形式的 X509 certificate 的路径
# ssl-cert = "/path/to/drainer.pem"
# 包含与集群链接的 PEM 形式的 X509 key 的路径
# ssl-key = "/path/to/drainer-key.pem"
# [storage]
# 设置为 true(默认值)来保证可靠性,确保 binlog 数据刷新到磁盘
# sync-log = true
# 当可用磁盘容量小于该设置值时,Pump 将停止写入数据
# 42 MB -> 42000000, 42 mib -> 44040192
# default: 10 gib
# stop-write-at-available-space = "10 gib"
# Pump 内嵌的 LSM DB 设置,除非对该部分很了解,否则一般注解掉
# [storage.kv]
# block-cache-capacity = 8388608
# block-restart-interval = 16
# block-size = 4096
# compaction-L0-trigger = 8
# compaction-table-size = 67108864
# compaction-total-size = 536870912
# compaction-total-size-multiplier = 8.0
# write-buffer = 67108864
# write-L0-pause-trigger = 24
# write-L0-slowdown-trigger = 17
- 启动实例
[root@tango-centos01 tidb-binlog]# nohup ./bin/pump -config pump.toml &
[2021/03/28 17:14:18.427 +08:00] [INFO] [version.go:50] ["Welcome to Pump"] ["Release Version"=v3.0.4-43-g094482d] ["Git Commit Hash"=094482d7b716509adc79d40c0a90e340d45d22dd] ["Build TS"="2019-12-30 03:32:11"] ["Go Version"=go1.13] ["Go OS/Arch"=linux/amd64]
[2021/03/28 17:14:18.427 +08:00] [INFO] [client.go:147] ["[pd] create pd client with endpoints"] [pd-address="[http://192.168.112.101:2379,http://192.168.112.102:2379,http://192.168.112.103:2379]"]
[2021/03/28 17:14:18.466 +08:00] [INFO] [client.go:255] ["[pd] switch leader"] [new-leader=http://192.168.112.102:2379] [old-leader=]
[2021/03/28 17:14:18.466 +08:00] [INFO] [client.go:166] ["[pd] init cluster id"] [cluster-id=6895288665419836207]
[2021/03/28 17:14:18.466 +08:00] [INFO] [server.go:128] ["get clusterID success"] [clusterID=6895288665419836207]
[2021/03/28 17:14:18.466 +08:00] [INFO] [client.go:147] ["[pd] create pd client with endpoints"] [pd-address="[http://192.168.112.101:2379,http://192.168.112.102:2379,http://192.168.112.103:2379]"]
[2021/03/28 17:14:18.469 +08:00] [INFO] [client.go:255] ["[pd] switch leader"] [new-leader=http://192.168.112.102:2379] [old-leader=]
[2021/03/28 17:14:18.469 +08:00] [INFO] [client.go:166] ["[pd] init cluster id"] [cluster-id=6895288665419836207]
[2021/03/28 17:14:18.476 +08:00] [INFO] [store.go:68] ["new store"] [path="tikv://192.168.112.101:2379,192.168.112.102:2379,192.168.112.103:2379?disableGC=true"]
[2021/03/28 17:14:18.476 +08:00] [INFO] [client.go:147] ["[pd] create pd client with endpoints"] [pd-address="[192.168.112.101:2379,192.168.112.102:2379,192.168.112.103:2379]"]
[2021/03/28 17:14:18.483 +08:00] [INFO] [client.go:255] ["[pd] switch leader"] [new-leader=http://192.168.112.102:2379] [old-leader=]
[2021/03/28 17:14:18.483 +08:00] [INFO] [client.go:166] ["[pd] init cluster id"] [cluster-id=6895288665419836207]
[2021/03/28 17:14:18.487 +08:00] [INFO] [store.go:74] ["new store with retry success"]
[2021/03/28 17:14:18.487 +08:00] [INFO] [storage.go:135] [NewAppendWithResolver] [options="{\"ValueLogFileSize\":524288000,\"Sync\":true,\"KVChanCapacity\":1048576,\"SlowWriteThreshold\":1,\"StopWriteAtAvailableSpace\":10737418240,\"KVConfig\":null}"]
[2021/03/28 17:14:18.487 +08:00] [INFO] [storage.go:1389] ["open metadata db"] [config="{\"block-cache-capacity\":8388608,\"block-restart-interval\":16,\"block-size\":4096,\"compaction-L0-trigger\":8,\"compaction-table-size\":67108864,\"compaction-total-size\":536870912,\"compaction-total-size-multiplier\":8,\"write-buffer\":67108864,\"write-L0-pause-trigger\":24,\"write-L0-slowdown-trigger\":17}"]
[2021/03/28 17:14:18.519 +08:00] [INFO] [storage.go:217] ["Append info"] [gcTS=0] [maxCommitTS=423889232304013313] [headPointer="{\"Fid\":0,\"Offset\":1932}"] [handlePointer="{\"Fid\":0,\"Offset\":1932}"]
[2021/03/28 17:14:18.566 +08:00] [WARN] [storage.go:337] ["no available space, you may want to free up some space or decrease `stop-write-at-available-space` configuration"] [available=4476448768] [StopWriteAtAvailableSpace=10737418240]
[2021/03/28 17:14:18.997 +08:00] [WARN] [ts.go:50] ["get timestamp too slow"] [take=101.274774ms]
[2021/03/28 17:14:19.015 +08:00] [INFO] [server.go:436] ["register success"] [NodeID=tango-centos01:8250]
[2021/03/28 17:14:19.015 +08:00] [INFO] [server.go:453] ["start to server request"] [addr=http://192.168.112.101:8250]
[2021/03/28 17:14:21.626 +08:00] [WARN] [storage.go:337] ["no available space, you may want to free up some space or decrease `stop-write-at-available-space` configuration"] [available=4476424192] [StopWriteAtAvailableSpace=10737418240]
3)部署Drainer
- Drainer配置文件
# Drainer Configuration.
# Drainer 提供服务的地址("192.168.112.10:8249")
addr = "192.168.112.10:8249"
# Drainer 对外提供服务的地址
advertise-addr = "192.168.112.10:8249"
# 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒)
detect-interval = 10
# Drainer 数据存储位置路径 (默认 "data.drainer")
data-dir = "data.drainer"
# PD 集群节点的地址 (英文逗号分割,中间不加空格)
pd-urls = "http://192.168.112.101:2379,http://192.168.112.102:2379,http://192.168.112.103:2379"
# log 文件路径
log-file = "drainer.log"
# Drainer 从 Pump 获取 binlog 时对数据进行压缩,值可以为 "gzip",如果不配置则不进行压缩
# compressor = "gzip"
# [security]
# 如无特殊安全设置需要,该部分一般都注解掉
# 包含与集群连接的受信任 SSL CA 列表的文件路径
# ssl-ca = "/path/to/ca.pem"
# 包含与集群连接的 PEM形式的X509 certificate 的路径
# ssl-cert = "/path/to/pump.pem"
# 包含与集群链接的 PEM 形式的 X509 key 的路径
# ssl-key = "/path/to/pump-key.pem"
# Syncer Configuration
[syncer]
# 如果设置了该项,会使用该sql-mode解析DDL语句,此时如果下游是MySQL或TiDB则
# 下游的sql-mode也会被设置为该值
# sql-mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"
# 输出到下游数据库一个事务的 SQL 语句数量 (默认 20)
txn-batch = 20
# 同步下游的并发数,该值设置越高同步的吞吐性能越好 (默认 16)
worker-count = 16
# 是否禁用拆分单个 binlog 的 SQL 的功能,如果设置为 true,则按照每个 binlog
# 顺序依次还原成单个事务进行同步(下游服务类型为 MySQL, 该项设置为 False)
# disable-dispatch = false
# safe mode 会使写下游 MySQL/TiDB 可被重复写入
# 会用 replace 替换 insert 语句,用 delete + replace 替换 update 语句
safe-mode = false
# Drainer下游服务类型(默认为 mysql)
# 参数有效值为 "mysql","tidb","file","kafka"
db-type = "file"
# 事务的 commit ts 若在该列表中,则该事务将被过滤,不会同步至下游
ignore-txn-commit-ts = []
# db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"),
# 不支持对 ignore schemas 的 table 进行 rename DDL 操作
ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql"
# replicate-do-db 配置的优先级高于 replicate-do-table。如果配置了相同的库名,支持使用正则表达式进行配置。
# 以 '~' 开始声明使用正则表达式
# replicate-do-db = ["~^b.*","s1"]
# [syncer.relay]
# 保存 relay log 的目录,空值表示不开启。
# 只有下游是 TiDB 或 MySQL 时该配置才生效。
# log-dir = ""
# 每个文件的大小上限
# max-file-size = 10485760
# [[syncer.replicate-do-table]]
# db-name ="test"
# tbl-name = "log"
# [[syncer.replicate-do-table]]
# db-name ="test"
# tbl-name = "~^a.*"
# 忽略同步某些表
# [[syncer.ignore-table]]
# db-name = "test"
# tbl-name = "log"
# db-type设置为mysql 时,下游数据库服务器参数
[syncer.to]
host = "192.168.112.10"
user = "root"
password = ""
# 使用 `./binlogctl -cmd encrypt -text string` 加密的密码
# encrypted_password 非空时 password 会被忽略
# encrypted_password = ""
# port = 3306
[syncer.to.checkpoint]
# 当checkpoint type是mysql或tidb时可以开启该选项,以改变保存checkpoint的数据库
# schema = "tidb_binlog"
# 目前只支持mysql或者tidb类型。可以去掉注释来控制checkpoint保存的位置。
# db-type 默认的 checkpoint 保存方式是:
# mysql/tidb -> 对应的下游 mysql/tidb
# file/kafka -> file in `data-dir`
# type = "mysql"
# host = "127.0.0.1"
# user = "root"
# password = ""
# 使用 `./binlogctl -cmd encrypt -text string` 加密的密码
# encrypted_password 非空时 password 会被忽略
# encrypted_password = ""
# port = 3306
- 启动Drainer
[root@tango-01 tidb-binlog]# nohup ./bin/drainer -config drainer.toml &
[2021/03/28 17:31:12.300 +08:00] [INFO] [version.go:50] ["Welcome to Drainer"] ["Release Version"=v3.0.4-43-g094482d] ["Git Commit Hash"=094482d7b716509adc79d40c0a90e340d45d22dd] ["Build TS"="2019-12-30 03:32:26"] ["Go Version"=go1.13] ["Go OS/Arch"=linux/amd64]
[2021/03/28 17:31:12.304 +08:00] [INFO] [main.go:46] ["start drainer..."] [config="{\"log-level\":\"info\",\"node-id\":\"\",\"addr\":\"http://192.168.112.10:8249\",\"advertise-addr\":\"http://192.168.112.10:8249\",\"data-dir\":\"data.drainer\",\"detect-interval\":10,\"pd-urls\":\"http://192.168.112.101:2379,http://192.168.112.102:2379,http://192.168.112.103:2379\",\"log-file\":\"drainer.log\",\"initial-commit-ts\":-1,\"sycner\":{\"sql-mode\":null,\"ignore-txn-commit-ts\":[],\"ignore-schemas\":\"INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql\",\"ignore-table\":null,\"txn-batch\":20,\"worker-count\":1,\"to\":{\"host\":\"192.168.112.10\",\"user\":\"root\",\"password\":\"\",\"port\":0,\"checkpoint\":{\"type\":\"\",\"schema\":\"\",\"host\":\"\",\"user\":\"\",\"password\":\"\",\"port\":0},\"dir\":\"data.drainer\",\"zookeeper-addrs\":\"\",\"kafka-addrs\":\"\",\"kafka-version\":\"\",\"kafka-max-messages\":0,\"topic-name\":\"\"},\"replicate-do-table\":null,\"replicate-do-db\":null,\"db-type\":\"file\",\"relay-log-dir\":\"\",\"relay-log-size\":10485760,\"enable-dispatch\":false,\"safe-mode\":false,\"enable-detect\":false},\"security\":{\"ssl-ca\":\"\",\"ssl-cert\":\"\",\"ssl-key\":\"\"},\"synced-check-time\":5,\"compressor\":\"\",\"EtcdTimeout\":5000000000,\"MetricsAddr\":\"\",\"MetricsInterval\":15}"]
[2021/03/28 17:31:12.305 +08:00] [INFO] [client.go:147] ["[pd] create pd client with endpoints"] [pd-address="[http://192.168.112.101:2379,http://192.168.112.102:2379,http://192.168.112.103:2379]"]
[2021/03/28 17:31:12.320 +08:00] [INFO] [client.go:255] ["[pd] switch leader"] [new-leader=http://192.168.112.102:2379] [old-leader=]
[2021/03/28 17:31:12.320 +08:00] [INFO] [client.go:166] ["[pd] init cluster id"] [cluster-id=6895288665419836207]
[2021/03/28 17:31:12.320 +08:00] [INFO] [server.go:111] ["get cluster id from pd"] [id=6895288665419836207]
[2021/03/28 17:31:12.326 +08:00] [INFO] [server.go:120] ["set InitialCommitTS"] [ts=423889540821286913]
[2021/03/28 17:31:12.326 +08:00] [INFO] [checkpoint.go:61] ["initialize checkpoint"] [type=file] [checkpoint=423889523349389314] [cfg="{\"CheckpointType\":\"file\",\"Db\":null,\"Schema\":\"\",\"Table\":\"\",\"ClusterID\":6895288665419836207,\"InitialCommitTS\":423889540821286913,\"dir\":\"data.drainer/savepoint\"}"]
[2021/03/28 17:31:12.327 +08:00] [INFO] [store.go:68] ["new store"] [path="tikv://192.168.112.101:2379,192.168.112.102:2379,192.168.112.103:2379?disableGC=true"]
[2021/03/28 17:31:12.327 +08:00] [INFO] [client.go:147] ["[pd] create pd client with endpoints"] [pd-address="[192.168.112.101:2379,192.168.112.102:2379,192.168.112.103:2379]"]
[2021/03/28 17:31:12.339 +08:00] [INFO] [client.go:255] ["[pd] switch leader"] [new-leader=http://192.168.112.102:2379] [old-leader=]
[2021/03/28 17:31:12.339 +08:00] [INFO] [client.go:166] ["[pd] init cluster id"] [cluster-id=6895288665419836207]
[2021/03/28 17:31:12.351 +08:00] [INFO] [store.go:74] ["new store with retry success"]
[2021/03/28 17:31:12.411 +08:00] [INFO] [binlogger.go:87] ["open binlogger"] [directory=data.drainer]
[2021/03/28 17:31:12.471 +08:00] [INFO] [file.go:146] ["ignored file in binlog dir"] [name=savepoint]
[2021/03/28 17:31:12.471 +08:00] [INFO] [binlogger.go:134] ["open and lock binlog file"] [name=data.drainer/binlog-0000000000000000-20210329172951]
[2021/03/28 17:31:12.472 +08:00] [INFO] [store.go:68] ["new store"] [path="tikv://192.168.112.101:2379,192.168.112.102:2379,192.168.112.103:2379?disableGC=true"]
[2021/03/28 17:31:12.472 +08:00] [INFO] [client.go:147] ["[pd] create pd client with endpoints"] [pd-address="[192.168.112.101:2379,192.168.112.102:2379,192.168.112.103:2379]"]
[2021/03/28 17:31:12.489 +08:00] [INFO] [client.go:255] ["[pd] switch leader"] [new-leader=http://192.168.112.102:2379] [old-leader=]
[2021/03/28 17:31:12.489 +08:00] [INFO] [client.go:166] ["[pd] init cluster id"] [cluster-id=6895288665419836207]
[2021/03/28 17:31:12.496 +08:00] [INFO] [store.go:74] ["new store with retry success"]
[2021/03/28 17:31:12.506 +08:00] [INFO] [server.go:255] ["register success"] ["drainer node id"=tango-01:8249]
[2021/03/28 17:31:12.507 +08:00] [INFO] [server.go:319] ["start to server request"] [addr=http://192.168.112.10:8249]
[2021/03/28 17:31:12.516 +08:00] [INFO] [merge.go:222] ["merger add source"] ["source id"=tango-centos01:8250]
[2021/03/28 17:31:12.516 +08:00] [INFO] [pump.go:134] ["pump create pull binlogs client"] [id=tango-centos01:8250]
[2021/03/28 17:31:18.056 +08:00] [INFO] [syncer.go:254] ["write save point"] [ts=423889542315507713]
3、运维管理
3.1 Pump/Drainer状态
Pump/Drainer的状态包括:online、pausing、paused、closing、offline,这些状态由Pump/Drainer自身维护,并定时更新到PD中。
3.2 Binlog Control
Binlog Control是TiDB Binlog的命令行工具,用于管理TiDB Binlog集群。binlogctl支持如下这些功能:
- 查看Pump/Drainer 状态
- 暂停/下线Pump/Drainer
- Pump/Drainer异常状态处理
使用binlogctl的场景:
- 同步出现故障/检查运行情况,需要查看Pump/Drainer的状态
- 维护集群,需要暂停/下线Pump/Drainer
- Pump/Drainer异常退出,状态没有更新,或者状态不符合预期,对业务造成影响
1)查询所有的Pump/Drainer的状态
#查看Pumps
[root@tango-01 tidb-binlog]# ./bin/binlogctl -pd-urls=http://192.168.112.101:2379 -cmd pumps
[2021/03/28 17:32:32.705 +08:00] [INFO] [nodes.go:52] ["query node"] [type=pump] [node="{NodeID: tango-centos01:8250, Addr: 192.168.112.101:8250, State: online, MaxCommitTS: 423889561202982913, UpdateTime: 2021-03-29 17:32:29 +0800 CST}"]
#查看Drainers
[root@tango-01 tidb-binlog]# ./bin/binlogctl -pd-urls=http://192.168.112.101:2379 -cmd drainers
[2021/03/28 17:33:05.926 +08:00] [INFO] [nodes.go:52] ["query node"] [type=drainer] [node="{NodeID: tango-01:8249, Addr: 192.168.112.10:8249, State: online, MaxCommitTS: 423889569853734913, UpdateTime: 2021-03-29 17:33:04 +0800 CST}"]
2)暂停/下线Pump/Drainer
binlogctl会发送HTTP请求给Pump/Drainer,Pump/Drainer收到命令后会主动执行对应的退出流程。
3)异常情况下修改Pump/Drainer的状态
在一些异常情况下Pump/Drainer无法正确维护自己的状态,可能会影响数据同步任务,在这种情况下需要使用binlogctl修复状态信息。设置cmd为update-pump或者update-drainer来更新Pump或者Drainer的状态。Pump和Draine 的状态可以为paused或者offline
bin/binlogctl -pd-urls=http://192.168.112.101:2379 -cmd update-pump -node-id ip-192-168-112-101:8250 -state paused
3.3 使用TiDB SQL管理Pump/Drainer
1)查看Pump/Drainer状态
mysql> show pump status;
+---------------------+----------------------+--------+--------------------+---------------------+
| NodeID | Address | State | Max_Commit_Ts | Update_Time |
+---------------------+----------------------+--------+--------------------+---------------------+
| tango-centos01:8250 | 192.168.112.101:8250 | online | 423889720416141313 | 2021-03-28 17:42:36 |
+---------------------+----------------------+--------+--------------------+---------------------+
1 row in set (1.42 sec)
mysql> show drainer status;
+---------------+---------------------+--------+--------------------+---------------------+
| NodeID | Address | State | Max_Commit_Ts | Update_Time |
+---------------+---------------------+--------+--------------------+---------------------+
| tango-01:8249 | 192.168.112.10:8249 | online | 423889724348301313 | 2021-03-28 17:42:52 |
+---------------+---------------------+--------+--------------------+---------------------+
1 row in set (0.01 sec)
2)异常情况下修改Pump/Drainer状态
mysql> change pump to node_state ='paused' for node_id 'tango-centos01:8250';
mysql> change drainer to node_state ='paused' for node_id 'tango-01:8249';
4、增量恢复
TiDB使用Reparo实现增量恢复,TiDB Binlog中的Drainer将binlog按照protobuf格式输出到文件,当需要恢复增量数据的时候,使用Reparo解析文件中的binlog,并应用到TiDB中。
1)下载Reparo
wget https://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz
2)配置Reparo
# Drainer 输出的 protobuf 格式 binlog 文件的存储路径。
data-dir = "./data.drainer"
# 日志输出信息等级设置:debug, info, warn, error, fatal (默认值:info)。
log-level = "info"
# 使用 start-datetime 和 stop-datetime 来选择恢复指定时间范围内的 binlog,格式为 “2006-01-02 15:04:05”。
# start-datetime = ""
# stop-datetime = ""
# start-tso、stop-tso 分别对应 start-datetime 和 stop-datetime,也是用于恢复指定时间范围内的 binlog,用 tso 的值来设置。如果已经设置了 start-datetime 和 stop-datetime,就不需要再设置 start-tso 和 stop-tso。
# start-tso = 0
# stop-tso = 0
# 下游服务类型。 取值为 print, mysql(默认值:print)。当值为 print 时,只做解析打印到标准输出,不执行 SQL;如果为 mysql,则需要在 [dest-db] 中配置 host、port、user、password 等信息。
dest-type = "print"
# 输出到下游数据库一个事务的 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 = "192.168.112.10"
port = 3309
user = "root"
password = ""
3)启动实例
[root@tango-01 tidb-binlog]# nohup ./bin/reparo -config reparo.toml
[2021/03/28 17:31:12.299 +08:00] [INFO] [config.go:357] ["use default downstream file directory"] [directory=data.drainer]
[2021/03/28 17:54:34.719 +08:00] [INFO] [config.go:357] ["use default downstream file directory"] [directory=data.drainer]
[2021/03/28 18:08:10.485 +08:00] [INFO] [version.go:50] ["Welcome to Reparo"] ["Release Version"=v3.0.4-43-g094482d] ["Git Commit Hash"=094482d7b716509adc79d40c0a90e340d45d22dd] ["Build TS"="2019-12-30 03:32:33"] ["Go Version"=go1.13] ["Go OS/Arch"=linux/amd64]
[2021/03/28 18:08:10.485 +08:00] [INFO] [reparo.go:38] ["New Reparo"] [config="{\"data-dir\":\"./data.drainer\",\"start-datetime\":\"\",\"stop-datetime\":\"\",\"start-tso\":0,\"stop-tso\":0,\"txn-batch\":20,\"worker-count\":16,\"dest-type\":\"print\",\"dest-db\":{\"host\":\"192.168.112.10\",\"user\":\"root\",\"password\":\"\",\"port\":3309},\"replicate-do-table\":null,\"replicate-do-db\":null,\"replicate-ignore-table\":null,\"replicate-ignore-db\":null,\"log-file\":\"\",\"log-level\":\"info\",\"safe-mode\":false}"]
[2021/03/28 18:08:10.485 +08:00] [INFO] [file.go:146] ["ignored file in binlog dir"] [name=savepoint]
[2021/03/28 18:08:10.485 +08:00] [WARN] [file.go:104] ["no binlog find in file"] [filename=data.drainer/binlog-0000000000000000-20210329172951]
[2021/03/28 18:08:10.485 +08:00] [INFO] [file.go:77] ["after filter files"] [files="[data.drainer/binlog-0000000000000000-20210329172951]"] ["start tso"=0] ["stop tso"=0]
[2021/03/28 18:08:10.485 +08:00] [INFO] [read.go:123] ["read file end"] [file=data.drainer/binlog-0000000000000000-20210329172951]
参考资料:
- https://pingcap.com/blog-cn/tidb-ecosystem-tools-1/
- https://docs.pingcap.com/zh/tidb/stable/tidb-binlog-overview
- https://pingcap.com/blog-cn/#TiDB-Binlog-源码阅读
转载请注明原文地址:https://blog.youkuaiyun.com/solihawk/article/details/119150983
文章会同步在公众号“牧羊人的方向”更新,感兴趣的可以关注公众号,谢谢!