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

愛可生雲資料庫發表於2022-04-13

作者:莫善

某網際網路公司高階 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、舊叢集環境介紹

  • 已有的元件
角色數量
pd35017
tidb34000
tikv320117
alertmanager19093
prometheus19100
grafana13000
vip192.168.1.1004000
dnsold.tdb.com4000
  • 未列舉的元件表示未啟用該元件,因歷史原因,叢集並沒有啟用pump元件。
  • 埠規劃也沒什麼規律
  • 預計增加的元件
角色數量
pump323001
drainer124001

2、舊叢集訪問資訊

dnsold.tdb.com
vip192.168.1.100:4000rs :
192.168.1.1:4000
192.168.1.2:4000
192.168.1.3:4000

3、新叢集環境介紹

角色數量
pd313002
tidb315002
tikv317002
ticdc333002
alertmanager121002
prometheus119002
grafana120002
vip192.168.1.10015002
dnsnew.tdb.com15002
  • 埠採用2+3的格式,前兩位是元件編號,後三位表示叢集編號。即後三位一樣的表示同一個叢集,前兩位一樣表示同一個元件。

4、新叢集訪問資訊

dnsnew.tdb.com
vip192.168.1.100:15002rs :
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> 
需要注意,<font color='red'>2.1.6之前的版本不支援這個查詢操作,需要通過binlogctl 進行檢視pump的狀態,如下示例。</font>
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節點

<font color='red'>執行這個操作前,一定要確保pump元件正常執行。</font>
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)
  • 需要注意,<font color='red'>2.1.6之前的版本 log_bin 恆等於 0</font>,就是說即便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/t...
  • 在業務低峰進行備份,否則可能會出現網路卡打滿的情況(尤其是tidb是萬兆網路卡,tikv是千兆網路卡的架構)
  • 可能會因為gc時間過短導致備份失敗(通過調整gc時間解決)
  • 可能因為tidb分配的記憶體過小導致備份失敗(通過調整tidb記憶體解決)
  • 備份完成後建議檢查一下建表語句的檔案,是否存在非法時間格式("0000-00-00"),如果存在在匯入新叢集的時候會報錯,需要跟業務溝通一下變更預設值。
  • mydumper不支援限流備份,可以通過備份到磁碟效能很差的機器或者cfs這種網路儲存,在一定程度上實現了限流備份。

4、部署4.0環境並匯入全量資料

悲觀事務模型需要關注一下,<font color='red'>4.0雖然支援悲觀事務模型,而且新建叢集預設也是開啟狀態,但是要想一個操作用到悲觀鎖,還是有一定的限定條件的,即非autocommit 的事務。具體請參考這個文章的【6.2.3.2部分】</font> https://book.tidb.io/session1...

(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

(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/t...
  • 建議在業務低峰進行恢復
  • 可能會因為表情符導致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> 
需要注意,<font color='red'>2.1.6之前的版本不支援這個查詢操作,需要通過binlogctl 進行檢視drainer的狀態,如下示例。</font>
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)測試用例

  • 每次執行校驗任務的時候<font color='red'>強制要清空log目錄,所以請做好校驗結果的備份</font>
  • 執行校驗任務的時候<font color='red'>強烈建議開啟screen</font>
  • 有網路卡監控需求,<font color='red'>執行監控指令碼時也強烈建議單獨開啟screen進行監控 </font>

第一步:先開啟一個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 # 

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

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
  • 許可權同步以後,<font color='red'>請業務不要做授權操作</font>,如需授權新主機或新建使用者,找dba協助。
  • 非必要<font color='red'>也請業務不要再做ddl操作</font>,如有需求也請dba協助。

10、切換流量

  • 業務切流量前,建議將新叢集的tidb挨個重啟一遍,釋放掉auto_increment快取,重啟完畢後需要檢查drainer任務的狀態及延遲,等沒延遲再聯絡業務進行切換。
  • 如果不重啟,切到新叢集后<font color='red'>自增列主鍵可能會報大量【Duplicate entry '' for key 'PRIMARY'】。</font>

這個流程其實很簡單,直接將新叢集的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人工干預進行修復。如果反過來,先寫舊庫再寫新庫(不考慮舊庫到新庫的延遲),這時候寫新庫的會話就會報錯,這種情況對資料沒影響。

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

(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之內),<font color='red'>這過程叢集不可用。</font>

完成上述操作後,舊叢集的訪問資訊會變成如下表:

dnsold.tdb.com
vip192.168.1.100:4000rs :
192.168.1.1:15002
192.168.1.2:15002
192.168.1.3:15002

這時候業務需要挨個更新業務程式碼的配置,將舊域名和埠替換成新域名和埠(需要將 old.tdb.com:4000 替換成 new.tdb.com:15002 ),這時候再修改配置重啟業務影響面會比較小。

五、寫在最後

本文件僅做經驗分享,避坑指南,因使用場景各異,各自環境也不同,在遷移過程中還可能碰上其他問題。<font color='red'>如有線上環境操作需求,請在測試環境充分測試。</font>

相關文章