作者:莫善
某互聯網公司高級 DBA。
本文來源:原創投稿
一、前言
線上tidb集羣都是2.1.[5,7,8,17],因版本太低,面臨諸多問題,比如管理難度大,熱點問題,執行計劃失效,性能瓶頸,其他已知/未知且無法解決的問題,現在需要升級至4.0.13版本。在調研後發現,如果原地升級將需要多次升級【2.1--> 3.0 --> 4.0】,擔心原地升級遇到不可逆的故障,更擔心的是解決不掉而影響業務,所以經過測試和評估,最終採用數據遷移的方式進行升級。
因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 |
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 |
角色 | 數量 | 端口 |
---|---|---|
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管理機執行
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
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、校驗新舊集羣數據一致性
ansible # git clone https://gitee.com/mo-shan/check_data_for_mysql.git
ansible # cd check_data_for_mysql
編輯配置文件
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的家目錄的絕對路徑
-
每次執行校驗任務的時候強制要清空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日誌,確認沒業務使用舊域名後再下掉。
因可能存在多個業務使用該庫,而且每個服務可能有多臺業務機器,做不到所有服務同一時刻都切到新庫,所以會出現下面幾種情況:
避免不了雙寫,可能會導致下面的問題。
A. 更新同一行數據的兩個連接執行的時間極短(小於舊庫到新庫的同步延遲)。兩個連接是分別在舊庫/新庫執行,這時候該行數據的最終狀態不是以誰最後執行爲準。比如說,先在舊庫執行了【update t set name = 1 where id = 2;】,然後在新庫執行【update t set name = 2 where id = 2;】,理論上這個數據的記錄最終應該是name=2,但是考慮到新庫到舊庫的同步有延遲,這個數據就可能會被舊庫的數據覆蓋變成name=1。如果反過來,先寫新庫,再寫舊庫,這種情況對數據沒影響。
B. 業務的兩個連接在新庫舊庫分別插入同一行數據(主鍵一樣或者唯一鍵一樣的數據),如果先寫新庫,再寫舊庫,這樣在業務端都會提交成功,但是會導致舊庫到新庫的同步失敗,因爲舊庫寫入的數據同步到新庫就會報主鍵衝突(唯一鍵衝突),這時候就需要dba人工干預進行修復。如果反過來,先寫舊庫再寫新庫(不考慮舊庫到新庫的延遲),這時候寫新庫的會話就會報錯,這種情況對數據沒影響。
針對上述的情況,需要業務充分評估。如果不能接受,可以建議業務使用下面的平滑方案,這樣影響面較小。
業務繼續使用 old.tdb.com:4000 這個來連接tidb。
將舊集羣的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 |
五、寫在最後
相關推薦:
MySQL binlog 分析工具 analysis_binlog 的使用介紹
點擊閱讀原文,詳細瞭解SQLE
本文分享自微信公衆號 - 愛可生開源社區(ActiontechOSS)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。