如何通过连接与查询测试Postgres 13中Pgbouncer的实用性?
测试Pgbouncer实用性的具体方案(Postgres 13)
Pgbouncer的核心价值是连接复用,优势在高并发场景下才会显著体现。以下是针对直连Postgres vs 通过Pgbouncer连接的对比测试方案,可直接验证其性能和负载优化效果:
测试前准备
- 确认Pgbouncer配置正确:推荐使用
pool_mode=transaction(最常用的事务级连接复用模式),监听端口与Postgres区分开(比如Postgres用5432,Pgbouncer用6432),设置合理的连接池参数(如max_client_conn=200、default_pool_size=20)。 - 准备工具:使用Postgres自带的
pgbench做标准压测,配合psql查看连接状态,用top/htop/iostat监控服务器负载。 - 初始化测试库:创建测试用数据库并导入基准数据:
createdb test_db pgbench -i test_db
方案1:用pgbench做高并发压测
步骤1:直连Postgres测试
模拟100个并发客户端,持续压测60秒:
pgbench -h localhost -p 5432 -U your_username -c 100 -j 4 -T 60 test_db
参数说明:
-c:并发客户端数量-j:压测工作线程数-T:测试持续时长(秒)
记录指标:输出中的tps(每秒事务数)、平均事务耗时、延迟标准差。同时在Postgres中查看实际连接数:
SELECT count(*) FROM pg_stat_activity WHERE datname = 'test_db';
步骤2:通过Pgbouncer连接测试
用完全相同的参数,仅修改端口为Pgbouncer的监听端口:
pgbench -h localhost -p 6432 -U your_username -c 100 -j 4 -T 60 test_db
记录指标:同样记录tps、耗时、延迟,同时查看:
- Pgbouncer连接池状态:用
psql连接Pgbouncer执行SHOW POOLS;,观察cl_active(活跃客户端连接)和sv_active(活跃Postgres后端连接)的差异(正常情况下sv_active远小于cl_active,体现连接复用)。 - Postgres实际连接数:再次执行上述
pg_stat_activity查询,会发现实际连接数远低于100。
对比结果
- 直连场景:Postgres会创建100个物理连接,每个连接占用几MB内存,高并发下内存占用飙升,CPU上下文切换开销大,最终表现为tps低、事务耗时高。
- Pgbouncer场景:Postgres实际连接数被控制在池大小范围内(比如20),内存占用低,CPU开销小,tps更高、平均事务耗时更短。
方案2:自定义业务场景并发测试
如果需要贴近实际业务查询,可写脚本模拟多并发执行复杂查询:
示例Python脚本(基于psycopg2)
import psycopg2 import threading import time # 直连和Pgbouncer的连接参数 DB_DIRECT = { 'host': 'localhost', 'port': 5432, 'user': 'your_username', 'password': 'your_pass', 'dbname': 'test_db' } DB_PGBOUNCER = { 'host': 'localhost', 'port': 6432, 'user': 'your_username', 'password': 'your_pass', 'dbname': 'test_db' } def run_query(db_params, query, results): start = time.time() try: conn = psycopg2.connect(**db_params) cur = conn.cursor() cur.execute(query) cur.fetchall() cur.close() conn.close() results.append(time.time() - start) except Exception: results.append(-1) def test_concurrency(db_params, concurrency, query): results = [] threads = [] total_start = time.time() for _ in range(concurrency): t = threading.Thread(target=run_query, args=(db_params, query, results)) threads.append(t) t.start() for t in threads: t.join() total_time = time.time() - total_start valid_results = [x for x in results if x != -1] avg_time = sum(valid_results) / len(valid_results) if valid_results else 0 print(f"并发数{concurrency}:总耗时{total_time:.2f}s | 平均查询耗时{avg_time:.4f}s | 成功次数{len(valid_results)}") return avg_time, total_time # 替换为你的业务查询(比如复杂关联查询) BUSINESS_QUERY = "SELECT * FROM pgbench_accounts JOIN pgbench_transactions ON pgbench_accounts.aid = pgbench_transactions.aid LIMIT 1000;" # 测试直连 print("=== 直连Postgres测试 ===") direct_avg, direct_total = test_concurrency(DB_DIRECT, 100, BUSINESS_QUERY) # 测试Pgbouncer print("\n=== 通过Pgbouncer测试 ===") pgb_avg, pgb_total = test_concurrency(DB_PGBOUNCER, 100, BUSINESS_QUERY) # 结果对比 print("\n=== 对比总结 ===") print(f"直连平均耗时: {direct_avg:.4f}s | Pgbouncer平均耗时: {pgb_avg:.4f}s") print(f"直连总耗时: {direct_total:.2f}s | Pgbouncer总耗时: {pgb_total:.2f}s")
运行脚本后,会明显看到Pgbouncer在高并发下的平均查询耗时更短、总耗时更少。
数据库负载差异监控
测试过程中同时监控服务器和Postgres的负载:
- 用
top/htop观察Postgres进程的CPU、内存占用:直连时内存会因大量连接飙升,CPU使用率更高。 - 用Postgres系统视图查看负载:
-- 查看当前连接数和查询累计耗时 SELECT count(*) AS total_connections, sum(extract(epoch FROM now() - query_start)) AS total_query_duration FROM pg_stat_activity WHERE datname = 'test_db'; -- 查看数据库整体负载 SELECT * FROM pg_stat_database WHERE datname = 'test_db';
通过Pgbouncer时,total_connections会大幅降低,total_query_duration也会更小,说明数据库资源利用更高效。
关键结论验证
- 当并发数超过Postgres的
max_connections设置时,直连会触发too many connections错误,而Pgbouncer可通过连接池正常处理。 - 高并发场景下,Pgbouncer的连接复用能减少Postgres的上下文切换和内存开销,显著提升吞吐量、降低延迟;低并发场景下两者差异不大,甚至Pgbouncer有微小额外开销,但高并发下优势明显。
内容的提问来源于stack exchange,提问作者Gerzzog
相关产品推荐
相关产品推荐

