2、监控体系设计:监控的黄金指标与分层架构
监控体系设计,说白了就是回答三个问题:看什么、怎么看、怎么收。我在多个实时OLAP项目中踩过不少坑,今天把这些经验拆开揉碎了讲给你听。
2.1 监控的黄金指标:四个维度锁定系统健康
Google SRE 那本圣经里提过四个黄金指标——延迟、吞吐、错误率、饱和度。我自己的经验是,这四个指标能覆盖 90% 的线上问题。你想想看,一个实时OLAP系统,用户最关心什么?查得快不快、查得准不准、能不能扛住并发。
核心原则:不要贪多。我见过有人一上来就配 200 个指标,结果告警全淹了。先盯住这四个,再慢慢加。
2.1.1 延迟(Latency)
延迟就是用户从发起查询到拿到结果的时间。实时OLAP里,延迟通常分两段:查询延迟和数据写入延迟。
- 查询延迟:P50、P95、P99 都要看。我习惯把 P99 作为红线,超过 5 秒就要人工介入。
- 写入延迟:从数据进入 Kafka 到 ClickHouse 可查询的时间。我曾经遇到过一个 case,写入延迟从 2 秒飙到 30 秒,结果是因为 MergeTree 的合并线程卡住了。
避坑指南:延迟指标一定要分位点看。只看平均值会骗人——P50 正常,P99 可能已经炸了。
2.1.2 吞吐(Throughput)
吞吐就是单位时间内系统处理了多少请求或数据量。实时OLAP里,我主要关注两个维度:
- QPS(每秒查询数):这个指标直接反映系统负载。我习惯把 QPS 和 CPU 使用率放在一张图上对比,能快速判断瓶颈在哪。
- 写入吞吐(Rows/s 或 MB/s):数据写入速度。如果写入吞吐突然下降,大概率是磁盘 IO 或网络带宽打满了。
2.1.3 错误率(Error Rate)
错误率是最直接的「系统挂了」信号。但要注意,错误率不能只看 HTTP 500。实时OLAP里,还有两种「隐形错误」:
- 查询超时:虽然没返回错误码,但用户等不到结果。
- 数据不一致:写入成功了,但查询结果不对。这种错误最难排查,我一般靠数据校验任务来发现。
注意:错误率告警阈值不要设得太死。比如 ClickHouse 偶尔会因为内存不足返回错误,但重试一次就好了。我一般设 1% 为告警线,5% 为 P0 事件。
2.1.4 饱和度(Saturation)
饱和度衡量系统资源被用到了什么程度。实时OLAP里,最容易饱和的资源是:
| 资源类型 | 关键指标 | 饱和阈值(我的经验值) |
|---|---|---|
| CPU | 用户态使用率、iowait | 持续 > 80% |
| 内存 | 可用内存、Swap 使用量 | 可用内存 < 10% |
| 磁盘 IO | IOPS、磁盘队列长度 | 队列长度 > 磁盘数 * 2 |
| 网络 | 带宽使用率、TCP 重传率 | 带宽 > 70% 或重传率 > 1% |
嗯,这里要注意:饱和度指标要结合延迟一起看。比如 CPU 到了 90%,但延迟没涨,那可能只是业务高峰,不用急着扩容。
2.2 监控分层架构:从硬件到业务,层层穿透
我习惯把监控分成三层:基础设施层、服务层、业务层。每一层关注的点不一样,告警的优先级也不一样。
2.2.1 基础设施层
这一层是地基。CPU、内存、磁盘、网络,任何一个出问题,上层服务都跑不稳。我个人的习惯是:基础设施层的告警要「快」,比如磁盘空间低于 10% 就立刻报警,别等到写不进去了再处理。
- CPU:不光看使用率,还要看 iowait。iowait 高说明磁盘是瓶颈。
- 内存:ClickHouse 是内存大户,Swap 使用量超过 0 就要警惕。
- 磁盘:实时OLAP 的写入量很大,我一般给磁盘空间告警设两个阈值:80% 警告,90% 紧急。
- 网络:TCP 重传率是个好指标,重传率高说明网络质量差。
2.2.2 服务层
服务层监控的是中间件和应用本身。比如 ClickHouse、Kafka、ZooKeeper 这些。这一层的指标最丰富,也最容易配乱。
我建议你从这几个维度入手:
- ClickHouse:查询延迟、合并队列长度、连接数、内存使用。
- Kafka:消费延迟、分区 Leader 分布、ISR 数量。
- ZooKeeper:请求延迟、连接数、Watch 数量。
个人经验:服务层的告警要「准」。比如 ClickHouse 的合并队列长度,短时间飙升可能是正常的,持续 10 分钟以上才需要处理。我一般加一个「持续 N 分钟」的条件。
2.2.3 业务层
业务层监控的是用户能感知到的指标。比如报表打开速度、数据刷新延迟、查询成功率。这一层的告警优先级最高,因为直接影响业务。
我记得有一次,基础设施层和服务层指标都正常,但业务方反馈报表数据不对。查了半天,发现是数据管道里一个字段映射错了。从那以后,我坚持在业务层加数据校验监控。
2.3 监控数据采集方式:Agent、Exporter、埋点
数据怎么收?市面上主流的方式就三种:Agent、Exporter、埋点。我根据场景选,不迷信某一种。
| 采集方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Agent | 基础设施监控(CPU、内存、磁盘) | 部署简单,采集全面 | 占用少量系统资源 |
| Exporter | 中间件监控(ClickHouse、Kafka) | 标准化接口,社区支持好 | 需要单独部署和配置 |
| 埋点 | 业务层监控(查询延迟、错误率) | 数据精准,可自定义 | 需要改代码,侵入性强 |
2.3.1 Agent 方式
Agent 是最传统的方式。在每台机器上装一个采集程序,比如 node_exporter 或 telegraf,定期上报系统指标。
我一般用 node_exporter 采集基础设施指标,配合 Prometheus 做存储和告警。配置很简单:
# node_exporter 启动命令示例
./node_exporter \
--web.listen-address=:9100 \
--collector.filesystem.mount-points-exclude=^/(sys|proc|dev) \
--collector.netstat.fields="*"
注意:Agent 采集频率不要太高。我见过有人设 1 秒采集一次,结果 Agent 自己占用了 10% 的 CPU。一般 15 秒一次就够了。
2.3.2 Exporter 方式
Exporter 是 Prometheus 生态的标准做法。每个中间件都有自己的 Exporter,比如 clickhouse_exporter、kafka_exporter。
我个人比较喜欢 Exporter 方式,因为它是「推模式」的变种——Exporter 暴露 HTTP 接口,Prometheus 定期去拉。这样采集端无状态,扩容方便。
举个例子,ClickHouse 的 Exporter 配置:
# prometheus.yml 中的 job 配置
scrape_configs:
- job_name: 'clickhouse'
static_configs:
- targets: ['clickhouse01:9363', 'clickhouse02:9363']
metrics_path: '/metrics'
scrape_interval: 15s
2.3.3 埋点方式
埋点是在应用代码里手动插入监控逻辑。比如在查询接口里记录耗时、结果大小、是否成功。这种方式最灵活,但也最「重」。
我一般在业务层用埋点。比如在 ClickHouse 查询的入口和出口加一段代码:
// 伪代码:查询埋点示例
long start = System.currentTimeMillis();
try {
ResultSet rs = clickHouseClient.executeQuery(sql);
long latency = System.currentTimeMillis() - start;
// 上报延迟和结果行数
metricsCollector.record("query.latency", latency);
metricsCollector.record("query.rows", rs.getRowCount());
metricsCollector.increment("query.success");
} catch (Exception e) {
metricsCollector.increment("query.error");
// 记录错误类型
metricsCollector.record("query.error_type", e.getClass().getSimpleName());
}
避坑指南:埋点代码不要影响主流程。我习惯用异步上报,或者用内存队列攒一批再发。否则监控代码本身可能成为性能瓶颈。
2.4 小结:怎么选?
其实没有银弹。我自己的经验是:
- 基础设施层:用 Agent(node_exporter)
- 服务层:用 Exporter(clickhouse_exporter、kafka_exporter)
- 业务层:用埋点(自己写代码上报)
三层数据统一汇到 Prometheus 或 VictoriaMetrics,再用 Grafana 展示。嗯,这套组合拳我用了好几年,基本没出过大问题。