技術分享 | tidb 2.1升級到4.0操作文檔

作者:莫善

某互聯網公司高級 DBA。

本文來源:原創投稿

*愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。

一、前言

線上tidb集羣都是2.1.[5,7,8,17],因版本太低,面臨諸多問題,比如管理難度大,熱點問題,執行計劃失效,性能瓶頸,其他已知/未知且無法解決的問題,現在需要升級至4.0.13版本。在調研後發現,如果原地升級將需要多次升級【2.1--> 3.0 --> 4.0】,擔心原地升級遇到不可逆的故障,更擔心的是解決不掉而影響業務,所以經過測試和評估,最終採用數據遷移的方式進行升級。

因爲使用2.1版本的用戶本身比較少,更別提升級了,所以可參考的遷移升級文檔幾乎沒有,在升級中遇到了很多問題,也踩了很多坑,本文整理了升級操作流程,並標記每個步驟容易遇到什麼問題及解決方案,權當經驗交流,避坑指南。本文所有內容/操作命令僅供參考。
  • 因5.0基於MySQL 8.0協議,擔心和業務不兼容,也因爲5.0+的小版本都還比較小,擔心穩定性,所以就不考慮了,當時4.0.13是4.0最新的版本,就選了這個版本。

  • 已經有24套tidb集羣完成了從2.1到4.0.13的升級。

二、環境介紹

1、舊集羣環境介紹

  • 已有的組件
角色 數量 端口
pd 3 5017
tidb 3 4000
tikv 3 20117
alertmanager 1 9093
prometheus 1 9100
grafana 1 3000
vip 192.168.1.100 4000
dns old.tdb.com 4000
  • 未列舉的組件表示未啓用該組件,因歷史原因,集羣並沒有啓用pump組件。

  • 端口規劃也沒什麼規律

  • 預計增加的組件
角色 數量 端口
pump 3 23001
drainer 1 24001
2、舊集羣訪問信息
dns old.tdb.com
vip 192.168.1.100:4000 rs :
192.168.1.1:4000
192.168.1.2:4000
192.168.1.3:4000
3、新集羣環境介紹
角色 數量 端口
pd 3 13002
tidb 3 15002
tikv 3 17002
ticdc 3 33002
alertmanager 1 21002
prometheus 1 19002
grafana 1 20002
vip 192.168.1.100 15002
dns new.tdb.com 15002
  • 端口採用2+3的格式,前兩位是組件編號,後三位表示集羣編號。即後三位一樣的表示同一個集羣,前兩位一樣表示同一個組件。

4、新集羣訪問信息

dns new.tdb.com
vip 192.168.1.100:15002 rs :
192.168.1.1:15002
192.168.1.2:15002
192.168.1.3:15002

三、流程介紹

  • 1、dba 打印當前連接tidb的ip列表讓主業務方確認是否存在非本業務的ip。確保所有使用該集羣的業務都參與進來。

  • 2、dba 跟業務確認是否有重連機制。(開啓binlog需要重啓tidb組件)。
  • 3、dba 開啓binlog,這步需要滾動重啓tidb組件,需要跟業務協商一個時間窗口。
  • 4、dba 部署4.0環境並導入全量數據。
  • 5、dba 同步增量數據。
  • 6、dba 校驗新舊集羣數據一致性。
  • 7、dba 交付新環境,提供新的域名 + 端口。
  • 8、dba 提供只讀賬戶,業務測試,驗證業務場景(僅限讀,不能寫)。
  • 9、dba 同步權限。
  • 10、切換流量。

四、升級操作

1、打印舊集羣訪問列表

ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb1 -P 4000 -ppassword
mysql> select distinct host from information_schema.processlist

ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb2 -P 4000 -ppassword
mysql> select distinct host from information_schema.processlist

ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb3 -P 4000 -ppassword
mysql> select distinct host from information_schema.processlist
登錄所有tidb節點,每個節點的輸出結果追加到一個文件,然後排序去重進行統計客戶端ip

