调试 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 文档以获取更多信息。
池最大可达 pool
(database.yml
中的配置选项)。因此,如果将 pool
选项设置为 40,则每个 process(unicorn worker)在使用 40(或更多) 时最多可以打开 40 个连接线程,所以在你的例子中,仅独角兽就可能吃掉多达 40 * 8 = 200 个连接。
所以,总的来说,我认为您的应用程序中一定有一些线程(可能在 gem 某处)。如果这与您的 中的应用程序相同,那么我猜它肯定与多个生成线程有关。
我们的新应用昨天流量很大,开始崩溃。错误是达到 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 文档以获取更多信息。
池最大可达 pool
(database.yml
中的配置选项)。因此,如果将 pool
选项设置为 40,则每个 process(unicorn worker)在使用 40(或更多) 时最多可以打开 40 个连接线程,所以在你的例子中,仅独角兽就可能吃掉多达 40 * 8 = 200 个连接。
所以,总的来说,我认为您的应用程序中一定有一些线程(可能在 gem 某处)。如果这与您的