作者: GreenGuan
为什么要升级?
- 低版本 TiDB 周边组件支持不完善,如低版本的 cdc 的支持并不完善,有内存泄露问题等;
- 实际工作中触发过 TiDB 的 panic bug;
- 在降本增效的大背景下,提升 TiDB 的性能或吞吐量;
- 为社区贡献实际业务场景;
如何升级?
TiDB 的升级分为停机升级和不停机升级,不停机升级又分平滑升级和强制升级(–force),下面简单说明下过程,不对细节过多展开,只介绍核心:
强制升级:
- 下载对应版本软件到目标主机上
- Upgrading component pd
- Upgrading component tikv
- 替换软件,不做leader选举,直接重启tikv server
- Upgrading component tidb
- 在升级tidb节点时,在该tidb上的所有会话将会断开
- Upgrading component prometheus,grafana,alertmanager
优点:
- 时间短(笔者做过测试,重启一个200G左右的tikv节点耗时1分钟左右)
- 升级结果可控
风险:
- 该升级方式强制升级,升级过程中,如果前端应用请求的leader正好重启,则会有读写失败的情况发生
- 在4步失败时,程序需要有重连机制
平滑升级:
- 下载对应版本软件到目标主机上
- Upgrading component pd
- Upgrading component tikv
- 在升级tikv时会滚动驱逐leader(超时默认10分钟,可调),后重启该节点
- Upgrading component tidb
- 在升级tidb节点时,在该tidb上的所有会话将会断开
- Upgrading component prometheus,grafana,alertmanager
优点:
- 该升级方式为平滑升级(前提是该节点上的leader可以在规定时长内驱逐完毕),不会有读写失败的情况发生(tidb组件重启时除外)
风险:
- 升级时间较长,举个例子如果有3pd,3tidb,100tikv,那么滚动升级的时间至少为 100(节点数量) * 10m(默认超时时间) + pd + tidb + 监控,我们假设 pd + tidb + 监控的升级时长为 10m,那么升级的总时长为 16h
- 如果在3.1步失败时,群集的版本状态有可能是 一部分新版本,一部分旧版本(笔者曾经遇到过的pd节点为v540 tikv 节点为 v409,好在没出什么问题)
- 在 4 步失败时,程序需要有重连机制(同上)
停机升级:
- 关闭 TiDB 整个实例 (所有组件)
- 软件下载及替换
- 启动 TiDB 实例
**风险:**简单的说就是停服维护
- 要通知前端业务,做好接口或程序侧的异常捕获,不要让error日志暴增而导致的前端应用崩溃
- 在停机维护时一定要做好主机硬件检查,主要有硬盘,内存,主板,电源等,如果能关不能开那就尴尬了,避免黑天鹅事件
我们大致总结下每种升级方式的优缺点如下:
优点 | 风险 | |
平滑升级 | 大部分业务读写不会失败 | 升级时间长升级结果不可控 |
强制升级 | 升级时间短升级结果可控 | 部分业务读写失败 |
停机升级 | 升级时间短升级结果可控 | 业务在升级时不可用 |
具体可参见官方文档,里面写的很清楚,连接如下:
https://docs.pingcap.com/zh/tidb/v5.4/upgrade-tidb-using-tiup
升级前后关注的核心问题
- 寻找适合的回退方案
- SQL兼容问题
- 性能回退问题
寻找适合的回退方案
原生的 TiDB 升级没有回退方案,如果需要回退方案,可以有如下方案参考:
技术实现 | 优点 | 缺点 | 备注 | |
方案一 | 备份 / 恢复 | - 数据可反复使用 | ||
- 运维成本低 | - 恢复时间长 | |||
- 无法快速回退,需要业务补数 | 适用于对cdc功能不完善的业务 | |||
方案二 | TiDB 从库 | 数据准实时同步 | 有维护etl工具的成本 | 可用pump或ticdc等工具 |
方案三 | 业务双写 | - 数据准实时同步 | ||
- dba运维成本低 | 可能破坏事务原子性 | |||
方案四 | 无回退方案 | - | - | - |
方案一:备份/恢复
方案二:TiDB从库
方案三:业务双写
方案四:无回退方案
SQL兼容问题
一般笔者常用的有如下三个方案,来规避升级高版本后的SQL不兼容问题,我给他起名叫“三板斧”:
方案一:mysql-replay 工具回放
mysql-replay工具git:https://github.com/innerr/workload-sim.tidb.ticat.git
方案二:阅读 TiDB changelog
方案三:业务参与
性能回退问题
方案一:手动收集统计信息
方案二:执行计划重绑
PS:5版本有一个叫自动捕获执行计划的功能,既系统自动捕获并绑定最近一次执行计划然后存储在系统表中,这个功能需要根据自己的业务场景斟酌是否打开;
升级 Check Point
前期准备
Check Point | 说明 |
测试升级TiDB所需耗时 | 选择升级方式进行测试(停机,强制,平滑) |
调研回退方案 | 方法如上:寻找适合的回退方案 |
验证回退方案 | 建议与业务方配合验证回退方案的可行性 |
检查主机状态并提前修复 | 检查cpu,内存,主板,磁盘的健康状态 |
SQL兼容性检查 | 方法如上:SQL兼容问题 mysql-replay工具、阅读 TiDB changelog、业务参与 |
防止性能回退 | 方法如上:性能回退问题 手动收集统计信息、执行计划导出 |
tiup 工具升级 | tiup 工具本身升级到最新版本,而非集群 |
与原厂工程师前期沟通 | 建议升级前和原厂工程师沟通升级计划 |
与业务方沟通升级方案 | 周知上下游,对有操作的务必做到责任到人,按时操作 |
积累升级经验 | 多升级非核心业务线集群,为重要升级积累经验 |
实施过程
Check Point | 说明 |
收集集群各指标 | 为对比升级前后负载差异,使用 clinic 工具 tiup diag collect --from “2022-07-13 00:00:00” --to "2022-07-14 00:00:00" --include system,config,monitor |
确认回退方案部署完毕 | DBA确认集群可用性与恢复时间点 业务确认业务数据可用 |
周知业务方停 DDL | 升级期间不要对表结构进行变更 |
上下游业务确认 | 确认上下游业务在升级前是否结束、切换或停止 |
停自动收集统计信息 | MySQL client: set global tidb_auto_analyze_start_time = '23:57 +0800'; set global tidb_auto_analyze_end_time = '23:58 +0800'; |
导出执行计划 | 可写脚本导出,假设叫sqlbind.sql |
预检查 region 副本 | pd-ctl: region --jq=".regions[] | {id: .id, peer_stores: [.peers[].store_id] | select(length != 3)}" PS:如果有副本丢失问题(无leader)则需停止升级,先解决副本问题 |
暂停 region 调度任务 | pd-ctl: config set region-schedule-limit 0; config set merge-schedule-limit 0; config set replica-schedule-limit 0; |
预检查 ssh 连通性 | tiup cluster exec xxx --command id |
升级 TiDB | tiup cluster upgrade xxx v5.x.x or tiup cluster upgrade xxx v5.x.x --force |
导入执行计划 | 导入并检查执行计划是否生效 source sqlbind.sql show global bindings; |
开自动收集统计信息 | 根据自己业务场景设定时间 MySQL client: set global tidb_auto_analyze_start_time = '23:57 +0800'; set global tidb_auto_analyze_end_time = '23:58 +0800'; |
手动设置参数提升性能与兼容性 | set global tidb_enable_async_commit = ON; set global tidb_enable_1pc = ON; set global tidb_multi_statement_mode = ON; set global tidb_enable_noop_functions = 1; set config tikv |
业务验证读写 | 需要业务方重启一下服务,应用新配置,验证是否有SQL不兼容问题 风险点:可能会启用回退方案 |
验证性能是否符合预期 | 与业务方一起判定是否有性能回退现象 风险点:可能会启用回退方案 |
备份新版本数据库 | 如果是用 br 备份建议在大版本升级后,用新版本的 br 全量备份一下数据库, 保持工具和db的版本统一 |
收集集群信息 | 官方提供工具 clinic 以供升级前后对比 |
后期跟进
Check Point | 说明 |
更新备份脚本 | 新版本 TiDB br备份改造 |
更新慢日志收集脚本 | 版本 4 与版本 5 的慢日志有些许差异,如果有logstash 收集的话需要修改一下正则匹配 |
案例分享
案例一、4PD 节点导致的升级失败
案例背景:
问题排查:
那么问题来了,请问4 pd 达到多数派同意了么,答案必然是没有,核心问题是有一个节点没投出来票,只有半数同意,所以导致leader无法竞选成功,最终升级失败;
解决方案:
案例二、集群A升级经验分享
案例背景:
面临的挑战:
- 集群规模大:规模大指的有两方面,一来TB级别的存储,二来节点数较多 TiDB 20+,TiKV 40+
- 维护窗口短:A集群白天承接 TP 类业务,晚上有 AP 类业务或业务抽数,在升级时业务方要求db不能停;
- 回退方案落地难:我们选择的回退方案是备份恢复,备份结果不稳定(后续会详细说明),并且第一次恢复用了86个小时;
- 集群A涉及的上下游较多,需要解决SQL兼容性问题:几乎牵扯到所有的业务线
- 性能回退:未升级时不确定是否会产生性能回退问题
制定升级方案:
PS:如果遇到 br 备份到自建 S3 失败时,首先需要检查一下 TiDB 的状态,如果正常那么大概率是 s3 不稳定造成的,我总结的报错集锦如下:
PS:v4.0.1 的 br 备份工具比 v4.0.16 的要 40% 左右,我感觉可能是 v4.0.16在校验部分做了更多的工作,v4.0.1 的 br 恢复与 v4.0.16 处理逻辑也不一样,尤其是对 分区表 ddl 功能,v4.0.1 能成功 v4.0.16 报错 [error="[ddl:-1]json: cannot unmarshal array into Go value of type string"]
升级流程:
升级后的收益:
- 升级后给我最大的感受是,5版本比4版本更稳定,尽可能去避免抖动产生的性能问题
Query summary 在相同时段 TiDB 内部自动执行的 SQL 语句 999 分位 由之前的4s 稳定在125ms左右提升了 97% ,并解决了性能抖动问题
- CPU方面的性能提升,Raft Store CPU升级后都在报警阈值以下运行
- 写性能能提升: 相比 v4.0.1 TiKV 对 gRPC 模块进行了优化,优化了 Raft 日志复制速度,降低了 Commit Log Duration 和 Store Duration。
Avg Duration | v4.0.1(µs) | v5.4.1(µs) |
Append Log Duration | 45 | 197 |
Commit Log Duration | 839 | 522 |
Apply Log Duration | 150 | 129 |
业务方反馈:
简单提一下 5版本带来性能收益,我们从读写两方面来解读
写:异步提交事务 (Async Commit) 与 1pc 提交,异步事务主要解决的是降低事务提交的延迟,1pc提交指的是只涉及一个 Region 的事务会大幅降低事务提交延迟并提升吞吐;
读:默认开启 Coprocessor cache 功能 降低读取数据的延时;
降低性能抖动:开启 GC in Compaction filter 功能,我理解是在冷数据compation 为sst的同时做GC,减少单独的GC worker做GC时的读MVCC版本时的压力;