2、確認是否有重連機制

3、開啓binlog並全量備份

這步操作在ansible管理機執行

(1)編輯配置文件
ansible # vim /path/github/tidb-ansible-2.1.8/inventory.ini
  • 添加pump組件的監控
[monitored_servers]
monitor-pump1 ansible_host=xxxx deploy_dir=/path/tidb-data/pump-23001
monitor-pump2 ansible_host=xxxx deploy_dir=/path/tidb-data/pump-23001
monitor-pump3 ansible_host=xxxx deploy_dir=/path/tidb-data/pump-23001
  • 添加pump組件
[pump_servers]
#下面三個是pump組件的機器, 如果啓用pump組件還需要打開 enable_binlog = True
pump1 ansible_host=xxxx deploy_dir=/path/tidb-data/pump-23001
pump2 ansible_host=xxxx deploy_dir=/path/tidb-data/pump-23001
pump3 ansible_host=xxxx deploy_dir=/path/tidb-data/pump-23001
  • pump端口設置及啓用binlog參數
## Global variables
[all:vars]
pump_port = 23001

## binlog trigger
enable_binlog = True
#enable_binlog = False
如果不設置enable_binlog = True,在部署pump的時候會被忽略。另外需要注意,在pump能提供服務前,不能重新加載tidb的配置並重啓,否則會導致業務寫操作失敗。

(2)編輯pump的配置

ansible # vim /path/github/tidb-ansible-2.1.8/conf/pump.yml
  • 修改binlog保存週期
global:
  # a integer value to control expiry date of the binlog data, indicates for how long (in days) the binlog data would be stored. 
  # must bigger than 0
  gc: 14
改成14天,避免全量數據導入時間過長導致增量數據丟失(binlog被清理)。

(3)登錄目標機器創建目錄

登錄各個pump節點創建目錄及更改權限

ansible # ssh pump1
pump1   # mkdir -p /path/tidb-data/pump-23001
pump1   # chown -R tidb. /path/tidb-data/pump-23001

ansible # ssh pump2
pump2   # mkdir -p /path/tidb-data/pump-23001
pump2   # chown -R tidb. /path/tidb-data/pump-23001

ansible # ssh pump3
pump3   # mkdir -p /path/tidb-data/pump-23001
pump3   # chown -R tidb. /path/tidb-data/pump-23001

(4)在ansible管理機部署pump及監控

ansible # ansible-playbook deploy.yml -l monitor-pump1,monitor-pump2,monitor-pump3,pump1,pump2,pump3 -i inventory.ini

(5)在ansible管理機啓動pump及監控

ansible # ansible-playbook start.yml -l monitor-pump1,monitor-pump2,monitor-pump3,pump1,pump2,pump3 -i inventory.ini

(6)登錄tidb查看pump是否部署完成

ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb.com -P 4000 -ppassword
mysql> show pump status;
+------------+------------+--------+--------------------+---------------------+
| NodeID     | Address    | State  | Max_Commit_Ts      | Update_Time         |
+------------+------------+--------+--------------------+---------------------+
| xxxx:23001 | xxxx:23001 | online | 427138948355850245 | 2021-08-20 04:42:57 |
| xxxx:23001 | xxxx:23001 | online | 427138948395171844 | 2021-08-20 04:42:57 |
| xxxx:23001 | xxxx:23001 | online | 427138948408279045 | 2021-08-20 04:42:57 |
+------------+------------+--------+--------------------+---------------------+
3 rows in set (0.00 sec)

mysql> 

需要注意,2.1.6之前的版本不支持這個查詢操作,需要通過binlogctl 進行查看pump的狀態,如下示例。

