调试 unicorn postgres 连接泄漏

Debugging unicorn postgres connection leak

我们的新应用昨天流量很大,开始崩溃。错误是达到 PG 最大连接数。考虑到我们的配置,这非常奇怪 -

PG max_connections = 100 独角兽工人=8 Sidekiq 进程 = 1 Sidekiq 并发 = 25

所以从技术上讲应该只有 34 个活动连接,对吗?我认为我们的应用程序中没有任何多线程。

在我重新启动数据库服务器和应用程序后,这个问题就解决了。今天,我开始看到这些连接弹出。

勾选 pg_stats_activity:

prod_db=# select datid, datname, pid, usesysid, usename, application_name, state from pg_stat_activity;                                                                             
 datid |        datname        |  pid  | usesysid | usename  |                        application_name                         | state  
-------+-----------------------+-------+----------+----------+-----------------------------------------------------------------+--------
 16384 | prod_db | 30104 |       10 | postgres | unicorn worker[1] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30094 |       10 | postgres | unicorn worker[0] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30110 |       10 | postgres | unicorn worker[2] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30116 |       10 | postgres | unicorn worker[3] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30123 |       10 | postgres | unicorn worker[4] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30129 |       10 | postgres | unicorn worker[5] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30135 |       10 | postgres | unicorn worker[6] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 30157 |       10 | postgres | unicorn worker[7] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 32161 |       10 | postgres | unicorn worker[5] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 32183 |       10 | postgres | unicorn worker[7] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 32273 |       10 | postgres | unicorn worker[5] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db | 32296 |       10 | postgres | unicorn worker[2] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db |   374 |       10 | postgres | unicorn worker[1] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db |   491 |       10 | postgres | sidekiq 3.4.2 app_production [0 of 25 busy]                     | idle
 16384 | prod_db |   498 |       10 | postgres | unicorn worker[7] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db |   581 |       10 | postgres | unicorn worker[3] -c /u/apps/e...ig/unicorn.rb -E deployment -D | idle
 16384 | prod_db |  1337 |       10 | postgres | psql                                                            | active
(17 rows)

我看到多个连接归因于单个 unicorn 工作进程,这很奇怪。

我读得正确吗?我的假设是,这是导致 postgres 连接致命事件的基石 运行 当有主要负载时。

如果那是真的,如何调试呢?任何指针?谢谢! :)

如果需要,很乐意分享更多详细信息。

postgresql.conf

data_directory = '/var/lib/postgresql/9.4/main'
datestyle = 'iso, mdy'
default_text_search_config = 'pg_catalog.english'
external_pid_file = '/var/run/postgresql/9.4-main.pid'
hba_file = '/etc/postgresql/9.4/main/pg_hba.conf'
ident_file = '/etc/postgresql/9.4/main/pg_ident.conf'
listen_addresses = 'localhost'
log_line_prefix = '%t '
max_connections = 100
port = 5432
shared_buffers = '24MB'
ssl = on
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
unix_socket_directories = '/var/run/postgresql'

unicorn.rb - https://gist.github.com/steverob/b83e41bb49d78f9aa32f79136df5af5f

database.yml -

production:
  adapter: postgresql
  host: localhost
  username: postgres
  password: app_name
  pool: 40
  timeout: 5000
  database: app_production
  encoding: utf8

不久前遇到过类似的问题,未使用的连接处于打开状态。对我来说 PgBouncer 修复了它

一般来说,应用程序中的任何线程,当它在数据库中执行查询时(即当它以任何方式使用 ActiveRecord::Base.connection 时),它都会获得到数据库的连接,与其他线程分开ConnectionPool class 负责将数据库连接分配给 Rails 中的线程。请阅读 class 文档以获取更多信息。

池最大可达 pooldatabase.yml 中的配置选项)。因此,如果将 pool 选项设置为 40,则每个 process(unicorn worker)在使用 40(或更多) 时最多可以打开 40 个连接线程,所以在你的例子中,仅独角兽就可能吃掉多达 40 * 8 = 200 个连接

所以,总的来说,我认为您的应用程序中一定有一些线程(可能在 gem 某处)。如果这与您的 中的应用程序相同,那么我猜它肯定与多个生成线程有关。