我在文档中找不到引用,但我的经验表明 EC2 的网络基础设施一般(包括 RDS 和可能在按客户预置的虚拟机上运行的任何其他 AWS 服务,如果不是全部的话) AWS,当然似乎并不严格限于“EC2 实例”)实施状态数据包检查,并且会在几分钟的绝对空闲后“忘记”TCP 连接是有效的......导致您描述的行为。
连接两端的机器可能会确信连接仍然存在,但网络不允许它们之间的流量通过,因为 SPI 环境中的 TCP 会话未被发现,它们被创建,并且只能当网络在一开始就看到连接时创建(SYN、SYN/ACK、ACK)。我最初在 EC2(不是 RDS)中遇到 MySQL 服务器的这个问题,但如果根本原因不一样,我会非常惊讶。
有两种可能的方法来解决这个问题。
如果您的 PHP 机器是 Linux,请配置内核以在第 4 层保持连接处于活动状态。这种变化对您来说是不可见的,因为这些保持活动不会改变连接 inTime
列中的值,因为它不会重置连接在第 7 层空闲的时间量......但如果管理 MySQL 连接的库正确设置套接字选项以利用它,它应该避免来自 AWS 基础设施的超时。SHOW PROCESSLIST
Sleep
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html解释了如何实时设置,以及如何使其在重新启动后持续存在。
如果做不到这一点,另一种选择是强制 MySQL在网络超时之前关闭连接,以便 PHP 机器立即识别出它正在尝试在关闭的套接字上进行通信。缩短超时而不是延长超时可能听起来违反直觉,但是如果会话空闲时间过长,缩短超时应该会导致您的 ping 测试很快失败,这也(基本上)“解决”了问题,假设理智在 PHP 客户端库中。一旦您的应用程序更忙,连接可能很少会空闲足够长的时间来达到超时。
MySQL 服务器有两种不同的空闲超时设置:(wait_timeout
对于非交互式会话,即来自代码的连接,如 PHP)和interactive_timeout
(来自查询浏览器和命令行客户端)但服务器只知道区别,因为客户端库必须通知服务器正在建立哪种类型的连接。假设您的客户端库使用正确的设置,那么wait_timeout
是你要找的那个。如果更改 Linux 内核中的 TCP keepalive 设置无法解决问题,请将其设置为低于 900 的值。但请注意,在进行更改后,只有未来的连接会受到影响——在进行更改时已经建立的连接仍将使用当前值运行,默认值为 8 小时(28800 秒)。这些可在您的实例的 RDS 参数组中进行配置。
此处的 AWS 文档中有类似行为的提示,以及需要调整的 Windows 注册表设置以更改 TCP keepalives 如果您在 Windows 上运行 PHP 服务器,而不是 Linux,正如我上面假设的那样......甚至尽管这篇文章专门关于 Redshift 和 EC2 外部的连接,但它似乎仍然验证了上面讨论的潜在问题。