ansible #  /path/binlogctl -pd-urls=http://pd_host:pd_port -cmd pumps
INFO[0000] pump: {NodeID: xxxx:23001, Addr: xxxx:23001, State: online, MaxCommitTS: 432180280017551379, UpdateTime: 2021-08-20 04:45:57 +0800 CST} 
INFO[0000] pump: {NodeID: xxxx:23001, Addr: xxxx:23001, State: online, MaxCommitTS: 432180280004444167, UpdateTime: 2022-03-30 18:45:14 +0800 CST} 
INFO[0000] pump: {NodeID: xxxx:23001, Addr: xxxx:23001, State: online, MaxCommitTS: 432180280017551372, UpdateTime: 2022-03-30 18:45:14 +0800 CST} 

(7)在ansible管理機滾動重啓tidb節點

執行這個操作前,一定要確保pump組件正常運行。

ansible # ansible-playbook rolling_update.yml -t tidb -i inventory.ini
需要注意的是,這個操作可能會出現ansible啓動或者關閉動作失敗(一直卡着直到超時),如果碰到這種情況,可以登錄到目標機器手動進行啓動或者停止。參考命令如下:
  • 啓動 cd /path/tidb/scripts && sudo -u tidb bash start_tidb.sh
  • 停止 cd /path/tidb/scripts && sudo -u tidb bash stop_tidb.sh

(8)登錄tidb檢查binlog是否已經開啓

ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb.com -P 4000 -ppassword
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | 1     |
+---------------+-------+
1 row in set (0.01 sec)
  • 需要注意,2.1.6之前的版本 log_bin 恆等於 0,就是說即便enable_binlog = True,通過show variables like 'log_bin';查出來的也是0,但是pump會記錄binlog。

  • 建議挨個tidb都檢查一遍。

(9)在ansible管理機更新監控

ansible # ansible-playbook rolling_update_monitor.yml -t prometheus -i inventory.ini
(10)創建全量備份
ansible # /path/mydumper -u user -p pass -h old.tdb.com -P 4000 -t 2 -F 32 --skip-tz-utc -o /backup_path/4000 -B db_name
備份需要注意:
  • 工具獲取 https://docs.pingcap.com/zh/tidb/v2.1/backup-and-restore
  • 在業務低峯進行備份,否則可能會出現網卡打滿的情況(尤其是tidb是萬兆網卡,tikv是千兆網卡的架構)
  • 可能會因爲gc時間過短導致備份失敗(通過調整gc時間解決)
  • 可能因爲tidb分配的內存過小導致備份失敗(通過調整tidb內存解決)
  • 備份完成後建議檢查一下建表語句的文件,是否存在非法時間格式("0000-00-00"),如果存在在導入新集羣的時候會報錯,需要跟業務溝通一下變更默認值。
  • mydumper不支持限流備份,可以通過備份到磁盤性能很差的機器或者cfs這種網絡存儲,在一定程度上實現了限流備份。

4、部署4.0環境並導入全量數據

悲觀事務模型需要關注一下,4.0雖然支持悲觀事務模型,而且新建集羣默認也是開啓狀態,但是要想一個操作用到悲觀鎖,還是有一定的限定條件的,即非autocommit 的事務。具體請參考這個文章的【6.2.3.2部分】 https://book.tidb.io/session1/chapter6/pessimistic-txn.html

(1)安裝tiup

ansible # curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
ansible # . /root/.bash_profile
ansible # tiup --version
ansible # tiup update --self

(2)準備拓撲文件

ansible # vim topology-oltp-xxx.yaml

global:
  user: "tidb"
  ssh_port: 22
  deploy_dir: "/tidb-deploy"
  data_dir: "/tidb-data"
  
monitored:
  node_exporter_port: 11000
  blackbox_exporter_port: 12000
  
pd_servers:
  - host: 10.0.1.4
  - host: 10.0.1.5
  - host: 10.0.1.6

tidb_servers:
  - host: 10.0.1.1
  - host: 10.0.1.2
  - host: 10.0.1.3

tikv_servers:
  - host: 10.0.1.7
  - host: 10.0.1.8
  - host: 10.0.1.9

cdc_servers:
  - host: 10.0.1.7
  - host: 10.0.1.8
  - host: 10.0.1.9

