Ubuntu下提升 PostgreSQL 并发能力的实用方案
一 连接与内核层面优化
- 使用连接池:避免每个应用线程直连数据库,推荐在应用与数据库之间部署**PgBouncer(事务级)**或 Pgpool-II,复用连接、削峰填谷。高并发下“连接风暴”是常见瓶颈,连接池能显著降低数据库进程数与上下文切换开销。
- 合理设置最大连接数:PostgreSQL 默认 max_connections=100,不宜盲目上调。建议结合连接池,将数据库侧上限控制在数百级;超出后优先扩容连接池与服务实例,而非继续拉高 max_connections。
- 处理“连接被拒绝/队列溢出”:高并发短连压测时出现“Resource temporarily unavailable”或“sorry, too many clients already”,需同时检查:
- 数据库 max_connections 是否触顶;
- 操作系统 somaxconn(监听队列)是否过小,必要时调大内核参数以容纳突发连接;
- 应用是否及时释放空闲连接,避免“idle in transaction”长期占用。
- 版本红利:升级到 PostgreSQL 14 及以上版本,高并发场景下的快照与可见性相关路径有显著优化,可降低 CPU 消耗并提升吞吐。
二 内存与后台任务配置
- 内存参数(示例为专用数据库主机,按内存总量 T 规划):
- shared_buffers:建议 T/4 ~ T/3;
- effective_cache_size:建议 0.5 ~ 0.7 × T(提示性参数,不分配实际内存);
- work_mem:按并发与查询特征设定,避免过大导致内存争用,过小触发磁盘临时文件。
- 维护与清理:
- 保障 autovacuum 资源与频率(如 autovacuum_max_workers、autovacuum_naptime、相关阈值),减少表膨胀与锁竞争;
- 对大表膨胀,使用 pg_repack 在线重打包,降低扫描与锁开销。
- 监控与定位慢 SQL:
- 设置 log_min_duration_statement(如 10000ms)记录长查询;
- 通过 pg_stat_activity 实时查看活跃/阻塞会话与长事务。
三 事务与锁的并发治理
- 理解并发模型:PostgreSQL 使用 MVCC,读不阻塞写、写不阻塞读;在 SERIALIZABLE 级别仍保持该特性,但会进行可串行化冲突检测。
- 隔离级别与重试:
- 默认 READ COMMITTED 适合多数 OLTP;
- 高竞争、强一致性场景可用 SERIALIZABLE,并为“序列化失败(40001)”设计自动重试;
- 只读事务尽量声明为 READ ONLY,减少冲突与开销。
- 避免长事务与空闲事务:配置 idle_in_transaction_session_timeout 自动断开“闲置在事务中”的连接,减少锁与快照占用。
- 显式锁与冲突点控制:按需使用 SELECT FOR UPDATE/SHARE、显式 LOCK,或通过 咨询锁 做应用级互斥;用 pg_locks 排查锁等待与死锁。
四 索引、SQL 与数据布局优化
- 减少锁与扫描:为高频点查/范围查询建立合适索引,优先 B-Tree/GiST/SP-GiST 等并发友好的索引类型;避免不必要的全表扫描。
- 优化执行计划:通过 EXPLAIN (ANALYZE) 验证索引命中、临时文件与成本;必要时调整成本参数(如 random_page_cost、cpu_tuple_cost)促使索引扫描。
- 降低序列化失败率:在 SERIALIZABLE 下,减少顺序扫描(鼓励索引扫描)、合理设置 max_pred_locks_per_transaction 等,降低谓词锁合并导致的冲突。
- 数据倾斜与热点:对热点数据做分桶/分区、引入局部索引或缓存层;必要时采用反范式化减少跨表事务与锁竞争。
五 快速排查清单与常用命令
- 连接与负载:
- 当前连接与状态:
- SELECT count(*), state FROM pg_stat_activity GROUP BY state;
- SELECT pid, now()-query_start AS dur, query FROM pg_stat_activity WHERE state=‘active’ ORDER BY dur DESC LIMIT 10;
- 长查询日志:设置 log_min_duration_statement=10000 并观察日志。
- 锁与阻塞:
- 查看锁与等待关系:
- SELECT pid, locktype, mode, relation::regclass, page, tuple, virtualxid, transactionid, classid::regclass, objid, objsubid, virtualtransaction, pid, mode, granted FROM pg_locks l JOIN pg_stat_activity s ON l.pid=s.pid ORDER BY granted, pid;
- 表膨胀与维护:
- 关注膨胀与 vacuum 效果(pg_stat_user_tables 等),必要时对大表执行 pg_repack。
- 连接数核对:
- 数据库上限:SHOW max_connections;
- 当前连接:SELECT count(*) FROM pg_stat_activity;
- 连接风暴与内核:压测/突发连接失败时,检查并适当调大 net.core.somaxconn,同时控制应用端连接生命周期与连接池配置。