TiDB Server 的优雅下线背景
TiDB 集群包含多个角色,升级重启操作根据角色特点进行专项设计。TiKV Server 属于有状态节点,tiup cluster reload 操作过程包含 region leader 的调度规则,保证重启过程对交易无影响。TiDB Server 属于无状态节点,但是活跃的数据库会话可能有进行中的事务,如果直接重启,交易事务失败会影响交易成功率,给终端用户带来不好的体验。通过应用连接管理和 TiDB Server 的优雅下线的结合,能实现 TiDB Server 的升级重启操作过程对业务的零影响。
设计方案
Java 连接池 hikariCP,连接池 maxlifetime 参数标识一个“连接” 生命周期的上限。当数据库长连接超过 maxlifetime 时间会被标记为过期连接,如果处于非活跃状态会被连接池关闭。负载均衡可以将数据库节点进行“计划内”下线,即原有连接继续保持,但新连接不再连接到下线节点,结合连接池的连接淘汰方式就可以实现连接的“迁移”。
hikariCP 配置示意如下:
hikari:
#连接池最大连接数
maximumPoolSize:60
#连接池名称
poolName:hikariCP
#数据库连接最大生命周期
maxLifetime:600000
#数据库连接超时时间
connectionTimeout:30000
#数据库连接有效性检查时间间隔
keepaliveTime:120000
负载均衡的管理界面进行手工下线
深信服负载均衡的管理界面中将需要单次升级重启服务器上的 TiDB 实例设置为“禁用”,即从 Virtual Server 转发的 Real Server 列表中剥离。
下线节点当前的连接到达 maxlifetime 断开后,新的连接就会转移到其他在线的节点。
监控上只选择三台节点的连接数可以看到,10 分钟内每台 4000 个连接快速下降到接近为 0。仅有少量应用连接未配置 maxlifetime 参数,人工等待到达 15 分钟上限后直接关闭进程,进行后续升级操作。服务恢复后的 10 分钟内,连接开始恢复到正常的水平线。
Haproxy 软负载也具备类似的功能,在图形界面上执行 Set state to DRAIN,能保证现有连接继续使用,但是不再接受新连接。
与负载均衡的探活感知实现联动
TiDB 从 v5.0 版本开始引入 graceful-wait-before-shutdown 特性,在 TiDB Server 等待服务器关闭期间,HTTP 状态会显示失败,使得客户端在等待时间内可以断开连接,并且负载均衡器可以重新路由流量。
将 TiDB Server 的优雅停机时间配置为 630 秒,对应连接池的 10 分钟生命周期。
$tiup cluster edit-config tidb-test1
server_configs:
tidb:
graceful-wait-before-shutdown: 630
tikv: {}
MySQL [(none)]> show config where name like '%graceful%';
+------+------------------+-------------------------------+-------+
| Type | Instance | Name | Value |
+------+------------------+-------------------------------+-------+
| tidb | 10.2.103.12:4100 | graceful-wait-before-shutdown | 630 |
| tidb | 10.2.103.28:4100 | graceful-wait-before-shutdown | 630 |
+------+------------------+-------------------------------+-------+
默认情况下,systemctl 服务的停止服务超时时间为 90s,需要配置为 11 分钟。
tiup cluster exec tidb-test1 --command "cat /etc/systemd/system/tidb-4100.service " -R tidb
tiup cluster exec tidb-test1 --command "sudo sed -i '6 a\TimeoutStopSec=11min' /etc/systemd/system/tidb-4100.service " -R tidb
tiup cluster exec tidb-test1 --command "cat /etc/systemd/system/tidb-4100.service " -R tidb
tiup cluster exec tidb-test1 --command "sudo systemctl daemon-reload " -R tidb
以 Haproxy 软件负载均衡为例,将服务的探测方式修改为 http 检查,检查网址 /status, 检查 10080 端口。
注意:http 检查网址不能使用 /regions/meta 在 SQL 执行过程所需的 API 接口。
listen tidb-test1
bind 0.0.0.0:6000
mode tcp
balance leastconn
option httpchk GET /status
server tidb-1 10.2.103.12:4100 check port 11080 inter 2000 rise 2 fall 3
server tidb-2 10.2.103.28:4100 check port 11080 inter 2000 rise 2 fall 3
正常的服务端口内容和返回值 200 返回如下:
$ curl -w "%{http_code}" 10.2.103.12:11080/status
{"connections":1,"version":"5.7.25-TiDB-v6.5.8","git_hash":"44f39e98a29e19bc00f2d6c1a7ab1609a7a9e822"}200
$ curl -w "%{http_code}" 10.2.103.28:11080/status
{"connections":0,"version":"5.7.25-TiDB-v6.5.8","git_hash":"44f39e98a29e19bc00f2d6c1a7ab1609a7a9e822"}200
Haproxy 探活正常。
使用 tiup cluster 关闭 tidb-server,操作超时参数 --wait-timeout 的默认值为 120 s,需要扩展为 700 秒。服务会等待 630 秒关闭,systemctl 处于 deactivating 状态。
$ tiup cluster stop tidb-test1 -N 10.2.103.12:4100 --wait-timeout 700
Will stop the cluster tidb-test with nodes: 10.2.103.12:4000, roles: .
Do you want to continue? [y/N]:(default=N) y
...
Stopping component tidb
Stopping instance 10.2.103.12
$ systemctl status tidb-4000
● tidb-4000.service - tidb service
Loaded: loaded (/etc/systemd/system/tidb-4000.service; enabled; vendor preset: disabled)
Active: deactivating (stop-sigterm) since Sat 2024-05-18 22:40:23 CST; 5min ago
Main PID: 11643 (tidb-server)
CGroup: /system.slice/tidb-4000.service
└─11643 bin/tidb-server -P 4000 --status=10080 --host=0.0.0.0 --advertise-address=10.2.103.12 --store=tikv --initialize-insecure --path=10.2.103.12:2379,10.2.103.28:2379,10.2.103.64:2379 --log-slow-query=/tidb-depl...
关闭过程中 tidb server 实例 http 检查网址已经返回 500 的内部错误码,regions/meta 仍可以正常工作。tiup cluster display 显示 tidb server 实例为 down。
# curl -w "%{http_code}" 10.2.103.12:11080/status
500
# curl -w "%{http_code}" 10.2.103.12:11080/regions/meta
[
{
"region_id": 2956,
"leader": {
"id": 2959,
...
$ tiup cluster display tidb-test1 -R tidb
Cluster type: tidb
Cluster name: tidb-test1
Cluster version: v6.5.8
Deploy user: tidb
SSH type: builtin
ID Role Host Ports OS/Arch Status Data Dir Deploy Dir
-- ---- ---- ----- ------- ------ -------- ----------
10.2.103.12:4100 tidb 10.2.103.12 4100/11080 linux/x86_64 Down - /tidb-deploy-test1/tidb-4100
10.2.103.28:4100 tidb 10.2.103.28 4100/11080 linux/x86_64 Up - /tidb-deploy-test1/tidb-4100
Haproxy 显示实例 L7 探活返回 500 错误并判断为 down。
连接数监控可以看到,前 20 分钟,四个应用实例的连接正常分发到两个 tidb server 实例上,负载均衡停止失效实例的转发后,应用实例的连接在 maxLifetime 到期后逐渐迁移到存活的实例上。
tidb server 实例正常结束退出过程中,应用没有连接失效的错误。
# java -Xms512m Xmx2048m Main
[main] INFO com.zaxxer.hikari.HikariDataSource - hikariCP - Starting...
[main] INFO com.zaxxer.hikari.HikariDataSource - hikariCP - Start completed.
[main] INFO com.zaxxer.hikari.HikariDataSource - hikariCP - Shutdown initiated...
[main] INFO com.zaxxer.hikari.HikariDataSource - hikariCP - Shutdown completed.
总结
应用层基于 hikariCP 连接池访问数据库,升级方法的改进是实现数据库运维与应用连接管理策略的协作。另外 maxlifetime 配置不仅在节点下线维护场景有效,也能在 TiDB 节点扩容后,由负载均衡根据最少连接策略将应用侧连接池的新建连接转移到连接较少的新 TiDB 节点,实现节点扩容后快速投入使用。