monitoring_servers:
  - host: 10.0.1.10

grafana_servers:
  - host: 10.0.1.10

alertmanager_servers:
  - host: 10.0.1.10
以上是官方提供的配置模板,請根據實際情況修改。
  • 建議部署ticdc(pump),避免需要回滾的時候可追溯增量數據。
  • 建議每個組件單獨一臺機器。

(3)檢查tiup 管理機到各個節點的ssh通道是否正常

(4)部署集羣

ansible # tiup cluster check tidb-oltp-xxx-v4.0.13 v4.0.13 topology-oltp-xxx.yaml
ansible # tiup cluster deploy tidb-oltp-xxx-v4.0.13 v4.0.13 topology-oltp-xxx.yaml
ansible # tiup cluster start tidb-oltp-xxx-v4.0.13
ansible # tiup cluster display tidb-oltp-xxx-v4.0.13
  • check可能會報很多異常,可以根據提示進行修復,很多異常也可以忽略。請參考 https://docs.pingcap.com/zh/tidb/v4.0/tiup-component-cluster-check#tiup-cluster-check

(5)權限維護

ansible # /opt/soft/mysql57/bin/mysql -u root -h new.tdb.com -P 15002 -p
mysql> create user if not exists root@"192.168.1.%" IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.%' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'pd1' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'pd2' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'pd3' WITH GRANT OPTION;
  • 這裏用空密碼就能登錄。

  • 這裏需要加上pd節點的授權,而且要求是root用戶(還是給all權限吧,測試發現給select權限不行,沒做更細緻的權限測試),否則dashboard不能正常使用。

ansible # /opt/soft/mysql57/bin/mysql -u root -h new.tdb.com -P 15002 -ppassword
mysql> drop user if exists root@"%";

建議刪除root@'%'這個空密碼用戶。

(6)導入全量數據

ansible # /path/loader -d /backup_path/4000 -h new.tdb.com -u user -p password -P 15002 -t 2 -status-addr ":9299"

恢復需要注意:

  • 工具獲取 https://docs.pingcap.com/zh/tidb/v2.1/backup-and-restore
  • 建議在業務低峯進行恢復
  • 可能會因爲表情符導致loader失敗,如果遇到,可以試試Dumpling
  • 多個loader任務的場景,建議避開默認端口,否則可能會因爲端口衝突導致失敗

5、同步增量數據

這步操作在ansible管理機執行

(1)在備份機獲取備份點位(本例使用ansible管理機進行備份)

從備份目錄查看metadata文件

ansible # cd /backup_path/xxx
ansible # cat metadata 

Started dump at: 2021-08-29 15:34:30
SHOW MASTER STATUS:
 Log: tidb-binlog
 Pos: 425971435565482001
 GTID:

Finished dump at: 2021-08-29 15:34:33
ansible 

(2)修改配置文件

ansible # vim /path/github/tidb-ansible-2.1.8/inventory.ini
  • 添加drainer組件的監控
[monitored_servers]
monitor-drainer1 ansible_host=xxxx deploy_dir=/path/tidb-data/drainer-24001
  • 添加drainer組件
[drainer_servers]
drainer1 ansible_host=xxxx deploy_dir=/path/tidb-data/drainer-24001 initial_commit_ts="425971435565482001"
  • drainer端口設置
## Global variables
[all:vars]
drainer_port = 24001

(3)準備drainer的配置文件

ansible # vim /path/github/tidb-ansible-2.1.8/conf/drainer1_drainer.toml 
配置文件名命名規則爲【別名_drainer.toml】,否則部署時無法找到自定義配置文件。
# drainer Configuration.

# the interval time (in seconds) of detect pumps' status
detect-interval = 10

# syncer Configuration.
[syncer]

# disable sync these schema
ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql"

# number of binlog events in a transaction batch
txn-batch = 2000

# work count to execute binlogs
worker-count = 32

disable-dispatch = false

