高并发请求下 TiDB 集群的业务无损升级
作者: Gin 原文来源:https://tidb.net/blog/11faa0a5
【是否原创】是
【首发渠道】TiDB 社区
目 录
一、前言
二、常见的联机交易系统升级方式
三、升级 TiDB 集群的常见问题
SQL 请求失败
升级前后版本不兼容导致升级失败
未制定升级失败的回退计划
四、升级准备及非核心组件的升级
升级前的准备工作
周边组件的升级
五、TiDB 集群核心组件的在线升级
核心组件升级顺序
使用 tiup cluster patch 操作各组件分别升级
升级 PD
升级 TiKV
升级 Pump
升级 TiDB
一、前言
承载重要业务的联机交易系统,受可用性和监管等要求一般需要保持 7*24h 运行,年计划停机时间几乎没有。如银行的交易系统,其计划内的停机窗口需要向上级主管部门报备,审批严格,过于频繁的停机窗口也会严重影响交易系统的服务质量。
二、常见的联机交易系统升级方式
主流的应用服务一般采用分布式部署(3 个实例以上),具备热插拔能力,在线滚动升级过程中不会引起交易失败或交易丢失。
单机 DBMS 一般通过主备单独升级结合主备切换(Oracle DG,DB2 HADR,AS/400 OMS 等)的方式进行滚动升级,当中切换的过程不可避免的需要应用停机。
TiDB 可以通过 tiup cluster upgrade 命令进行集群滚动升级,但精细程度还达不到业务无损的要求,尤其是升级 TiDB Server 时会造成大量请求失败。
三、升级 TiDB 集群的常见问题
1. SQL 请求失败
使用 TiUP 运维的集群,在使用 tiup cluster patch 命令进行 PD 与 TiKV 的升级时,不会引起交易失败,只会在升级 PD 的过程中引起 1s 左右的全局 SQL 延迟略微增加。
这得益于调度机制,TiDB 可以控制 PD 及 TiKV region 的 raft leader (PD 需要部署 3 个或 5 个实例)在成员之间进行主动 transfer,加以 TiDB 的 backoff 机制,可以将 SQL 层面的影响控制在延迟略微增加的程度,而不会引起 SQL 失败。
升级 TiDB 集群引起交易失败的主要因素在于升级 tidb-server 的过程中数据库连接会被强制断开。
虽然 tidb-server 具备 graceful shutdown 特性,可以在拒绝处理新 SQL 的同时等待当前正在运行的 SQL 执行完成之后再停止服务,但由于应用连接池或负载均衡器还连接到这台已经被停止的 TiDB 上,这会导致大量的请求失败,当负载均衡器识别到该 TiDB 不可用时,才会将连接迁移到其他可用的 TiDB 上。另外需要注意的是,TiDB 无法保障到事务级别的 graceful shutdown,会造成有些事务的回滚。另外主流应用处理一笔交易往往需要多个数据库事务,使用滚动升级脚本升级 TiDB 可能会造成这种交易的一部分成功提交,另一部被拒绝执行的异常状态。
2. 升级前后版本不兼容导致升级失败
一般而言,在不考虑可用性要求的前提下,低版本的 TiDB 是可以直接滚动升级到高版本的,尤其是具有相同 minor 版本号的 patch 版本之间(如 5.1.3,其中 5 被称为 major 版本,5.1 被成为 minor 版本,5.1.3 被成为 patch 版本)。但也存在高版本不向下兼容的案例,如:
0.9 到 1.0 版本调整了数据结构,只能做进行停机的数据导入导出升级。
2.0 到 2.1 tidb-binlog 架构做了重大调整,在 2.0 版本上开启了 tidb-binlog 的集群需要进行停机升级,以切换到新版 tidb-binlog 架构。
如非官方特别声明,相同 major 版本号的 patch 版本是相互兼容的,可以回退到相同的 minior 版本的其他 patch 版本上。但也出现过某些版本由于内部组件升级或开启了某些旧版本不支持的功能之后,导致无法回退案例,如:
grpc 升级,无法通过一般方法降级。
PD etcd 升级,无法通过一般方法降级。
升级到高版本集群打开 region merge 之后,无法直接降级到原版本。
针对以上情况,PingCAP 会在官网上发布升级指南,升级之前请参考官网发布的信息。
3. 未制定升级失败的回退计划
为应对升级中的种种异常状况(如升级后集群无法正常工作;达到限制时间尚未完成升级操作等),往往需要制定回退计划,并为回退计划留有足够的操作时间,回退方式包括在原有集群直接回退,主备集群回退,恢复备份数据回退等。
生产集群的版本升级和回退都需要在测试环境上充分演练后进行。
四、升级准备及非核心组件的升级
1. 升级前的准备工作
规划升级时间窗口,应包含回退计划,为回退计划保留足够时间;
确保升级前后版本的兼容性。
备份 tiup 的元信息文件
.tiup/storage/cluster/clusters/test_cluster/meta.yaml
2. 周边组件的升级
周边组件如除 Pump(Pump 须作为核心组件进行升级)之外的 Data Platform 组件(DM,TiCDC,Drainer,Reparo 等),ctl 组件(pd-ctl,tikv-ctl,dm-ctl,binlog-ctl 等)以及 tiup 自身的升级如果没有特别的可用性要求,都可以离线完成,升级要点如下:
确认新版周边工具与当前版本的 TiDB 集群,Pump 等组件相互兼容,以便于优先离线升级周边组件。
使用 patch 的方式升级 Data Platform 组件
tiup cluster patch -R <role>
升级 tiup
tiup update --self
升级 ctl 类组件
tiup install ctl:<version>
升级 tiup 其余离线组件
tiup update --all
不要轻易用替换的方式覆盖原有程序,尽量就地备份旧版程序,以供回退或排查问题使用。(tiup 会自动对旧版本 binary 做归档)
五、TiDB 集群核心组件的在线升级
1. 核心组件升级顺序
TiDB 集群核心组件除了 TiDB,PD,TiKV 之外,还包含 TiDB-Binlog 中的 Pump,这是由于当启用了 TiDB-Binlog 功能后,Pump 将和 TiKV 进行同步提交,且在默认配置下(ignore-error=false)Pump 发生整体故障会导致 TiDB 无法对外提供服务。
对于核心组件,需要依照先升级 PD,再升级 TiKV,最后升级 TiDB+Pump 的顺序进行升级,原因如下:
服务依赖的拓扑关系为 TiDB+Pump 依赖 TiKV 和 PD,TiKV 依赖 PD 和 其他 TiKV。
PD 在更新版本时一般是向下兼容的,更新的时候需要先升级被依赖的组件。比如 PD 添加了功能 x 给 TiDB 用,如果先升级 TiDB 的话会出现新的 TiDB 使用 x 功能,但是旧的 PD 还没这个功能,先升级 PD 的话则没这个问题。
PD、TiKV 以及 Pump 的在线滚动升级无需外部配合,而 TiDB 的升级则需要负载均衡器和应用的配合才能达成在线无损升级,因此建议将 PD、TiKV 和 Pump 升级到目标版本后,择期对 TiDB 进行升级。
另外需要注意:PD 经常更新其中集成的 etcd 代码,历史上曾经出现过由于新版本 etcd 的问题导致 PD 无法向下兼容,应充分测试并准备好回退工具(如 PD 重建工具 pd-recover)及回退方案。
2. 使用 tiup cluster patch 操作各组件分别升级
由于 tiup cluster upgrade 只能一次升级集群的所有组件,不支配置 -R 参数来升级特定的组件,也不支持配置 -N 参数升级特定的实例。因此需要采用 tiup cluster patch 的方式将特定组件的新版本 binary 通过 patch 的方式进行依次升级。使用方法请参考 tiup cluster patch | PingCAP Docs
3. 升级 PD
PD Leader 负责全局唯一的事务号 tso 的发放,因异常导致 PD Leader 丢失时,PD 会发生被动的重新选举,一般需要 10s 左右选出新的 Leader,在此期间整个集群无法提供服务。而通过 pd-ctl 的 member leader transfer 功能主动切换 PD Leader 时,这个不可用的窗口可以被控制在 1s 以内,再借助 TiDB 的 backoff 机制,这个短暂的不可用不会引起 SQL 失败,对于应用服务层面的影响是短时的 SQL 响应时间延长和 TPS 下降。
tiup 已经集成了 pd-ctl 的主动切换 PD Leader 的功能,可以通过 tiup cluster patch 的方式进行 pd-server 版本的滚动升级,参考下例:
tiup cluster patch sa2 patch/pd-hotfix-linux-amd64.tar.gz -R pd --overwrite --transfer-timeout 3600
需要注意该命令在不同版本的 tiup 的行为略有差别:
tiup 1.4.0 之前的版本: tiup 顺序升级 PD,有概率发生两次 PD Leader 切换。
tiup 1.4.0 及之后的版本:tiup 会优先升级非 Leader 的 PD,最后才执行 PD Leader 切换来升级最后一个 PD,只会发生一次 PD Leader 切换,降低升级 PD 对交易延迟造成的影响。
4. 升级 TiKV
TiKV 是一个 Multi-Raft 系统,相较于升级 PD 时只会发生一个 PD Leader 切换,在线对 TiKV 进行升级的时候,会发生非常多的 region leader 切换。与 PD 一样,通过 PD 的 region leader 调度做主动切换时,不会对集群的可用行造成影响。但当某个 TiKV 实例由于异常停止,剩余存活的 TiKV 完成全部受影响的 region leader 选举的耗时一般需要 10~20s。
tiup 在升级某个 TiKV 实例时,会首先对这个 TiKV 增加 evict-leader 调度,意图迁移走其上的 region leader,但在默认配置下 tiup 不会等待太久,一旦达到 tiup 的超时时间,tiup 就会强制杀死该 TiKV 实例执行升级操作,这将引起交易失败。在升级实例 region 较多的集群时可能会面临此问题,可以通过增加 --transfer-timeout 3600
参数来设置升级每个 TiKV 的超时时间为 1 小时来避免此问题。
TiKV 数量较多的集群升级耗时会比较久,升级中注意观察监控及命令的屏幕返回信息,确保升级顺利完成。参考下例滚动升级整个 TiKV 集群:
tiup cluster patch sa2 patch/tikv-hotfix-linux-amd64.tar.gz -R tikv --overwrite --transfer-timeout 3600
5. 升级 Pump
在开启了 TiDB-Binlog 的集群中,事务提交需要同步在 Pump 和 TiKV 中持久化。在默认配置下(ignore-error=false
),当所有 Pump 不可用的时候,由于事务无法同步在 Pump 中落实,TiDB 将停止对外服务以保障 TiDB-Binlog 的数据完整性。
因此在升级 Pump 时,需确保在升级过程中时刻至少有一个 Pump 可用。参考下例滚动升级整个 Pump 集群:
tiup cluster patch sa2 patch/pump-hotfix-linux-amd64.tar.gz -R pump --overwrite
6. 升级 TiDB
贸然升级 TiDB 实例会导致其上的全部连接断开,正在处理的请求全部失败回滚,在线升级 TiDB 需具备滚动升级能力的分布式应用服务配合,典型升级方案如下:
扩容一个或多个(视业务负载而定)新版本的 TiDB 实例,或升级集群中配备的人工操作使用的不承载生产交易的 TiDB 实例。
修改负载均衡器(LB)配置,增加该 TiDB 实例为 LB 后端节点,之后会有请求发送到该 TiDB 实例上。
修改 LB 配置,摘除原有的全部 TiDB 实例,注意 LB 只是标记摘除这些后端节点,并不再在这些节点上建立新的连接,LB 不会断开现有连接,应用依然能通过已有连接访问到这些低版本 TiDB 实例。
滚动重启全部应用服务,重启后的应用实例建立的新连接只会发送到新版本的 TiDB 实例上。
确保所有低版本 TiDB 实例上没有连接和请求之后,使用
tiup cluster patch -N
升级这些低版本 TiDB 实例。参考下例升级多个 TiDB 实例:
tiup cluster patch sa2 patch/tidb-hotfix-linux-amd64.tar.gz -N 192.168.1.8:5000,192.168.1.8:5001 --overwrite
修改 LB 配置,增加这些刚刚升级好的 TiDB 实例为 LB 后端节点,之后会有请求发送到该 TiDB 实例上。
修改 LB 配置,标记摘除步骤 2 增加的后端节点。
滚动重启全部应用服务,确保步骤 2 增加 TiDB 实例上不再有业务连接和请求。
版权声明: 本文为 InfoQ 作者【TiDB 社区干货传送门】的原创文章。
原文链接:【http://xie.infoq.cn/article/c2f7b156ef3046762e542e33a】。文章转载请联系作者。
评论