一个由于 Nginx 静态 DNS 解析缓存导致的奇怪问题【续】

该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/post/2024/01/21/problem-led-by-nginx-static-dns-cache-2/

书接上文,被同一个问题坑了两次……

2023年11月的时候,AWS 的运营人员通知我们,由于 MySQL 5.7 生命周期的结束,因此 AWS RDS MySQL 将于 2024 年 2 月 29 日完成 MySQL 5.7 -> 8.0 的强制升级。虽说 AWS 运营人员说 2 月 29 日是最后期限,但是根据文档显示,他们会对 MySQL 5.7 的不同补丁版本在不同的时间进行分批升级。而我们使用的 MySQL 5.7.42 版本将从 1 月 16 日开始分区域启动(强制)升级。

出于业务稳定性考虑,我们选择主动升级,而不是等 AWS 的强制升级——鬼知道会搞出来什幺蛾子。同时年关将至,为了避免过年放假期间出问题,大家急急忙忙地验证所有系统的兼容性、寻找无缝升级的方案、实验并测试,终于赶在 2024 年 1 月上旬完成了所有 AWS RDS MySQL 5.7 实例的无缝升级。

听起来很顺利,那么问题出在哪里呢?

先简单介绍下我们的部署架构,由于业务需要和成本考虑,我们的系统采用了多云混用模式,在不同云厂商的各个可用区都部署了服务器节点,但是数据库以 AWS RDS 为主。其他云上面的系统对数据库的需求都是以读为主,极少量写入(没有冲突)。由于不需要高频读写,所以干脆用了公网直连的模式,反正有 TLS 和云厂商的安全组保护——但是,由于全球部署的机器实在太多了,所以为了避免安全组规则数量爆炸,我们在每个云上配了一台机器作为 AWS RDS 实例的反向代理,同一个云的服务器机器都通过内部网络连接到这台机器上的反代访问 AWS 上的 RDS MySQL,而这个反代就是 Nginx……

这里需要指出,AWS RDS MySQL 的接入点是 AWS 提供的一个资源域名(如 xxxxx.rds.amazonaws.com。这次升级,我们使用的是 AWS RDS 提供的蓝绿部署(Blue/Green Deployment)功能,最初升级的几台 RDS 并没有配置公网访问,因此没有遇到任何问题。我们都想当然地以为“蓝绿部署”的“切换”功能是 AWS 将 RDS 的蓝绿实例的网络接入点直接互换,并强制掐断现有的客户端连接,使之自动重连,这时候所有客户端就会连接到新的(切换后的)实例上,蓝绿切换就完成了。至少,在前几台 RDS 上,这与我们观测到的现象是一致的。直到我们开始升级配置了公网访问的这一台 RDS,一切都变了。

其实并没有任何可观测到的异常,监控显示一切正常,各地服务器都“正常”地连接到了 MySQL 服务器。在这期间,虽然我们观测到连接数下降了大约一半,但是我们以为是各个客户端连接池里的冗余(闲置)连接被释放了导致的,并没有太过关注。直到这台 RDS 升级完成大约 15 分钟后,我进入数据库检查一个状态表,发现数据都停留在了 15 分钟前,也就是切换完成的那一瞬间——完蛋,切换出问题了。再查了一下这台 MySQL 的连接情况,并不是没有客户端连上来,那就说明蓝绿切换确实是成功的。

立即启动问题排查,发现所有未连接到新实例的客户端,都是通过 Nginx 代理访问的,这让我们一头雾水,难道是连接没断开?但是之前几台 RDS 的客户端都确实自动断开当前连接,并自动连接到新的实例上了没错啊。虽然还没想明白原因,但是为了避免故障扩大,我通知运维同事立即重启各大云上面的 Nginx 反代,然后,一切突然就恢复正常了。

此时我们才后知后觉,原来 AWS RDS 的所谓蓝绿切换,就是把 DNS 一切,接着掐断旧实例上的客户端连接……

comments powered by Disqus