Skip to content

PostgreSQL 连接问题

连接问题类型

1. 连接失败

  • 现象:客户端无法建立到PostgreSQL服务器的连接
  • 错误信息
    • could not connect to server: Connection refused
    • could not connect to server: No such file or directory
    • FATAL: password authentication failed for user "postgres"
    • FATAL: database "mydb" does not exist

2. 连接超时

  • 现象:客户端连接请求超时
  • 错误信息
    • connection to server at "localhost" (127.0.0.1), port 5432 failed: Connection timed out

3. 连接数达到上限

  • 现象:新连接无法建立,提示连接数已满
  • 错误信息
    • FATAL: sorry, too many clients already

4. 连接泄漏

  • 现象:连接数逐渐增加,最终达到上限
  • 表现:大量空闲连接占用资源

连接问题诊断

1. 检查PostgreSQL服务状态

bash
# 检查PostgreSQL服务是否运行
sudo systemctl status postgresql@15-main

# 检查PostgreSQL进程
ps aux | grep postgres

# 检查监听端口
netstat -tuln | grep 5432
ss -tuln | grep 5432

2. 检查监听配置

sql
-- 查看监听地址和端口
SHOW listen_addresses;
SHOW port;

-- 查看pg_hba.conf配置
SELECT * FROM pg_hba_file_rules;

3. 检查连接数配置

sql
-- 查看最大连接数配置
SHOW max_connections;

-- 查看当前连接数
SELECT count(*) FROM pg_stat_activity;

-- 查看连接数分布
SELECT usename, application_name, client_addr, count(*) FROM pg_stat_activity GROUP BY usename, application_name, client_addr;

-- 查看空闲连接
SELECT pid, usename, application_name, client_addr, state, backend_start, now() - backend_start AS idle_time
FROM pg_stat_activity
WHERE state = 'idle' AND now() - backend_start > interval '10 minutes';

4. 检查认证配置

bash
# 查看pg_hba.conf文件内容
sudo cat /etc/postgresql/15/main/pg_hba.conf

# 查看pg_ident.conf文件内容
sudo cat /etc/postgresql/15/main/pg_ident.conf

5. 检查防火墙配置

bash
# 检查iptables规则
sudo iptables -L -n

# 检查firewalld规则
sudo firewall-cmd --list-ports

# 临时开放PostgreSQL端口
sudo firewall-cmd --add-port=5432/tcp --permanent
sudo firewall-cmd --reload

连接问题解决措施

1. 连接失败解决

服务未运行

bash
# 启动PostgreSQL服务
sudo systemctl start postgresql@15-main

# 设置开机自启
sudo systemctl enable postgresql@15-main

监听配置错误

sql
-- 修改监听地址为所有网卡
ALTER SYSTEM SET listen_addresses = '*';

-- 重新加载配置
SELECT pg_reload_conf();

认证配置错误

bash
# 修改pg_hba.conf文件,添加正确的认证规则
sudo vi /etc/postgresql/15/main/pg_hba.conf

# 添加允许所有IP访问的规则(仅测试环境使用)
host    all             all             0.0.0.0/0               md5

# 重新加载配置
sudo systemctl reload postgresql@15-main

2. 连接超时解决

网络问题

bash
# 测试网络连通性
ping postgres-server

# 测试端口连通性
telnet postgres-server 5432
nc -zv postgres-server 5432

防火墙问题

bash
# 开放PostgreSQL端口
sudo firewall-cmd --add-port=5432/tcp --permanent
sudo firewall-cmd --reload

3. 连接数达到上限解决

临时解决方案

sql
-- 终止空闲连接
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle' AND now() - backend_start > interval '30 minutes';

-- 终止特定用户的连接
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename = 'app_user';

长期解决方案

sql
-- 增加最大连接数(需谨慎调整)
ALTER SYSTEM SET max_connections = '200';

-- 重启PostgreSQL服务使配置生效
sudo systemctl restart postgresql@15-main

4. 连接泄漏解决

应用层修复

  • 检查应用代码,确保正确关闭数据库连接
  • 调整连接池配置,设置合理的连接超时和最大连接数
  • 使用连接池监控工具,及时发现连接泄漏

数据库层防护

sql
-- 设置空闲连接超时
ALTER SYSTEM SET idle_in_transaction_session_timeout = '30000'; -- 30秒
ALTER SYSTEM SET idle_session_timeout = '3600000'; -- 1小时

-- 重新加载配置
SELECT pg_reload_conf();

连接池配置最佳实践

1. 连接池参数调优

参数说明建议值
max_connections数据库最大连接数根据服务器资源和业务需求调整,建议不超过服务器CPU核心数的2-4倍
min_connections连接池最小连接数5-10
max_idle_time连接最大空闲时间300秒(5分钟)
acquire_timeout获取连接超时时间30秒
validation_timeout连接验证超时时间5秒

