写点什么

tidb 2.1 升级到 4.0 操作文档

  • 2022 年 7 月 11 日
  • 本文字数:10213 字

    阅读完需:约 34 分钟

作者: sustyle 原文来源:https://tidb.net/blog/c6adb7b4

一、前言

    线上 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、旧集群环境介绍

  • 已有的组件



  • 未列举的组件表示未启用该组件,因历史原因,集群并没有启用 pump 组件。

  • 端口规划也没什么规律


  • 预计增加的组件


| 角色 | 数量 | 端口 || ——- | – | —– || pump | 3 | 23001 || drainer | 1 | 24001 |

2、旧集群访问信息

3、新集群环境介绍


  • 端口采用 2+3 的格式,前两位是组件编号,后三位表示集群编号。即后三位一样的表示同一个集群,前两位一样表示同一个组件。

4、新集群访问信息

三、流程介绍

  • 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 -ppasswordmysql> select distinct host from information_schema.processlist
复制代码


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


ansible # /opt/soft/mysql57/bin/mysql -u root -h old.tdb3 -P 4000 -ppasswordmysql> 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 组件的监控

  • 添加 pump 组件

  • pump 端口设置及启用 binlog 参数


如果不设置 enable_binlog = True,在部署 pump 的时候会被忽略。另外需要注意,在 pump 能提供服务前,不能重新加载 tidb 的配置并重启,否则会导致业务写操作失败。


(2)编辑 pump 的配置


ansible # vim /path/github/tidb-ansible-2.1.8/conf/pump.yml
复制代码


  • 修改 binlog 保存周期


改成 14 天,避免全量数据导入时间过长导致增量数据丢失(binlog 被清理)。


(3)登录目标机器创建目录


    登录各个 pump 节点创建目录及更改权限


ansible # ssh pump1pump1   # mkdir -p /path/tidb-data/pump-23001pump1   # chown -R tidb. /path/tidb-data/pump-23001
复制代码


ansible # ssh pump2pump2   # mkdir -p /path/tidb-data/pump-23001pump2   # chown -R tidb. /path/tidb-data/pump-23001
复制代码


ansible # ssh pump3pump3   # mkdir -p /path/tidb-data/pump-23001pump3   # 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 -ppasswordmysql> 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 pumpsINFO[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 节点




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 -ppasswordmysql> 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 | shansible # . /root/.bash_profileansible # tiup --versionansible # 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.yamlansible # tiup cluster deploy tidb-oltp-xxx-v4.0.13 v4.0.13 topology-oltp-xxx.yamlansible # tiup cluster start tidb-oltp-xxx-v4.0.13ansible # tiup cluster display tidb-oltp-xxx-v4.0.13
复制代码



(5)权限维护


ansible # /opt/soft/mysql57/bin/mysql -u root -h new.tdb.com -P 15002 -pmysql> 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 -ppasswordmysql> 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/xxxansible # cat metadata 
Started dump at: 2021-08-29 15:34:30SHOW MASTER STATUS: Log: tidb-binlog Pos: 425971435565482001 GTID:
Finished dump at: 2021-08-29 15:34:33ansible #
复制代码


(2)修改配置文件


ansible # vim /path/github/tidb-ansible-2.1.8/inventory.ini
复制代码


  • 添加 drainer 组件的监控

  • 添加 drainer 组件

  • drainer 端口设置


(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' statusdetect-interval = 10
# syncer Configuration.[syncer]
# disable sync these schemaignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql"
# number of binlog events in a transaction batchtxn-batch = 2000
# work count to execute binlogsworker-count = 32
disable-dispatch = false
# safe mode will split update to delete and insertsafe-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 drainer1ansible # 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 -ppasswordmysql> 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 drainer1ansible # 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 -ppasswordmysql> 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 drainersINFO[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.gitansible # cd check_data_for_mysql
复制代码


(2)修改配置


  • 编辑配置文件


请结合实际情况根据注释提示进行相关配置


  • 修改工作路径


(3)测试用例


  • 每次执行校验任务的时候强制要清空 log 目录,所以请做好校验结果的备份

  • 执行校验任务的时候强烈建议开启 screen

  • 有网卡监控需求,执行监控脚本时也强烈建议单独开启 screen 进行监控


    第一步:先开启一个 screen 监控网络


ansible # screen -S check_net_4000ansible # 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_4000ansible # 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 -ppasswordmysql> 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/bashport=4000mysql_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)写旧库,读新库,可能会读不到,因为旧库跟新库之间存在延迟。


    3)避免不了双写,可能会导致下面的问题。


  • 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 之内),这过程集群不可用。


    完成上述操作后,旧集群的访问信息会变成如下表:



    这时候业务需要挨个更新业务代码的配置,将旧域名和端口替换成新域名和端口(需要将 old.tdb.com:4000 替换成 new.tdb.com:15002 ),这时候再修改配置重启业务影响面会比较小。

五、写在最后

    本文档仅做经验分享,避坑指南,因使用场景各异,各自环境也不同,在迁移过程中还可能碰上其他问题。如有线上环境操作需求,请在测试环境充分测试。


发布于: 刚刚阅读数: 2
用户头像

TiDB 社区官网:https://tidb.net/ 2021.12.15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
tidb 2.1升级到4.0操作文档_迁移_TiDB 社区干货传送门_InfoQ写作社区