简体   繁体   English

MariaDB THREADS_CONNECTED 使用 php-fpm 构建 static

[英]MariaDB THREADS_CONNECTED build up with php-fpm static

The Problem问题

  • My app is written in PHP, on top of Laravel.我的应用程序是在 PHP 中编写的,位于 Laravel 之上。
  • Every hour, I have to restart php-fpm to prevent the MariaDB database from hitting max_connections = 150 and disabling the app since no more connections can be created.每小时,我必须重新启动 php-fpm 以防止 MariaDB 数据库达到max_connections = 150并禁用应用程序,因为无法创建更多连接。

Diagnostic Information诊断信息

  • PHP-FPM is configured as static , with a max child count of 39 . PHP-FPM 配置为static ,最大子节点数为39
  • DB connections are not configured as persistent.数据库连接未配置为持久连接。
  • Raising max_connections above 150 only delays the issue.将 max_connections 提高到 150 以上只会延迟问题。
  • There are three DB nodes and three app nodes.有 3 个 DB 节点和 3 个 app 节点。 The app nodes only talk to their partner DB node in the same region.应用程序节点仅与同一区域中的合作伙伴数据库节点通信。
  • The DB nodes are replicating to each other via Galera.数据库节点通过 Galera 相互复制。
  • The DB nodes have too many connections independently, not as a cluster. DB节点独立连接太多,不成集群。
  • Checking show full processlist shows me that the vast majority of connections are in SLEEP state and doing nothing.检查show full processlist显示绝大多数连接处于SLEEP state 并且什么都不做。
  • Using the remote port from the processlist and ss on the app node as well as the php-fpm status page, I've determined that the children holding the connections open are themselves in idle state.使用应用程序节点上的进程列表和ss的远程端口以及 php-fpm 状态页面,我确定保持连接打开的孩子本身处于idle state。

Attempted solutions尝试的解决方案

  • I've switched php-fpm to dynamic and set the idle-timout to 10s.我已将 php-fpm 切换为动态并将空闲超时设置为 10 秒。 The children do not quit, and I can't see any errors.孩子们不退出,我也看不出有什么错误。
  • I've turned down the number of requests a php-child can handle before it is reaped from 100 to 1 with no effect.我已经将 php-child 在收割之前可以处理的请求数从 100 减少到 1,但没有任何效果。
  • I've registered a shutdown handler with PHP that checks if my DB connection is open and produces an alert.我已经使用 PHP 注册了一个关闭处理程序,用于检查我的数据库连接是否打开并生成警报。 No alerts have been sent.没有发送警报。
  • I've set up a cronjob to systemctl restart php7.4-fpm every hour.我已经设置了一个 cronjob 以systemctl restart php7.4-fpm This alleviates the issue, but obviously isn't a good solution.这缓解了这个问题,但显然不是一个好的解决方案。

Questions问题

  • Under what circumstance does php-fpm maintain a DB connection beyond the end of a script or request? php-fpm 在什么情况下会在脚本或请求结束后保持数据库连接?
  • How do I stop it from doing that?我如何阻止它这样做?

Thanks for reading and any idea that might help.感谢阅读和任何可能有帮助的想法。

"I've registered a shutdown handler with PHP that checks if my DB connection is open and produces an alert. No alerts have been sent." “我已经用 PHP 注册了一个关闭处理程序,它会检查我的数据库连接是否打开并生成警报。没有发送任何警报。”

Regardless of whether you're getting the alert, are you certain that this is running explicitly?无论您是否收到警报,您确定它正在明确运行吗?

DB::disconnect('yourdatabase');

If you think you've got that covered, looking at the PDO object that Laravel is using internally may help.如果您认为自己已经涵盖了这些内容,那么查看 PDO Laravel 在内部使用的 PDO object 可能会有所帮助。 Instead of just debugging via an alert, which may be getting lost somewhere, logging a positive assertion that the connection is closed could be helpful.与其仅仅通过可能在某处丢失的警报进行调试,不如记录连接已关闭的肯定断言可能会有所帮助。

$pdo = DB::connection()->getPdo();
// My "positive assertion" comment is because this can be deceiving:
alertThatDoesNotWork();

// Instead, with odd problems like this, I prefer to do
logStateOfDatabaseConnection();

Without more information, my best guess is related to "not guilty" !== "innocent" .在没有更多信息的情况下,我最好的猜测与"not guilty" !== "innocent"有关。 The log-regardless-of-state approach reduces the outputs to "innocent" and "guilty" with no ambiguity. log-regardless-of-state 方法将输出毫不含糊地减少为“无辜”和“有罪”。

2022-02-09 Edit: Have you checked for a persistence setting? 2022-02-09 编辑:您是否检查了持久性设置? I think this may conventionally be in a database.php or somesuch:我认为这可能通常在数据库中。php 或类似的东西:

  'options' => [
    \PDO::ATTR_PERSISTENT => true
  ]

If you can find a use of "PTO::ATTR_PERSISTENT" in setting up the database, then that may be the culprit.如果您可以在设置数据库时找到“PTO::ATTR_PERSISTENT”的用法,那么这可能就是罪魁祸首。 If you're able to test after switching it off, it may at least clearly define the problem at the cost of some latency.如果您能够在关闭它后进行测试,它至少可以以一些延迟为代价清楚地定义问题。

It's still a bug, but potentially one you can't do much about if the PDO object's destructor is never running.它仍然是一个错误,但如果 PDO 对象的析构函数从未运行,则可能是您无能为力的错误。 From the manual:从手册:

The connection remains active for the lifetime of that PDO object. To close the connection, you need to destroy the object by ensuring that all remaining references to it are deleted--you do this by assigning NULL to the variable that holds the object. If you don't do this explicitly, PHP will automatically close the connection when your script ends.连接在 PDO object 的生命周期内保持活动状态。要关闭连接,您需要销毁 object,方法是确保删除对它的所有剩余引用——您可以通过将 NULL 分配给保存 object 的变量来实现。如果你没有明确地这样做,PHP 会在你的脚本结束时自动关闭连接。

Perhaps the script is ending without destroying your PDO object, and the harder-stop of the process ending (and thus freeing the db resource) isn't happening because the fpm process is persistent.也许脚本在没有破坏您的 PDO object 的情况下结束,并且由于 fpm 进程是持久的,所以进程结束(并因此释放数据库资源)的更难停止没有发生。 A hail-Mary attempt would be throwing a gc_collect_cycles();冰雹玛丽尝试将抛出gc_collect_cycles(); into your shutdown function with the hope that it works around a resource leak.进入您的关机 function,希望它能解决资源泄漏问题。 If there are still references to the PDO object that Laravel hasn't cleaned up, then to some extent, it's their bug.如果还有 PDO object 的引用没有被 Laravel 清理掉,那么在某种程度上,就是他们的 bug。 If you can hunt down references to the object, including those in your debug code, and destroy them, perhaps you can drive the ref-count to 0 so that it gets cleaned up properly.如果您可以找到对 object 的引用(包括调试代码中的引用)并销毁它们,也许您可以将引用计数驱动为 0,以便正确清理它。 I'm not saying that we should all go back to malloc() and free(), but sometimes this "convenience features" aren't so convenient.我并不是说我们应该将所有 go 都返回到 malloc() 和 free(),但有时这种“便利功能”并不是那么方便。 :-/ :-/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM