一、前言
承载重要业务的 OLTP 系统,受监管等要求一般需要保持 7*24h 运行,年计划停机时间几乎没有。如银行的交易系统,其计划内的停机窗口需要向上级主管部门报备,审批严格,过于频繁的停机窗口也会严重影响交易系统的服务质量。
通过应用服务配合,TiDB 能够做到在线无损升级。
二、常见的 OLTP 系统升级方式
应用服务一般采用分布式部署(一般是 3 台),可以采用滚动升级的方式进行在线升级,滚动升级中不会丢失交易。
单机 DBMS 一般通过主备切换(Oracle DG,DB2 HADR,AS/400 OMS等)的方式进行滚动升级。
TiDB 可以通过 TiUP 进行集群滚动升级,但精细程度还达不到业务无损的要求,尤其是升级 TiDB Server 时会造成大量请求失败。
三、升级 TiDB 集群的常见问题
TiUP 提供了较为粗犷的滚动升级功能,在线业务中使用该脚本会面临以下几个问题。
1. SQL 请求失败
滚动升级TiKV的过程中导致SQL请求失败的常见原因:
升级中正在被访问的 region leader 被强制中止,导致这个 TiDB 发来的 kv 请求被 backoff,被 backoff 回 TiDB 的 kv 请求在默认配置下会自动重试,默认重试次数上限为 10 次,滚动升级 TiKV 时使用了 evict-leader 调度,该调度会主动将正在升级的 TiKV 上的 leader 主动迁移走,此时 backoff 的请求一般重试一次即可成功访问到新的 leader。但需要注意的是,默认配置下,evict-leader 调度最多会执行 120s,达到超时时间 TiKV 就会被强制中止,如果在这个时间内有 leader 还没有来得及被调度走,那么就会发生 region leader 的被动选举,leader 选举耗时一般在 10~20s,期间有可能会出现 SQL 请求失败。在升级 Region 较多的集群时可能会面临此问题,可以通过增加 --wait-timeout 参数来设置超时时间。
滚动升级PD的过程中导致SQL请求失败的常见原因:
PD 负责全局唯一且顺序递增的事务号 tso 的生成和 region 元信息的维护,PD leader 被强制中止时会导致整个集群不可用,通过 raft 被动重新选出 PD leader 一般需要 10s 左右的时间。一次滚动升级中,会发生多次 leader 被强制中止。
滚动升级TiDB的过程中导致SQL请求失败的常见原因:
滚动升级时,TiDB 提供 graceful shutdown 功能,可以在拒绝处理新 SQL 的同时等待当前正在运行的 SQL 执行完成之后再停止服务,由于应用连接池或负载均衡器还连接到这台已经被停止的 TiDB 上,这会导致大量的请求失败,当负载均衡器识别到该 TiDB 不可用时,才会将连接迁移到其他可用的 TiDB 上。另外需要注意的是,TiDB 无法保障到事务级别的 graceful shutdown,会造成有些事务的回滚。另外当今的 OLTP 系统一笔交易往往是被拆分成为多个数据库事务的,使用滚动升级脚本升级 TiDB 可能会造成某些交易的一部分成功提交,另一部被拒绝执行的异常状态。据某用户反馈,应用通过负载均衡器(F5)连接了 6 台 TiDB,滚动升级 TiDB 过程中的整体失败率为 8%(根据失败交易笔数和升级期间总交易笔数计算得到)。
2. 升级前后版本不兼容导致升级失败
一般而言,低版本的 TiDB 是可以在线升级到高版本的,尤其是大版本号(如 2.1.x)相同的版本之间,默认是相互兼容的。但历史上出现过某些版本因存在兼容性问题而无法在线升级,如:
- 0.9 到 1.0 版本调整了数据结构,只能做进行停机的数据导入导出升级。
- 2.0 到 2.1 tidb-binlog 架构做了重大调整,在 2.0 版本上开启了 tidb-binlog 的集群需要进行停机升级,以切换到新版 tidb-binlog 架构。
大部分相临近的版本之间是可以进行在线回退操作的,除了上面一段提到的无法再现升级的版本之外,历史上还出现过某些版本由于内部组件升级或开启了某些旧版本不支持的功能之后,会导致无法在线回退版本,如:
- grpc 升级,无法通过一般方法降级。
- PD etcd 升级,无法通过一般方法降级。
- 升级到高版本集群打开 region merge 之后,无法通过一般方法降级。
针对以上情况,通常我们会在 PingCAP 官网(文档->操作指南->升级)上发布升级指南,升级之前请参考官网发布的信息。
3. 未制定升级失败的回退计划
为应对升级中的种种异常状况(如升级后集群无法正常工作;达到限制时间尚未完成升级操作等),往往需要制定回退计划,并为回退计划留有足够的操作时间,回退计划包括在线回退,停机回退,数据重新导入恢复等。
生产集群的版本升级需要在测试环境上充分演练后进行。
四、升级前的准备及非核心组件的升级
1. 升级前的准备工作
- 规划升级时间窗口,应包含回退计划,为回退计划保留足够时间;
- 确保升级前后版本的兼容性。
- 备份 TiUP 的元信息文件 .tiup/storage/cluster/clusters/test_cluster/meta.yaml
2. 周边工具的升级
周边工具如 DM,Drainer,Reparo 等的升级如果没有特别的可用性要求,都可以离线完成,升级要点如下:
- 确认新版程序与 TiDB 集群,Pump 等组件相互兼容。
- 明确当前运行程序的所在位置,是配置在环境变量里还是使用绝对路径,避免升级错目标。
- 不要轻易用替换的方式覆盖原有程序,尽量就地备份旧版程序,以供回退或排查问题使用。
五、TiDB 集群核心组件的在线升级
1. 组件升级顺序
一般依照先升级 PD,再升级 TiKV 和 TiDB/Pump 的顺序进行升级,原因如下:
- 服务依赖的拓扑关系为 TiDB 依赖 TiKV 和 PD,TiKV 依赖 PD 和 其他 TiKV。
- PD 在更新版本时一般是向下兼容的,更新的时候需要先升级被依赖的组件。比如 PD 添加了功能 x 给 TiDB 用,如果先升级 TiDB 的话会出现新的 TiDB 使用 x 功能,但是旧的 PD 还没这个功能,先升级 PD 的话则没这个问题。
另外需要注意:PD 经常更新其中集成的 etcd 代码,有些时候会导致无法向下兼容的问题,应准备好回退工具及方案。
2. 升级 PD 集群
PD 集群由 PD leader 对外提供服务,transfer PD leader 的过程中会导致短时的集群不可用*,升级 PD 集群的要点是尽量减少 leader transfer 次数。升级步骤如下:
- 确认 PD 服务器的时间完全一致(重要),新旧 leader 的时差会增加 TiDB 集群的不可用时间。
- 升级非 leader 的 PD。
- 通过 pd-ctl transfer leader 到另外一个优先级较高的 PD 上。
- 升级前 PD leader。
*注:升级 PD 会导致集群短时(一般在秒级或以下)不可用,是现阶段无法克服的问题。
3. 升级 TiKV 集群
TiKV 集群可以做到完全的无缝升级,升级要点如下:
- 升级前明确集群规模,了解 TiKV 中 region 的数量级。
- TiUP 会检测 tikv-server 中的全部 leader 都 transfer 到其他 tikv-server 后再进行升级操作,检测过程的默认超时时间为 120s,如果单一 tikv 上 region 较多(100k+ regions),可以适当调整超时设置
tiup cluster upgrade test_cluster --wait-timeout 1800 - 由于 TiKV 升级时要先 transfer 其上的 region leader,TiKV 数量较多的集群升级耗时会比较久,升级中注意观察监控及 playbook 的返回信息,确保升级顺利完成。
4. 升级 TiDB
贸然升级 TiDB server 会导致其上的全部连接断开,以及正在处理的请求全部失败回滚,TiDB 的无缝升级需要有滚动升级能力的分布式应用服务配合,典型升级方案如下:
- 创建一个新版本的 tidb-server,或升级集群中非业务访问的现有 tidb-server(如备份用的 tidb-server)。
- 修改负载均衡器配置(或 DNS 配置)到这个单独的 tidb-server 上,此时只是修改了配置,应用依然能通过已有连接访问到旧版 tidb-server 上执行。
- 循环重启应用服务,一轮重启之后应用连接都集中到了单独的 tidb-server 上。
- 确保业务用 tidb-server 上没有连接和请求之后,滚动升级这些 tidb-server。
- 修改负载均衡器配置(或 DNS 配置)到业务使用 tidb-server 上。
- 循环重启应用服务,确保单独的 tidb-server 上不再有业务连接和请求。
目录