把服务器比作一家餐厅,这套体系里每个角色分工如下。
| 组件 | 打个比方 | 一句话职责 |
|---|---|---|
| Blackbox Exporter | 侦察兵 / 便衣保安 | 从外部定时敲门,测网站通不通、慢不慢 |
| Prometheus | 情报中心 / 记录员 | 把每次探测结果按时序记录下来 |
| Grafana | 大屏指挥室 | 把记录画成折线图、仪表盘 |
| JMeter / Locust | 雇来的临时演员 | 主动发大量请求,给服务器施压 |
[压测工具 JMeter / Locust] --大量请求--> [被测网站 www.baidu.com]
[Blackbox Exporter :9115] --每 15 秒探测--> [被测网站]
[Prometheus :9090] --每 15 秒拉取--> [Blackbox Exporter]
[Grafana :3000] --查询指标--> [Prometheus]
[你] --看大屏--> [Grafana]
一句话总结:
Blackbox 去敲门,Prometheus 记笔记,Grafana 画图,压测工具负责制造 “人多” 的场景。
两者配合,才能得出最有价值的结论:临界点。
所有工具放在同一个盘、同一层目录,路径不要有中文和空格(很多工具对中文路径支持很差)。
D:\monitor\
├── prometheus\
├── blackbox\
├── grafana\
├── jmeter\ 可选
└── locust\ 可选
三个组件分别使用 9090 / 9115 / 3000 端口。先在 CMD 里确认:
netstat -ano | findstr :9090
netstat -ano | findstr :9115
netstat -ano | findstr :3000
本手册统一使用百度首页,方便任何人零成本复现:
https://www.baidu.com/
换成自己的地址时,后面所有配置和命令里的协议、域名、端口、路径都要同步替换。
注意:百度是第三方公网站点,只用来验证监控链路是否打通。不要对百度做高并发压测,正式压测请换成自己的测试环境。
prometheus-<版本>.windows-amd64.zip,例如 prometheus-3.5.0.windows-amd64.zip。D:\monitor\prometheus\,目录结构如下:D:\monitor\prometheus\
├── prometheus.exe 主程序
├── promtool.exe 配置校验 / 调试工具
├── prometheus.yml 配置文件,本次要改的就是它
└── data\ 首次启动后生成,存放时序数据
用记事本或 VS Code 打开 prometheus.yml,清空原有内容,整体替换为下面这份:
# ============ 全局配置 ============
global:
scrape_interval: 15s # 全局默认抓取间隔:每 15 秒拉一次数据
evaluation_interval: 15s # 告警规则评估间隔,本手册不配告警,保留默认
# ============ 抓取任务列表 ============
scrape_configs:
# ---------- 任务 1:监控 Prometheus 自己 ----------
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
# ---------- 任务 2:黑盒探测(配合 blackbox_exporter) ----------
- job_name: "blackbox_http"
metrics_path: /probe # 注意:这里是 /probe,不是默认的 /metrics
params:
module: [http_2xx] # 使用 http_2xx 模块,返回 2xx 视为成功
static_configs:
- targets:
- https://www.baidu.com/ # 改成你要监控的网页
relabel_configs:
# 下面三行是固定写法:把目标地址传给 blackbox 去探测
# 1. 把目标地址存入临时标签 __param_target
- source_labels: [__address__]
target_label: __param_target
# 2. 同时记成 instance 标签,Grafana 图例才会显示网址
- source_labels: [__param_target]
target_label: instance
# 3. 把真正请求的地址改成 blackbox 的地址
- target_label: __address__
replacement: localhost:9115
YAML 有三条硬性规则:
: 后面必须有一个空格,例如 scrape_interval: 15s,写成 scrape_interval:15s 会解析失败。改完先校验一遍,能提前发现绝大多数格式错误:
cd /d D:\monitor\prometheus
.\promtool.exe check config prometheus.yml
出现 SUCCESS: prometheus.yml is valid prometheus config file syntax 即表示配置合法。
打开 CMD(Win + R 输入 cmd 回车),执行:
cd /d D:\monitor\prometheus
.\prometheus.exe --config.file=prometheus.yml --web.enable-lifecycle
参数说明:
| 参数 | 作用 |
|---|---|
--config.file=prometheus.yml |
指定配置文件路径 |
--web.enable-lifecycle |
开启热加载,改完配置无需重启进程 |
启动成功后 CMD 窗口不要关闭,关闭即停止服务。窗口里会出现类似日志:
level=info msg="Server is ready to receive web requests."
如果想延长数据保留时间,可以追加 --storage.tsdb.retention.time=30d。数据存放在 data\ 目录,删掉该目录即清空历史。
浏览器打开 http://localhost:9090,进入 Status → Targets,应该看到两个任务,状态都是 UP:
| 任务 | 目标 | 状态 |
|---|---|---|
prometheus |
http://localhost:9090/metrics |
UP |
blackbox_http |
https://www.baidu.com/ |
UP |
如果 blackbox_http 是 DOWN,通常是 Blackbox Exporter 还没启动,或者 replacement 里的地址、端口填错。启动 Blackbox 后刷新页面,最多等 15 秒。
无需重启,另开一个 CMD 执行:
curl -X POST http://localhost:9090/-/reload
Lifecycle API is not enabled:说明启动时忘了加 --web.enable-lifecycle,只能重启进程。blackbox_exporter-<版本>.windows-amd64.zip,解压到 D:\monitor\blackbox\。D:\monitor\blackbox\
├── blackbox_exporter.exe 主程序
└── blackbox.yml 配置文件,默认即可
官方默认的 blackbox.yml 可以直接使用,不需要修改。它内置了多种探测模块:
| 模块名 | 用途 |
|---|---|
http_2xx |
发 HTTP 请求,返回 2xx 视为成功,最常用 |
http_2xx_example |
带自定义请求头的示例写法 |
tcp_connect |
只测 TCP 端口是否连通 |
icmp |
Ping 探测,Windows 下需要管理员权限 |
dns_udp |
测试 DNS 解析 |
用记事本打开 blackbox.yml 可以看到每个模块的注释说明。
直接双击 blackbox_exporter.exe,弹出的黑窗口会显示:
level=info msg="Listening on address" address=:9115
保持窗口不关闭,默认监听 9115 端口。
如果端口被占用,可以在 CMD 里换端口启动:
.\blackbox_exporter.exe --web.listen-address=":9116"
换端口后,记得把 Prometheus 配置里的 replacement: localhost:9115 同步改掉。
浏览器打开 http://localhost:9115,能看到标题为 Blackbox Exporter 的页面即启动成功。
再手动测一次探测,单独验证目标网站通不通:
curl "http://localhost:9115/probe?target=https://www.baidu.com/&module=http_2xx"
返回内容很长,重点看这两行:
probe_success 1 # 1 表示成功,0 表示失败
probe_duration_seconds 0.123 # 本次探测耗时,单位秒
probe_success 1:网址可正常访问,链路没问题。probe_success 0:网站不可达,检查地址是否写错、本机能否打开、是否有防火墙或内网限制。D:\monitor\grafana\。bin 目录,双击 grafana-server.exe,同样保持黑窗口不关闭。Grafana 是 Go 编写的单文件程序,不需要安装 Java、Node 或数据库,解压即用。数据默认保存在 data\grafana.db(SQLite)。
浏览器打开 http://localhost:3000:
admin
admin
admin123。Prometheus,点击结果中的 Prometheus。http://localhost:9090,其他选项保持默认。Successfully queried the Prometheus API. 即连接成功。Grafana 社区有现成的 Blackbox Exporter 面板,ID 为 7587,不需要自己从零画图。
7587,点击 Load。DS_SIGNCL-PROMETHEUS 下拉框里选择刚才创建的数据源。面板里会显示这些内容:
| 面板 | 说明 |
|---|---|
| Probe Success | 探测成功率,正常为 1 |
| Probe Duration | 每次探测耗时曲线 |
| HTTP Status Code | 返回的状态码分布 |
| Probe Duration Phases | 耗时拆解:DNS、连接、TLS、首字节、传输 |
| SSL Certificate Expiry | HTTPS 证书剩余天数 |
面板左上角是时间范围(默认 Last 6 hours),右上角是自动刷新按钮(默认 30s 或 1m),打开后才能看到实时变化。
推荐启动顺序:
1. Blackbox Exporter(:9115)
2. Prometheus(:9090) 依赖 Blackbox,先启动它可避免 Targets 出现 DOWN
3. Grafana(:3000) 依赖 Prometheus
停止时顺序反过来:先关 Grafana,再关 Prometheus,最后关 Blackbox。实际上数据不会丢失,顺序影响不大,但这样最稳妥。
嫌窗口太多,可以在 D:\monitor\ 下新建 start-all.bat,双击即可全部启动:
@echo off
chcp 65001 >nul
echo 正在启动监控三件套...
start "Blackbox" cmd /k "cd /d D:\monitor\blackbox && blackbox_exporter.exe"
timeout /t 2 >nul
start "Prometheus" cmd /k "cd /d D:\monitor\prometheus && prometheus.exe --config.file=prometheus.yml --web.enable-lifecycle"
timeout /t 2 >nul
start "Grafana" cmd /k "cd /d D:\monitor\grafana\bin && grafana-server.exe"
echo 启动完成:
echo Blackbox http://localhost:9115
echo Prometheus http://localhost:9090
echo Grafana http://localhost:3000
pause
如果需要主动模拟大量用户访问,JMeter 和 Locust 是两款主流工具,先分清定位再选。
| 对比维度 | JMeter | Locust |
|---|---|---|
| 上手难度 | 零代码,图形界面 | 需要写 Python |
| 协议支持 | 非常广,HTTP / JDBC / FTP 等 | 以 HTTP 为主,可扩展 |
| 资源占用 | GUI 模式吃内存 | 单机性能好,基于协程 |
| 脚本形式 | .jmx 文件 | locustfile.py |
| 分布式 | 支持,配置稍繁琐 | 支持,一条命令起 worker |
| 报告 | 聚合报告、HTML 报告 | Web UI 实时图表 |
| 适合人群 | 测试人员,偶尔压一次 | 研发人员,复杂业务流、CI |
选型建议:
JMeter 基于 Java,必须先装 JDK(8 / 11 / 17 均可,推荐 17)。
java -version
能输出版本号即可。没有的话去 https://adoptium.net/ 下载安装,安装时勾选 “添加到 PATH”。
apache-jmeter-<版本>.zip,解压到 D:\monitor\jmeter\。bin\jmeter.bat(Windows 下不要用 jmeter.sh)。第一次启动可能弹窗询问是否允许 Java 通过防火墙,点击允许。
按下面的顺序,在左侧树里右键添加。
第 1 步:添加线程组
右键 “测试计划”→ 添加 → 线程(用户)→ 线程组。在线程组面板里设置三个关键参数:
| 参数 | 含义 | 演示值 | 说明 |
|---|---|---|---|
| 线程数 | 并发用户数 | 10 | 对百度演示用 10,压自己环境再调大 |
| Ramp-Up | 多少秒内启动完所有用户 | 10 | 不要设为 0,否则瞬间冲击 |
| 循环次数 | 每个用户执行几轮 | 10 | 勾选 “永远” 则一直压到手动停止 |
第 2 步:添加 HTTP 请求
右键 “线程组”→ 添加 → 取样器 → HTTP 请求,按下表填写:
| 字段 | 填写内容 |
|---|---|
| 协议 | https |
| 服务器名称或 IP |
www.baidu.com(不要带 https://) |
| 端口号 | 443 |
| 路径 | / |
| 方法 | GET |
第 3 步:添加监听器
点击工具栏的绿色三角形开始压测。右上角的绿色数字表示当前运行的线程数。停止时点击红色方形,不要直接关闭窗口,否则可能导致 JVM 卡死。
聚合报告里重点看这几列:
| 列名 | 含义 | 判断方式 |
|---|---|---|
| # Samples | 总请求数 | 越多说明压得越久 |
| Average | 平均响应时间 | 突然变大说明服务端开始吃力 |
| 90% Line | 90% 请求的耗时上限 | 比平均值更接近真实体验 |
| Error % | 错误率 | 从 0 开始上升说明扛不住了 |
| Throughput | 吞吐量 | 到顶不再上升说明达到瓶颈 |
GUI 只用来编排脚本。正式压测请使用命令行,省内存且结果更准:
jmeter -n -t your_plan.jmx -l result.jtl -e -o report
-n:非 GUI 模式-t:指定脚本-l:结果文件-e -o:生成 HTML 报告到 report 目录确认已安装 Python 3.9 及以上版本,然后执行:
pip install locust
locust --version
新建目录 D:\monitor\locust\,创建 locustfile.py:
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
# 每次请求后随机等待 1~3 秒,模拟真实用户的思考时间
wait_time = between(1, 3)
@task
def index_page(self):
# 访问首页,host 在启动命令里指定
self.client.get("/")
想模拟多步行为,再增加一个 @task 方法即可。@task(3) 里的数字是权重,表示被选中的概率是其他任务的 3 倍。
在脚本目录打开 CMD:
locust -f locustfile.py --host=https://www.baidu.com
浏览器访问 http://localhost:8089,填写:
| 字段 | 演示值 | 含义 |
|---|---|---|
| Number of users | 10 | 总虚拟用户数 |
| Spawn rate | 2 | 每秒启动的用户数 |
| Host | 已指定 | 可留空 |
点击 Start 后即可看到实时图表:RPS、响应时间、失败率、当前用户数。
换成自己的测试环境后,再按 “先小后大” 逐步加到 100 / 500 / 1000。不要对百度拉起 1000 并发。
正式压测或 CI 场景使用命令行,把 host 换成自己的测试环境:
locust -f locustfile.py --host=https://your-test-env.example.com --headless -u 1000 -r 100 -t 5m
| 参数 | 含义 |
|---|---|
--headless |
不启动 Web UI |
-u 1000 |
1000 个虚拟用户 |
-r 100 |
每秒启动 100 个 |
-t 5m |
持续压 5 分钟 |
跑完会在命令行打印汇总统计,也可以加 --csv=result 导出 CSV。
一台机器压不动(CPU 打满但服务端很轻松)时,可以起多台机器。
:: 主控机,只发号施令
locust -f locustfile.py --master
:: 压测机,可以多台
locust -f locustfile.py --worker --master-host=主控机IP
主控机的 Web UI 会汇总所有 worker 的数据。
目标:验证被测网站在逐步加压下会不会变慢或挂掉,并能用监控数据定位瓶颈。
重要前提:本手册的被测目标是百度,只适合验证监控链路是否打通。百度是第三方公网站点,绝对不要对它做 500 / 1000 这类高并发压测。正式压测请把地址换成自己负责的测试环境。
用 Locust 对百度发起 10 个用户、持续 2 分钟的轻量访问,确认 “压测流量 → 黑盒探测 → Grafana 曲线” 整条链路是通的:
locust -f locustfile.py --host=https://www.baidu.com --headless -u 10 -r 2 -t 2m
此时 Grafana 上 probe_success 应恒为 1,probe_duration_seconds 保持平稳,即链路验证成功。
把地址换回自己的服务,按 “先小后大” 逐步加压。
| 阶段 | 并发用户数 | Spawn rate | 持续时间 | 目的 |
|---|---|---|---|---|
| 基线 | 10 | 10/s | 2 分钟 | 记录健康状态下的耗时 |
| 轻压 | 100 | 20/s | 2 分钟 | 观察曲线变化 |
| 中压 | 500 | 50/s | 3 分钟 | 大概率出现拐点 |
| 高压 | 1000 | 100/s | 3 分钟 | 逼近或超过临界点 |
每个阶段之间停 30 秒,让连接池和 GC 缓一缓,也方便在 Grafana 上区分各阶段的曲线。
盯住 Grafana 面板,重点关注:
| 指标 | 正常表现 | 压力上来后的表现 |
|---|---|---|
probe_success |
一直为 1 | 变成 0,表示服务端已连不上 |
probe_duration_seconds |
0.1~0.5 秒 | 直线飙升,请求开始排队 |
probe_http_status_code |
200 | 出现 502 / 503 / 504 |
phase="connect" 耗时 |
很小 | 变大,TCP 连接建立困难 |
phase="resolve" 耗时 |
很小 | 变大,DNS 解析变慢 |
phase="transfer" 耗时 |
很小 | 变大,服务端处理慢或带宽打满 |
同时观察压测工具一侧:
黑盒监控不只知道 “挂了”,还能指出 “挂在哪一环”:
probe_success = 0
├── 未到超时阈值就失败
│ ├── phase=connect 耗时高:连接数满、防火墙、进程挂了
│ ├── phase=resolve 耗时高:DNS 问题
│ └── phase=tls 耗时高:证书、加密算法、CPU 打满
└── 顶到超时阈值(如 10s / 30s)
└── 服务端处理不过来:慢查询、线程池满、下游依赖超时
用数据说话,例如:
实测并发到 500 时,首页接口的 95 分位响应时间从 0.3s 涨到 8s,错误率从 0% 升到 12%,
probe_http_status_code开始出现 504。connect 阶段正常、transfer 阶段耗时飙升,瓶颈在应用层处理慢,不是网络问题。建议加机器、扩线程池、排查慢查询。
记得截图 Grafana(带上时间轴和压测阶段),这是最有说服力的证据。
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 服务用着用着就停了 | 黑窗口被关闭 | 最小化即可,不要点 X;或用 nssm 注册为服务 |
| Prometheus 启动报 YAML 解析错误 | 混入 Tab、缩进不对、冒号后少空格 | 用 VS Code 检查,并执行 promtool check config |
| blackbox_http 一直是 DOWN | Blackbox 未启动、地址或端口写错、目标挂了 | 先手动 curl probe 接口验证 |
| probe_success 一直是 0 | 目标返回的不是 2xx,例如 302 / 403 | 调整 module,或自定义可接受重定向的模块 |
| 报错 Lifecycle API is not enabled | 启动时没加 --web.enable-lifecycle | 加参数重启 |
| Grafana 面板全是 No data | 数据源填错、时间范围不对、Prometheus 无数据 | 先在 Prometheus 查 probe_success 是否有值 |
| Grafana 时间差 8 小时 | 时区默认 UTC | 时区改为 Asia/Shanghai |
| 端口被占用 | 9090 / 9115 / 3000 已被其他程序使用 | 用 netstat 找到 PID 并结束,或换端口 |
| 路径含中文或空格时异常 | 部分程序不支持中文路径 | 改为纯英文无空格路径 |
| JMeter GUI 高并发卡死 | GUI 模式极吃内存 | 只用于编排,压测用命令行模式 |
| Locust 报模块找不到 | pip 装到了别的 Python 环境 | 用 python -m locust,或统一 python 与 pip |
| 本机 CPU 打满但服务端健康 | 压测机自己先到瓶颈 | 降并发、关 Grafana 自动刷新、分布式压测 |
| 内网域名打不开 | 域名解析到内网,需要 VPN | 连 VPN 后再试,用 ping、nslookup 排查 |
| Prometheus 磁盘持续增长 | 历史数据累积 | 设置 retention.time,或清理 data 目录 |
nssm.exe(64 位在 win64\ 目录)。nssm install Prometheus "D:\monitor\prometheus\prometheus.exe"
nssm set Prometheus AppParameters "--config.file=D:\monitor\prometheus\prometheus.yml --web.enable-lifecycle"
nssm set Prometheus AppDirectory "D:\monitor\prometheus"
nssm start Prometheus
nssm start|stop|restart|remove <服务名>。注意:nssm 以 SYSTEM 账号运行,Prometheus 的
data\目录和 Grafana 的data\grafana.db会以该账号写入。如果之前用普通用户跑过,可能出现权限冲突,删掉data\目录重新生成即可。
| 端口 | 组件 | 访问地址 | 修改方式 |
|---|---|---|---|
| 9090 | Prometheus | http://localhost:9090 | --web.listen-address=:9091 |
| 9115 | Blackbox Exporter | http://localhost:9115 | --web.listen-address=":9116" |
| 3000 | Grafana | http://localhost:3000 | 修改 conf\defaults.ini 的 http_port
|
| 8089 | Locust Web UI | http://localhost:8089 | --web-port |
D:\monitor\
├── prometheus\
│ ├── prometheus.exe
│ ├── promtool.exe
│ ├── prometheus.yml 核心配置
│ └── data\ 时序数据,可删
├── blackbox\
│ ├── blackbox_exporter.exe
│ └── blackbox.yml 默认即可
├── grafana\
│ ├── bin\grafana-server.exe
│ ├── conf\defaults.ini 端口、路径等配置
│ └── data\grafana.db 面板、数据源、用户,备份它即可
├── jmeter\
│ └── bin\jmeter.bat
├── locust\
│ └── locustfile.py
└── start-all.bat 一键启动脚本
promtool check config prometheus.yml 通过。http://localhost:9115 能打开。probe_success 1。在 Prometheus 的 Graph 页面或 Grafana 里直接查询:
# 1. 目标是否存活,1 成功 / 0 失败
probe_success
# 2. 最近 1 分钟平均探测耗时
avg_over_time(probe_duration_seconds[1m])
# 3. 探测失败率,最近 5 分钟低于 99%
avg_over_time(probe_success[5m]) < 0.99
# 4. HTTP 状态码分布
probe_http_status_code
# 5. 耗时拆解:resolve / connect / tls / processing / transfer
probe_http_duration_seconds
# 6. HTTPS 证书剩余天数
(probe_ssl_earliest_cert_expiry - time()) / 86400
# 7. 探测成功率与耗时放在同一张图上对比
probe_success or avg_over_time(probe_duration_seconds[1m])
整套体系跑通后,你手里会有两样东西:
先有眼睛,再出手。这样每次压测都不是盲压,而是带着观测数据去找答案。