乘客使用比预期更多的 PostgreSQL 连接

Passenger uses more PostgreSQL connection than expected

长期在生产中发生的难题,我们不知道它的来源。有时可以在本地主机上重现它,Heroku Enterprise 支持已经 clue-less 关于这个。

在我们的生产数据库中,我们目前有以下设置:

a SELECT * FROM pg_stat_activity GROUP BY client_addr 并计算每个实例的连接数显示,在我们的高峰期,为一个乘客进程打开了超过 1 个 PSQL 连接。

假设:

这是 SELECT * FROM pg_stat_activity;:

的屏幕截图

在屏幕截图中,我们可以看到有 45 个 psql 连接 来自运行 passenger 的同一个 dyno。如果我们按照我们之前的逻辑,每个 Passenger 进程不应该有超过 1 个连接,所以 25 个。

日志看起来没有异常,没有提到 dyno 崩溃/进程崩溃。

下面是我们同一个dyno的passenger状态截图(不同时间,只是为了证明一个dyno创建的进程数不超过25个):

最后是我们从 Heroku 支持中得到的回应之一(顺便说一句,支持很棒)

I have also seen previous reports of Passenger utilising more connections than expected, but most were closed due to difficulty reproducing, unfortunately.

在 Passenger 文档中,解释了 Passenger 自行处理 ActiveRecord 连接。

感谢任何线索。谢谢!

各种信息:

如果您需要更多信息,请在评论中告诉我,我会很乐意更新此 post。

最后一件事:我们使用 ActionCable。我在某个地方读到乘客正在奇怪地处理套接字连接(打开一个有点隐藏的进程以保持连接有效)。这是我们的线索之一,但到目前为止还没有在本地主机上重现它。如果有人能确认 Passenger 如何处理 ActionCable 连接,将不胜感激。

更新 1 (01/10/2018):

实验:

我们终于设法解决了我们在 Passenger 上遇到的问题。实际上,我们已经遇到这个问题很长时间了。

修正

如果您使用 ActionCable,并且您的默认电缆路线是 /cable,则将 Procfile 更改为:

web: bundle exec passenger start -p $PORT --max-pool-size $PASSENGER_MAX_POOL_SIZE

web: bundle exec passenger start -p $PORT --max-pool-size $PASSENGER_MAX_POOL_SIZE --unlimited-concurrency-path /cable

解释

更改之前,每个套接字连接 (ActionCable) 将在 Passenger 中占用一个进程。 但是一个Socket其实是不应该走完整个进程的东西。一个进程可以处理许多打开的套接字连接。 (对于一些大牌来说,很多是同时超过一万)。幸运的是,我们的套接字连接数要低得多,但仍然如此。

更改后,我们基本上告诉 Passenger 不要用整个进程来处理一个套接字连接,而是用整个进程来处理所有套接字连接。

文档

一些指标,修复 3 周后

  • Passenger 上的分叉进程数 显着减少(从 75 个进程减少到约 15 个进程)
  • Web dynos 上的全局内存使用量 显着下降(与之前分叉的 Passenger 进程有关)
  • 全球 PSQL 连接数 急剧下降并稳定了两天(甚至在部署后)。 (从 150 到 ~30 个连接)
  • 每个测力计的 PSQL 连接数 显着减少,(从每个测力计约 50 个到每个测力计不到 10 个)
  • Redis 连接数下降,稳定了两天(即使部署后)
  • PostgreSQL 上的平均内存使用量 急剧下降,并且已经稳定了两天。
  • 总体吞吐量比平时高一点(吞吐量是每分钟处理的请求数)