# safe mode will split update to delete and insert
safe-mode = false

# downstream storage, equal to --dest-db-type
# valid values are "mysql", "pb", "tidb", "flash", "kafka"
db-type = "tidb"

# the downstream MySQL protocol database
[syncer.to]
host = "new.tdb.com"
user = "user"
password = "xxxx"
port = 15002
txn-batch 和 worker-count的配置在配置文件默認值應該是1,建議根據實際情況改大點,如果太小可能出現增量數據一直追不上的情況。

(4)部署drainer及監控

ansible # ansible-playbook deploy_drainer.yml -i inventory.ini -l drainer1
ansible # ansible-playbook deploy.yml -i inventory.ini -l monitor-drainer1

(5)登錄新集羣的tidb,給drainer節點授權

ansible # /opt/soft/mysql57/bin/mysql -u root -h new.tdb.com -P 15002 -ppassword
mysql> create user if not exists user@"drainer_host" IDENTIFIED BY 'xxxx';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'user'@'drainer_host';
注意:新集羣(4.0)要給drainer所在的主機授權,否則啓動drainer將報錯,爲了演示方便,這裏直接給了所有權限

(6)啓動drainer及監控

啓動drainer前建議先確定一下目標庫是否已經存在tidb_binlog庫,如果存在,且又需要從備份的點位開始增量同步,這種情況需要手動刪除一下,要不然drainer會從checkpoint開始同步數據。(一般出現在導入全量失敗後需要重新導入全量,然後忘記清理tidb_binlog庫)

ansible # ansible-playbook start_drainer.yml -i inventory.ini -l drainer1
ansible # ansible-playbook start.yml -i inventory.ini -l monitor-drainer1

(7)登錄tidb檢查drainer狀態

ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb.com -P 4000 -ppassword
mysql> show drainer status;
+------------+------------+--------+--------------------+---------------------+
| NodeID     | Address    | State  | Max_Commit_Ts      | Update_Time         |
+------------+------------+--------+--------------------+---------------------+
| xxxx:24001 | xxxx:24001 | online | 431972431138127904 | 2021-08-25 16:42:57 |
+------------+------------+--------+--------------------+---------------------+
1 rows in set (0.00 sec)

mysql> 

需要注意,2.1.6之前的版本不支持這個查詢操作,需要通過binlogctl 進行查看drainer的狀態,如下示例。

ansible #  /path/binlogctl -pd-urls=http://pd_host:pd_port -cmd drainers
INFO[0000] drainer: {NodeID: xxxx:24001, Addr: xxxx:24001, State: online, MaxCommitTS: 432180589478543384, UpdateTime: 2021-08-25 16:45:57 +0800 CST} 

(8)更新監控

ansible # ansible-playbook rolling_update_monitor.yml -t prometheus -i inventory.ini

(9)登錄grafana進行查看同步進度

注意:如果同步落後比較大,可以在alertmanager將drainer的告警先禁用

6、校驗新舊集羣數據一致性

(1)下載工具
ansible # git clone https://gitee.com/mo-shan/check_data_for_mysql.git
ansible # cd check_data_for_mysql
(2)修改配置
  • 編輯配置文件

ansible # cd /path/check_data_for_mysql
ansible # vim conf/check.conf

mysql_user="xxxx"
mysql_passwd="xxxx"
mysql_port1="6666"
mysql_port2="6666"
mysql_host1="192.168.1.1"
mysql_host2="192.168.1.2"
max_count=10000
threads=5
max_threads_running=30
mysql_path="/opt/soft/mysql57/bin/mysql"
log_partition="/dev/sda3"
log_par_size="10"
skip_check_table=""
skip_check_db="INFORMATION_SCHEMA,METRICS_SCHEMA,PERFORMANCE_SCHEMA,mysql,sys,tidb_binlog,test,tidb_loader,dm_meta" #不建議改

請結合實際情況根據註釋提示進行相關配置

  • 修改工作路徑
