我正在尝试从运行在外部ubuntu服务器上的php工作者建立到MySQL RDS数据库的持久连接。作为连接的一部分,我首先检查“mysql_ping”。如果ping返回true,则使用当前连接,否则建立新连接。
我面临的问题是,当我启动我的工作者时,连接建立良好,并且运行良好一段时间,即我可以成功地重复查询RDS数据库。然而大约15分钟后,如果我发出请求,那么“mysql_ping”会挂起,因此php脚本本身会挂起。在进一步调试时,我发现在936秒后mysql_ping响应返回为false。
从外部服务器访问数据库所需的权限是存在的,并且在这段时间内(当脚本挂起时),我能够使用mysql命令行选项成功连接到RDS数据库。此外,如果我杀死工作人员并再次重新启动它,它可以再次成功连接,但问题会在15分钟后回复。
是否需要在RDS服务器设置中更改任何内容以避免此问题?
此致 卡皮尔
答案 0 :(得分:3)
我在文档中找不到引文,但我的经验表明EC2的网络基础设施一般(包括RDS以及可能在按客户配置的虚拟机上运行的任何其他AWS服务,如果并非所有的AWS,当然似乎没有严格限制为“EC2实例”)实现有状态数据包检查,并将“忘记”TCP连接在几分钟的绝对空闲后有效...导致你的行为描述。
连接两端的机器可能确信连接仍然存在,但网络不允许流量在它们之间传递,因为SPI环境中的TCP会话未被发现,它们被创建,并且只能在网络最开始看到连接时创建(SYN, SYN/ACK, ACK)。我最初在EC2(而不是RDS)中使用MySQL服务器遇到了这个问题,但如果根本原因不一样,我会非常惊讶。
有两种方法可以解决这个问题。
如果您的PHP计算机是Linux,请配置内核以使第4层的连接保持活动状态。这些更改将对您不可见,因为这些保持活动不会更改Time
列中的值。 SHOW PROCESSLIST
中的连接Sleep
,因为它不会重置连接在第7层空闲的时间...但是如果管理MySQL的库,它应该避免来自AWS基础架构的超时连接正确设置套接字选项以利用它。
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参数组中进行配置。
有hints of similar behavior in the AWS docs here以及Windows注册表设置,如果您在Windows上运行PHP服务器而不是Linux,则需要调整以更改TCP keepalive,如上所述......即使本文特别关于Redshift和EC2外部的连接,它仍然似乎验证了上面讨论的潜在问题。