1. 项目背景与核心价值
最近在做一个需要模拟10万级并发用户的压测项目,传统的JMeter方案在实时数据展示和持久化方面遇到了明显瓶颈。经过多轮技术选型,最终敲定了Locust+InfluxDB这套组合拳。这套方案最吸引我的地方在于:用Locust的轻量级协程机制实现高并发压测,配合InfluxDB的时间序列数据库特性,可以实时捕获每秒20万+的监控数据点,并通过Grafana实现毫秒级延迟的可视化。
实际跑下来发现,这套架构不仅完美解决了传统方案的数据堆积问题,还能在压测过程中实时观察系统各项指标的变化曲线。比如上周排查一个内存泄漏问题时,就是通过InfluxDB记录的内存占用曲线,精准定位到了某个RPC接口在并发量超过5万时会出现堆内存阶梯式增长的现象。
2. 技术栈深度解析
2.1 Locust的协程优势
Locust采用gevent协程实现并发,相比JMeter的线程模型,在单机模拟高并发时优势明显。实测在16核32G的压测机上:
- 用JMeter开5000线程时CPU占用率达80%
- 而Locust跑1万并发用户时CPU仅占用35%
关键配置参数:
python复制class WebsiteUser(HttpUser):
wait_time = between(0.5, 2.5) # 思考时间随机区间
host = "http://api.example.com"
@task(3) # 权重设置
def get_index(self):
self.client.get("/")
2.2 InfluxDB的时序特性
InfluxDB的TSM存储引擎对时间序列数据有特殊优化:
- 压缩比可达10:1(相比MySQL节省90%存储)
- 写入速度达50万点/秒(实测在NVMe SSD上)
- 自带时间降采样函数(如MEAN、MAX等)
数据模型示例:
code复制measurement,host=server01,region=us-west cpu=23.4,mem=4096 1465839830100400200
3. 系统集成方案
3.1 数据流架构设计
mermaid复制graph LR
A[Locust Master] -->|HTTP| B[被测系统]
A -->|UDP| C[InfluxDB]
C --> D[Grafana]
B -->|Metrics| C
注意:生产环境建议改用TCP协议传输,UDP可能存在丢包风险
3.2 关键配置代码
Locust的stats.py扩展:
python复制from influxdb import InfluxDBClient
client = InfluxDBClient(host='localhost', port=8086)
client.switch_database('locust')
def on_request_success(request_type, name, response_time, response_length):
json_body = [{
"measurement": "requests",
"tags": {"type": request_type},
"time": datetime.utcnow().isoformat(),
"fields": {
"response_time": response_time,
"length": response_length
}
}]
client.write_points(json_body)
4. 性能优化实战
4.1 写入批处理优化
原始方案是每个请求都立即写入InfluxDB,当QPS>5万时出现瓶颈。改进方案:
python复制from queue import Queue
from threading import Thread
write_queue = Queue(maxsize=10000)
def batch_writer():
points = []
while True:
point = write_queue.get()
points.append(point)
if len(points) >= 1000 or write_queue.empty():
client.write_points(points)
points = []
Thread(target=batch_writer, daemon=True).start()
4.2 查询性能对比
测试条件:1小时压测数据(约7200万数据点)
| 查询类型 | InfluxDB | MySQL |
|---|---|---|
| 时间范围查询 | 23ms | 1.2s |
| 聚合统计 | 56ms | 4.8s |
| 多条件过滤 | 102ms | 8.3s |
5. 踩坑实录
-
时间戳问题:
初期使用本地时间导致图表出现锯齿,改为UTC时间后解决:python复制from datetime import datetime, timezone datetime.now(timezone.utc).isoformat() -
字段类型陷阱:
误将status_code存为float类型,导致Grafana无法正确显示HTTP状态码分布。修正方案:python复制fields={"status": int(response.status_code)} -
内存泄漏排查:
发现InfluxDB客户端会缓存未发送数据,通过定期重启worker解决:bash复制watch -n 3600 "pkill -f locust && nohup locust &"
6. 监控看板配置
Grafana关键面板配置示例:
-
实时RPS面板:
sql复制SELECT count("response_time") FROM "requests" WHERE $timeFilter GROUP BY time(1s) fill(0) -
响应时间百分位:
sql复制SELECT percentile("response_time", 95) FROM "requests" WHERE $timeFilter GROUP BY time(10s) -
错误率统计:
sql复制SELECT sum("error")/count("error") FROM "requests" WHERE $timeFilter GROUP BY time(30s)
这套方案目前已经稳定运行了半年多,最高记录是单机模拟12万并发用户,持续写入InfluxDB的数据量达到230万点/分钟。对于需要长时间稳定性压测的场景,建议增加磁盘监控,我们曾遇到过InfluxDB的wal日志写满磁盘的情况。