ansible # sed -i 's#^work_dir=.*#work_dir=\"/check_data_for_mysql_path\"#g' start.sh #將這裏的check_data_for_mysql_path改成check_data_for_mysql的家目錄的絕對路徑
(3)測試用例
  • 每次執行校驗任務的時候強制要清空log目錄,所以請做好校驗結果的備份
  • 執行校驗任務的時候強烈建議開啓screen
  • 有網卡監控需求,執行監控腳本時也強烈建議單獨開啓screen進行監控

第一步:先開啓一個screen監控網絡

ansible # screen -S check_net_4000
ansible # bash manager.sh -a start
[ 2022-01-18 11:55:34 ] [ 1000 Mb/s ] [ RX : 2    MB/S ]  [ TX : 2    MB/S ]
[ 2022-01-18 11:55:35 ] [ 1000 Mb/s ] [ RX : 2    MB/S ]  [ TX : 4    MB/S ]
[ 2022-01-18 11:55:36 ] [ 1000 Mb/s ] [ RX : 2    MB/S ]  [ TX : 2    MB/S ]
[ 2022-01-18 11:55:37 ] [ 1000 Mb/s ] [ RX : 2    MB/S ]  [ TX : 3    MB/S ]
[ 2022-01-18 11:55:38 ] [ 1000 Mb/s ] [ RX : 1    MB/S ]  [ TX : 2    MB/S ]
[ 2022-01-18 11:55:39 ] [ 1000 Mb/s ] [ RX : 1    MB/S ]  [ TX : 2    MB/S ]
[ 2022-01-18 11:55:41 ] [ 1000 Mb/s ] [ RX : 1    MB/S ]  [ TX : 2    MB/S ]
[ 2022-01-18 11:55:42 ] [ 1000 Mb/s ] [ RX : 2    MB/S ]  [ TX : 8    MB/S ]

第二步:新開啓一個screen執行校驗任務

ansible # screen -S check_data_4000
ansible # bash start.sh -d dba -t dbatest1 -f true 
[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ start.sh/start.sh ] [ f_prepare:130 ] [ 本次數據一致性檢查開始 ]
[ 2022-01-17 20:32:19 ] [ 警告 ] [ 192.168.1.1 ] [ start.sh/start.sh ] [ f_main:185 ] [ 本次數據一致性檢查將檢查如下庫 : [dba] ]
[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ start.sh/start.sh ] [ f_main:203 ] [ 正在檢查dba庫 ]

[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ func/f_check_diff_for_mysql.sh ] [ f_check_diff_for_mysql:249 ] [ dba.dbatest1 ] [ 表結構一致 ]

[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ func/f_check_diff_for_mysql.sh ] [ f_check_diff_for_mysql:491 ] [ dba.dbatest1 ] [ 1,1 ] [ 00 d 00 h 00 m 00 s ] [ 9.09%, (0:0)/1 ] [ 數據一致 ]
[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ func/f_check_diff_for_mysql.sh ] [ f_check_diff_for_mysql:491 ] [ dba.dbatest1 ] [ 2,11 ] [ 00 d 00 h 00 m 00 s ] [ 100.00%, (0:0)/1 ] [ 數據一致 ]
[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ func/f_check_diff_for_mysql.sh ] [ f_check_diff_for_mysql:504 ] [ dba.dbatest1 ] [ 檢查完畢 ]

[ 2022-01-17 20:32:19 ] [ 成功 ] [ 192.168.1.1 ] [ start.sh/start.sh ] [ f_main:242 ] [ 本次數據一致性檢查完成 ] [ 通過 ]

ansible 

檢查結束後會提示檢查通過,否則就是檢查不通過。

  • 工具實現邏輯請參考  https://mp.weixin.qq.com/s/PPGSnPL-2FgRWftDzqxAOA

7、交付新環境

dba提供新的域名和端口給業務,這裏給業務提供一個只讀賬戶即可。