2. 常见连接池配置示例

pgBouncer配置

ini
[databases]
* = host=localhost port=5432

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 5
max_db_connections = 100
max_user_connections = 50
idle_timeout = 300

HikariCP配置(Java应用)

java
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
config.setUsername("postgres");
config.setPassword("password");
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
config.setIdleTimeout(300000); // 5分钟
config.setMaxLifetime(1800000); // 30分钟
config.setConnectionTimeout(30000); // 30秒

连接监控与告警

1. 连接监控

sql
-- 监控连接数
SELECT 
  current_setting('max_connections')::int as max_connections,
  count(*) as current_connections,
  round(count(*) * 100.0 / current_setting('max_connections')::int, 2) as connection_percentage
FROM pg_stat_activity;

-- 监控空闲连接
SELECT 
  state,
  count(*),
  round(count(*) * 100.0 / (SELECT count(*) FROM pg_stat_activity), 2) as percentage
FROM pg_stat_activity
GROUP BY state;

-- 监控连接来源
SELECT 
  client_addr,
  count(*),
  round(count(*) * 100.0 / (SELECT count(*) FROM pg_stat_activity), 2) as percentage
FROM pg_stat_activity
GROUP BY client_addr
ORDER BY count(*) DESC;

2. 连接告警配置

Prometheus + Grafana监控

  • 监控指标

    • pg_stat_database_numbackends:当前连接数
    • pg_settings_max_connections:最大连接数
    • pg_stat_activity_count_by_state:按状态分类的连接数
  • 告警规则

    • 连接数超过最大连接数的80%时告警
    • 空闲连接数超过总连接数的50%时告警
    • 连接池使用率超过90%时告警

Zabbix监控

  • 监控项

    • PostgreSQL连接数
    • PostgreSQL空闲连接数
    • PostgreSQL最大连接数
  • 触发器

    • 连接数 > 最大连接数 * 0.8
    • 空闲连接数 > 总连接数 * 0.5

连接问题最佳实践

1. 预防措施

  • 合理配置连接数:根据服务器资源和业务需求调整最大连接数
  • 使用连接池:在应用层使用连接池管理数据库连接
  • 设置连接超时:配置合理的连接超时和空闲超时
  • 监控连接状态:定期监控连接数和连接状态
  • 定期清理空闲连接:设置自动清理长时间空闲的连接

2. 安全配置

  • 限制监听地址:只监听必要的网卡地址
  • 配置pg_hba.conf:使用最小权限原则,只允许必要的IP和用户访问
  • 使用SSL连接:加密客户端和服务器之间的通信
  • 定期更换密码:定期更换数据库用户密码

3. 性能优化

  • 调整work_mem:根据连接数调整work_mem大小,避免内存不足
  • 优化查询:减少长时间运行的查询,避免占用连接资源
  • 使用事务池模式:对于只读应用,使用pgBouncer的事务池模式提高并发性能

常见问题(FAQ)

Q1:PostgreSQL连接失败的常见原因有哪些?

A1:PostgreSQL连接失败的常见原因包括:

  • PostgreSQL服务未运行
  • 监听地址或端口配置错误
  • 防火墙阻止了连接
  • pg_hba.conf配置错误
  • 用户名或密码错误
  • 数据库不存在
  • 连接数达到上限

Q2:如何查看PostgreSQL的当前连接数?

A2:可以使用以下命令查看当前连接数:

sql
SELECT count(*) FROM pg_stat_activity;

Q3:如何增加PostgreSQL的最大连接数?

A3:可以通过以下步骤增加最大连接数:

  1. 修改max_connections参数:ALTER SYSTEM SET max_connections = '200';
  2. 重启PostgreSQL服务使配置生效
  3. 注意:增加最大连接数会增加内存使用,需根据服务器资源调整

Q4:什么是连接池?为什么要使用连接池?

A4:连接池是一种管理数据库连接的技术,它可以:

  • 减少连接建立和关闭的开销
  • 限制并发连接数,保护数据库服务器
  • 提高应用性能
  • 便于监控和管理连接

Q5:如何诊断连接泄漏问题?

A5:诊断连接泄漏问题的方法:

  1. 监控连接数变化趋势
  2. 查看长时间空闲的连接
  3. 分析连接来源和应用
  4. 检查应用代码,确保正确关闭连接
  5. 使用连接池监控工具

Q6:如何设置PostgreSQL的空闲连接超时?

A6:可以使用以下参数设置空闲连接超时:

  • idle_in_transaction_session_timeout:设置事务中空闲连接的超时时间
  • idle_session_timeout:设置空闲连接的超时时间

例如:

sql
ALTER SYSTEM SET idle_in_transaction_session_timeout = '30000'; -- 30秒
ALTER SYSTEM SET idle_session_timeout = '3600000'; -- 1小时
SELECT pg_reload_conf();