一、为什么要做数据库压测?
想象你开了一家网红餐厅,开业当天突然涌进来500个客人,结果厨房瘫痪、服务员手忙脚乱。数据库就像这个厨房,压测就是提前模拟"客流高峰",看看系统什么时候会"翻台"。
真实案例:某电商去年双十一前没做压测,大促时订单库响应延迟高达15秒,直接损失300万订单。通过压测可以:
- 发现性能瓶颈(比如CPU跑满/内存泄漏)
- 确定最大承载量(就像知道餐厅最多能接待多少桌)
- 验证优化效果(索引优化后性能提升多少)
二、PostgreSQL压测工具箱
2.1 内置武器:pgbench
这是PostgreSQL自带的"跑步机",可以模拟简单业务场景:
-- 技术栈:PostgreSQL 14
-- 初始化测试数据(生成10万账户的测试库)
pgbench -i -s 10 -U test_user test_db
-- 执行压测(100个并发连接,持续60秒)
pgbench -c 100 -T 60 -U test_user test_db
参数说明:
-s 10:缩放因子,每个因子约等于10万条记录-c 100:模拟100个客户端同时操作-T 60:持续运行60秒
2.2 高级装备:自定义测试脚本
真实业务往往更复杂,可以自己编写测试脚本:
-- 技术栈:PostgreSQL 14
-- custom_benchmark.sql
\set uid random(1, 100000) -- 随机选择用户ID
BEGIN;
UPDATE accounts SET balance = balance + 1 WHERE user_id = :uid;
INSERT INTO transactions VALUES (:uid, now(), 1);
COMMIT;
执行命令:
pgbench -c 50 -T 120 -f custom_benchmark.sql test_db
三、实战压测五步法
3.1 环境准备
就像运动员热身,需要:
- 关闭其他应用服务
- 记录初始硬件状态(
top命令看CPU/内存) - 备份数据库(防止测试数据污染)
# 记录初始状态
vmstat 1 60 > baseline.log &
pg_stat_activity > pg_before.log
3.2 渐进式加压
不要一上来就"暴力测试",要像汽车转速表那样逐步升档:
- 先用10个并发测基础性能
- 每次增加20%并发数
- 记录每次的TPS(每秒事务数)变化
for clients in 10 30 50 80 100; do
pgbench -c $clients -T 30 test_db | tee log_$clients.txt
done
3.3 监控关键指标
这些指标就像汽车的仪表盘:
- CPU使用率:超过70%就要警惕
- 磁盘IO:
iostat查看await值(超过10ms说明磁盘忙) - 锁等待:
SELECT * FROM pg_locks查看锁冲突
3.4 结果分析
典型性能曲线有三种情况:
- 理想型:TPS随并发线性增长
- 瓶颈型:达到某个点后TPS不再上升
- 崩溃型:超过阈值后性能断崖下跌
3.5 优化验证
假设发现索引缺失导致慢查询:
-- 优化前(全表扫描)
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 12345;
-- 添加索引后对比
CREATE INDEX idx_orders_user ON orders(user_id);
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 12345;
四、避坑指南
4.1 测试数据陷阱
不要用1万条数据测100万条数据的性能!数据量要接近生产环境:
-- 生成百万级测试数据
INSERT INTO users
SELECT generate_series(1,1000000),
md5(random()::text),
random()*1000;
4.2 网络延迟干扰
如果应用服务器和数据库分开部署,建议:
- 在数据库本机直接测试,排除网络因素
- 使用
ping和traceroute检查网络质量
4.3 缓存预热
冷启动和热启动能差10倍性能!测试前先预热:
-- 手动加载常用表到内存
SELECT pg_prewarm('orders');
SELECT pg_prewarm('users');
五、进阶技巧
5.1 模拟混合读写
真实业务往往是读写混合的,可以这样设计:
-- 技术栈:PostgreSQL 14
\set read_prob 0.8 -- 80%概率是读操作
\set uid random(1, 1000000)
-- 读操作
SELECT * FROM products WHERE id = :uid;
-- 写操作
\if :read_prob < 0.8
UPDATE products SET stock = stock - 1 WHERE id = :uid;
\endif
5.2 连接池测试
连接池就像餐厅的候客区,测试连接池大小的影响:
# 测试不同连接池配置
for pool_size in 20 50 100; do
sed -i "s/max_connections = .*/max_connections = $pool_size/" postgresql.conf
pg_ctl restart
pgbench -c $((pool_size+10)) -T 60 test_db
done
六、总结与建议
经过完整压测后,你应该能回答这些问题:
- 系统能承受多少并发用户?
- 响应时间在多少并发时开始恶化?
- 硬件资源瓶颈在哪里?
最后给三个实用建议:
- 定期压测:就像汽车定期保养,建议每季度做一次
- 真实模拟:测试场景要尽量接近真实业务
- 留有余量:最大承载量按测试结果的70%来规划
记住:压测不是考试,而是体检。目的是发现问题而不是追求高分!
评论