ansible # /opt/soft/mysql57/bin/mysql -u root -h new.tdb.com -P 15002 -ppassword
mysql> create user if not exists read_only@"host" IDENTIFIED BY 'xxxx';
mysql> GRANT SELECT ON *.* TO 'read_only'@'host';
需要注意的是,交付新環境前先不要同步權限表(mysql.user)。

8、業務驗證

請業務充分驗證。

9、同步權限表

tidb2.1和4.0的權限表結構不一致,所以沒法通過導出導入的方式同步權限,另外經過測試使用pt工具也是不行的,下面提供一個同步權限的腳本,2.1到4.0版本測試有效,其他版本尚未測試。

#!/bin/bash
port=4000
mysql_comm="/opt/soft/mysql57/bin/mysql -u root -h old.tdb.com -P ${port} -ppassword"

for user in $(${mysql_comm} -NBe "select concat(user,'@','\"',host,'\"',':::',password) from mysql.user;" 2>/dev/null)
do
    user_tmp="$(awk -F::: '{print $1}' <<< "${user}")"
    pass_tmp="$(awk -F::: '{print $2}' <<< "${user}")"
    create_user="create user if not exists ${user_tmp} IDENTIFIED BY PASSWORD '${pass_tmp}';"
    drop_user="drop user if exists ${user_tmp};"
    grep -q "^root@" <<< "${user_tmp}" && {
            grant_user="$(${mysql_comm} -NBe "show grants for ${user_tmp}" 2>/dev/null|sed 's/$/ WITH GRANT OPTION;/g')"
        } || {
            grant_user="$(${mysql_comm} -NBe "show grants for ${user_tmp}" 2>/dev/null|sed 's/$/;/g')"
            echo "${drop_user}"
        }
    echo "${create_user}"
    echo "${grant_user}"
done
該腳本會將舊集羣的權限打出來,確認無誤後可以寫到新集羣。
ansible # bash show_grant.sh | /opt/soft/mysql57/bin/mysql -u root -h new.tdb.com -P 15002 -ppassword
  • 權限同步以後,請業務不要做授權操作,如需授權新主機或新建用戶,找dba協助。
  • 非必要也請業務不要再做ddl操作,如有需求也請dba協助。

10、切換流量

  • 業務切流量前,建議將新集羣的tidb挨個重啓一遍,釋放掉auto_increment緩存,重啓完畢後需要檢查drainer任務的狀態及延遲,等沒延遲再聯繫業務進行切換。

  • 如果不重啓,切到新集羣后自增列主鍵可能會報大量【Duplicate entry '' for key 'PRIMARY'】。

這個流程其實很簡單,直接將新集羣的tidb主機替換到vip原來 rs列表即可,或者新申請一個vip,將原來的域名解析到新vip。但因歷史問題,原來的域名和tidb端口都不符合管理規範,所以需要業務通過新的域名/端口訪問tidb。

需要注意:將域名解析到新的vip,這種僅對新進來的連接起作用。

鑑於環境的特殊性,dba提供了兩種方案實現讓業務通過新的域名端口訪問tidb。

不管採用哪種方案,在切流量以後都不建議馬上下掉舊域名。推薦的做法是刪除舊域名對應的vip的rs列表,將新集羣的tidb節點掛到舊域名對應的vip的rs列表(需要注意新tidb端口跟舊vip端口可能不一致),這樣做是避免了業務漏切的情況,觀察幾天dns日誌,確認沒業務使用舊域名後再下掉。

(1)野蠻方案
業務直接修改連接信息,使用 new.tdb.com:15002 來連接tidb。

因可能存在多個業務使用該庫,而且每個服務可能有多臺業務機器,做不到所有服務同一時刻都切到新庫,所以會出現下面幾種情況:

1)寫新庫,讀舊庫會讀不到,因爲新庫跟舊庫沒有同步鏈路。
2)寫舊庫,讀新庫,可能會讀不到,因爲舊庫跟新庫之間存在延遲。

