PostgreSQL常見錯誤:sorry, too many clients already
當(dāng)應(yīng)用程序連接 PostgreSQL 數(shù)據(jù)庫遇到“FATAL: sorry, too many clients already”錯誤時,表示數(shù)據(jù)庫連接數(shù)已經(jīng)到達(dá)服務(wù)器允許的最大值,無法建立新的連接。
原因分析
PostgreSQL 允許的最大客戶端連接數(shù)由配置參數(shù) max_connections ,默認(rèn)值通常為 100。
SHOW max_connections;
max_connections|
---------------+
100 |
那是不是意味著客戶端一定可以創(chuàng)建 100 個并發(fā)連接呢?
并不是,因?yàn)?PostgreSQL 還有另外兩個相關(guān)參數(shù):
SHOW superuser_reserved_connections;
superuser_reserved_connections|
------------------------------+
3 |
superuser_reserved_connections 參數(shù)代表了 PostgreSQL 數(shù)據(jù)庫為超級用戶保留的連接數(shù),默認(rèn)值為 3。
也就是說,當(dāng)客戶端連接數(shù)到達(dá) max_connections - superuser_reserved_connections 時,只有超級用戶才能繼續(xù)創(chuàng)建新的連接。
SHOW reserved_connections;
reserved_connections|
--------------------+
0 |
reserved_connections 參數(shù)代表了 PostgreSQL 數(shù)據(jù)庫為擁有 pg_use_reserved_connections 角色的用戶保留的連接數(shù),默認(rèn)值為 0。這個參數(shù)是 PostgreSQL 16 新增參數(shù)。
當(dāng)可用連接數(shù)大于 superuser_reserved_connections 并且小于等于 superuser_reserved_connections + reserved_connections 時,只有超級用戶或者擁有 pg_use_reserved_connections 角色的用戶才能繼續(xù)創(chuàng)建新的連接。
總結(jié)一下,假設(shè) max_connections 參數(shù)設(shè)置為 100,superuser_reserved_connections 參數(shù)設(shè)置為 3,reserved_connections 參數(shù)設(shè)置為 10。此時,客戶端最多可以同時創(chuàng)建 100 個連接;當(dāng)連接數(shù)到達(dá) 87 并且小于 97 時,只有超級用戶和 pg_use_reserved_connections 角色用戶可以繼續(xù)創(chuàng)建連接;當(dāng)連接數(shù)到達(dá) 97 時,只有超級用戶可以繼續(xù)創(chuàng)建連接。
解決方法
我們可以利用數(shù)據(jù)庫為超級用戶保留的連接登錄數(shù)據(jù)庫,然后查看當(dāng)前服務(wù)器進(jìn)程情況:
SELECT * FROM pg_stat_activity;
datid|datname |pid |leader_pid|usesysid|usename |application_name |client_addr|client_hostname|client_port|backend_start |xact_start |query_start |state_change |wait_event_type|wait_event |state |backend_xid|backend_xmin|query_id|query |backend_type |
-----+--------+-----+----------+--------+--------+-----------------------------------------+-----------+---------------+-----------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+---------------+-------------------+------+-----------+------------+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+
5|postgres|19256| | 10|postgres|DBeaver 24.1.5 - Main <postgres> |127.0.0.1 | | 55986|2024-08-28 21:20:25.682 +0800| |2024-08-28 21:20:25.795 +0800|2024-08-28 21:20:25.795 +0800|Client |ClientRead |idle | | | |SHOW search_path |client backend |
5|postgres|22216| | 10|postgres|DBeaver 24.1.5 - Metadata <postgres> |127.0.0.1 | | 55987|2024-08-28 21:20:25.826 +0800| |2024-08-28 22:03:37.376 +0800|2024-08-28 22:03:37.376 +0800|Client |ClientRead |idle | | | |SELECT c.oid,c.*,d.description,pg_catalog.pg_get_expr(c.relpartbound, c.oid) as partition_expr, pg_catalog.pg_get_partkeydef(c.oid) as partition_key ?FROM pg_catalog.pg_class c?LEFT OUTER JOIN pg_catalog.pg_description d ON d.objoid=c.oid AND d.objsubid=|client backend |
5|postgres|10736| | 10|postgres|DBeaver 24.1.5 - SQLEditor <Script-2.sql>|127.0.0.1 | | 55988|2024-08-28 21:20:26.003 +0800|2024-08-28 22:03:41.802 +0800|2024-08-28 22:03:41.803 +0800|2024-08-28 22:03:41.803 +0800| | |active| |1032 | |select * from pg_stat_activity |client backend |
| |20852| | | | | | | |2024-08-24 20:56:59.100 +0800| | | | | | | | | | |autovacuum launcher |
| | 9236| | 10|postgres| | | | |2024-08-28 21:13:57.480 +0800| | | |Activity |LogicalLauncherMain| | | | | |logical replication launcher|
| |19468| | | | | | | |2024-08-24 20:56:59.082 +0800| | | |Activity |WalWriterMain | | | | | |walwriter |
| | 3524| | | | | | | |2024-08-24 20:56:58.608 +0800| | | |Activity |CheckpointerMain | | | | | |checkpointer |
| | 8896| | | | | | | |2024-08-24 20:56:58.620 +0800| | | |Activity |BgwriterHibernate | | | | | |background writer |
系統(tǒng)視圖 pg_stat_activity 顯示了所有后端進(jìn)程的信息,其中 backend_type 字段取值為 client backend 的進(jìn)程對應(yīng)客戶端連接。通過這個視圖可以了解客戶端的連接情況。
如果應(yīng)用程序的確需要更多的數(shù)據(jù)庫連接,可以修改上面介紹的 PostgreSQL 配置參數(shù),這些參數(shù)的修改都需要重啟服務(wù)。
如果應(yīng)用程序并不需要這么多連接,而是由于代碼問題導(dǎo)致連接泄露,例如創(chuàng)建了數(shù)據(jù)庫連接后沒有正確地釋放,或者數(shù)據(jù)庫連接池配置不當(dāng)導(dǎo)致打開了過多連接。這種情況就需要調(diào)整應(yīng)用端代碼,確保正確管理了數(shù)據(jù)庫連接。