首先,这里有一些背景信息。
我们有一个定制的 PHP 应用程序,它在 Apache 下运行并支持我们的网站。
目前我们的网站流量很大。以下是我们当前的设置: - 负载均衡器后面有 10 个 Linux Web 服务器(每个服务器有 8 个 CPU、30Go RAM) - 1 个 Linux MySQL 数据库服务器(30 个 CPU、120 Go RAM)
大部分时间流量都保持良好,但有时出于不确定的原因,我们会看到活动 mysql 连接总数激增。它不断泄漏,直到达到最大值,最终导致我们的网络用户无法使用该应用程序。
当这种情况发生时,就平均负载、内存、CPU 使用率、磁盘交换而言,所有服务器都很好。它们有充足的可用资源。
我们确实注意到有许多 Apache 进程处于 CLOSE_WAIT 连接状态。我们在其中一个 Web 服务器中看到大约 600 个进程处于该状态。
这似乎是我们遇到的问题的一个症状。然而,我们很难深入挖掘。以下是我的问题:
- 为什么 Apache 挂在这些进程上?
- 是否有任何工具或调试技术可以帮助我们找出导致这一问题的原因?
- 我们应该关注哪些指标来了解正在发生的事情?
提前感谢您的帮助,
答案1
我认为您有一个查询锁定了某个表/某些行,而其他 mysql 连接尝试更新这些行的时间比应有的要长。发生这种情况时,所有传入请求都会堆积在其后面,直到达到最大连接数。
Apache 端也发生了同样的情况,因为请求已进入但尚未收到响应(因为查询在数据库上被阻止)。PHP 已打开与数据库的连接;它已进行查询但尚未收到响应。Apache 此时“挂起”是您所期望的,因为它正在等待答案。
Apache 似乎从外部(您的浏览器/移动应用程序/等等)挂起了,因为所有服务器上可用的所有子进程都卡在等待数据库回复。实际上没有更多可用的连接。(这也可能是您的负载均衡器上设置的连接限制)。如果您还没有开始记录负载均衡器上的状态变化,请开始记录。在发生“惊群效应”问题(稍后解释)时,您可能会看到每个 Web 服务器反复启动和关闭。
我认为您的连接处于 CLOSE_WAIT 状态只是一种症状,而不是问题。在解决更明显的可能问题(数据库)之前,我不会花时间尝试解决该问题。一旦您修复了问题,您的大量 CLOSE_WAIT 问题很可能会消失。
要开始在数据库端进行故障排除,您应该启用慢查询日志如果您还没有这样做。让它记录 1 秒左右的请求,并查看问题发生时显示的内容。
注意:慢速查询日志不会记录查询,直到查询完成。不要假设问题开始时出现的第一个查询就是问题查询。它可能是也可能不是。
现在,您可能希望在阻止其他查询的问题查询完成后网站恢复正常......
事实并非如此。如果您每秒有 500 个请求定期进入,并且每秒可以处理 1000 个请求,而您的查询将数据库锁定 10 秒。除了每秒仍在进入的 500 个请求外,现在还有 5,000 个请求等待处理。这被称为惊群问题。
您的问题可能完全是其他问题,但这些症状与我多次处理过的问题完全相同,在大多数情况下,问题都是数据库查询阻止了其他查询。我遇到的唯一一次不是由于数据库引起的问题是在 CentOS 6 上(RHEL 也有这个问题)。不幸的是,Red Hat 的知识库文章讨论了这个问题,但只对订阅者开放,但如果您搜索的话,还有其他参考资料。如果您认为可能是这种情况,那么测试起来非常简单。您只需在 resolv.conf 中添加一行。
如果问题似乎在发生时的同一时间/接近同一时间出现,您应该检查您的 cron 作业(或任何其他按照设定的时间表运行的程序),看看问题查询是否从那里发送。
最后,如果您确实确定自己正受到惊群效应的影响,我建议您对负载均衡器进行限制。您应该对服务器进行基准测试,大致确定它可以同时处理的最大请求数,并限制负载均衡器与每个后端 Web 服务器的连接数不超过该数量。
祝你好运。