避免不了雙寫,可能會導致下面的問題。

  • A. 更新同一行數據的兩個連接執行的時間極短(小於舊庫到新庫的同步延遲)。兩個連接是分別在舊庫/新庫執行,這時候該行數據的最終狀態不是以誰最後執行爲準。比如說,先在舊庫執行了【update t set name = 1 where id = 2;】,然後在新庫執行【update t set name = 2 where id = 2;】,理論上這個數據的記錄最終應該是name=2,但是考慮到新庫到舊庫的同步有延遲,這個數據就可能會被舊庫的數據覆蓋變成name=1。如果反過來,先寫新庫,再寫舊庫,這種情況對數據沒影響。

  • B. 業務的兩個連接在新庫舊庫分別插入同一行數據(主鍵一樣或者唯一鍵一樣的數據),如果先寫新庫,再寫舊庫,這樣在業務端都會提交成功,但是會導致舊庫到新庫的同步失敗,因爲舊庫寫入的數據同步到新庫就會報主鍵衝突(唯一鍵衝突),這時候就需要dba人工干預進行修復。如果反過來,先寫舊庫再寫新庫(不考慮舊庫到新庫的延遲),這時候寫新庫的會話就會報錯,這種情況對數據沒影響。

針對上述的情況,需要業務充分評估。如果不能接受,可以建議業務使用下面的平滑方案,這樣影響面較小。

(2)平滑方案

業務繼續使用 old.tdb.com:4000 這個來連接tidb。

dba需要將新集羣的tidb加到舊集羣的vip的rs列表,但是爲了避免同時往新舊集羣寫數據,所以應該先將vip的rs先下掉,然後再將新集羣的tidb ip加到vip rs列表。
這裏涉及兩個動作:
  • 將舊集羣的vip的rs列表清空(下線rs),這裏建議主動釋放連接(重啓/關閉舊集羣的tidb),要不然可能會出現下掉rs後(具體需要看vip的實現機制),連接不會釋放。

  • 將新集羣的tidb的ip加到舊集羣vip 的rs列表。

這兩個操作需要跟業務確認好,因爲下掉rs再重新加入有個時間差(預計30s之內),這過程集羣不可用。

完成上述操作後,舊集羣的訪問信息會變成如下表:
dns old.tdb.com
vip 192.168.1.100:4000 rs :
192.168.1.1:15002
192.168.1.2:15002
192.168.1.3:15002
這時候業務需要挨個更新業務代碼的配置,將舊域名和端口替換成新域名和端口(需要將 old.tdb.com:4000 替換成 new.tdb.com:15002 ),這時候再修改配置重啓業務影響面會比較小。

五、寫在最後

本文檔僅做經驗分享,避坑指南,因使用場景各異,各自環境也不同,在遷移過程中還可能碰上其他問題。如有線上環境操作需求,請在測試環境充分測試。
本文關鍵字:#tidb升級# #tidb數據遷移#

相關推薦:

MySQL binlog 分析工具 analysis_binlog 的使用介紹

兩個單機 MySQL 該如何校驗數據一致性

MySQL Load Data 的多種用法

一次數據庫遷移

SQLE 徵稿活動開始啦!
所有稿件,一經採用,均會爲作者署名、推廣、並收納到《大智小技4》
SQLE 是愛可生開源社區開發的一款面向數據庫使用者和管理者的 SQL 審覈工具,旨在規範 SQL 審覈上線流程,提高 SQL 質量。自 2021 年 10 月 24 日推出後得到數據庫行業同仁及用戶的廣泛關注。
爲進一步提升 SQLE 審覈平臺內容質量及深度,現對廣大用戶發起徵稿,希望更多關注技術內容的小夥伴能夠在這個平臺展示自己,分享獨到的技術見解和優質內容。點擊下圖瞭解活動詳情:


點擊閱讀原文,詳細瞭解SQLE

本文分享自微信公衆號 - 愛可生開源社區(ActiontechOSS)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章