2、监控体系架构设计:分层监控架构、数据采集层、数据处理层、告警与展示层
好,咱们直接进入正题。监控体系怎么搭?我个人的习惯是,别一上来就想着买什么工具、用什么数据库。先想清楚一件事:你的数据从哪来,到哪去,中间怎么处理。
说白了,就是分层。把整个监控拆成三层:数据采集层、数据处理层、告警与展示层。每一层各司其职,互不干扰。这样做的好处是,哪一层出了问题,你只需要动那一层,不用把整个系统推倒重来。
2.1 分层监控架构:为什么必须分层?
我在项目中遇到过这么一件事:有个团队把所有监控逻辑写在一个脚本里,采集、处理、告警全混在一起。结果有一天行情数据量暴增,脚本卡死了,告警也发不出来。排查了半天,才发现是采集部分把CPU吃满了,导致告警线程饿死。
你看,这就是不分层的后果。分层架构的核心思想就四个字:关注点分离。
- 采集层:只负责把数据拿回来,不管数据长什么样。
- 处理层:只负责清洗、聚合、计算,不管数据怎么来的。
- 展示与告警层:只负责把结果画出来、推出去,不管底层逻辑。
这样做还有一个好处:每一层都可以独立扩展。比如行情数据量翻倍了,你只需要给采集层加机器,处理层和展示层完全不用动。
核心原则:每一层只做一件事,并且把这件事做到极致。
2.2 数据采集层:把数据「捞」回来
数据采集层是整个监控体系的「眼睛」。眼睛瞎了,后面再牛的分析也没用。
高频交易系统的数据源,我总结下来主要有三类:
| 数据源类型 | 典型数据 | 采集方式 |
|---|---|---|
| 行情数据 | Level-2 快照、逐笔成交、订单簿 | UDP 组播、TCP 直连 |
| 交易系统内部 | 订单状态、成交回报、延迟指标 | 日志采集、API 回调 |
| 基础设施 | CPU、内存、网络、磁盘 | Agent 采集、SNMP |
嗯,这里要注意一个坑。我曾经见过有人用同一个线程去采集行情和系统指标。结果行情数据量大时,系统指标的采集被阻塞了,导致 CPU 告警延迟了十几秒才触发。这在高频交易里是致命的。
我的建议是:不同数据源用不同的采集通道,最好是独立的进程或线程。行情数据走低延迟通道,系统指标走常规通道,互不干扰。
代码层面,一个简单的采集器长这样:
// 伪代码:行情数据采集器
class MarketDataCollector {
void start() {
// 绑定 UDP 组播地址
socket.bind("224.0.0.1:8888");
while (true) {
// 非阻塞接收,避免卡死
byte[] data = socket.receiveNonBlocking();
if (data != null) {
// 直接扔到队列里,不做任何处理
queue.push(data);
}
}
}
}
你看,采集层只做一件事:把原始数据扔进队列。至于数据怎么解析、怎么处理,那是下一层的事。
2.3 数据处理层:把数据「洗干净」
数据到了处理层,就像原材料进了工厂。你要做的第一件事是清洗。
为什么?因为高频交易的数据太「脏」了。行情数据可能乱序、重复、甚至缺失。我遇到过最离谱的一次,交易所因为网络抖动,同一笔成交发了三遍。如果不做去重,你的延迟统计直接就炸了。
数据处理层通常包含这几个步骤:
- 数据清洗:去重、补全、排序。
- 数据聚合:比如把毫秒级的 tick 数据聚合成秒级的 K 线。
- 指标计算:延迟、吞吐量、订单成交率等。
- 数据存储:写入时序数据库或消息队列。
这里我分享一个经验:能流式处理就别批处理。高频交易的数据是源源不断的,你不可能等数据攒够了再处理。用流式计算框架(比如 Flink 或 Kafka Streams)来做实时聚合,效果会好很多。
避坑指南:我曾经用批处理的方式计算每秒的订单延迟,结果发现数据窗口总是对不齐。后来改成流式处理,用事件时间而不是处理时间,问题才解决。
数据处理层的输出,一般会写入两个地方:一个是时序数据库(比如 InfluxDB、ClickHouse),用于历史回溯;另一个是消息队列(比如 Kafka),用于实时告警。
2.4 告警与展示层:让数据「说话」
这一层是直接面对人的。你想想看,如果数据采集和处理都做得很好,但告警发不出来、图表看不清,那前面全白干。
告警这块,我个人的原则是:宁可漏报,不要误报。高频交易系统里,误报的代价太大了。一次假告警可能让交易员分心,错过真正的交易机会。
所以告警规则一定要设计得「钝」一点。比如:
- 不要单点触发告警,而是连续 N 次超过阈值才告警。
- 不要只看瞬时值,要看滑动窗口内的平均值。
- 告警级别要分清楚:P0(系统不可用)、P1(功能受损)、P2(性能下降)。
展示层呢,说白了就是「一眼能看出问题」。我见过很多监控大屏,花花绿绿的图表堆了一堆,但真正有用的信息反而被淹没了。
我的建议是:展示层只放三个东西——
- 核心指标:延迟、吞吐量、错误率。这三个指标必须放在最显眼的位置。
- 异常事件:最近发生的告警和异常,按时间倒序排列。
- 系统健康度:用红黄绿三色表示整体状态,一眼就能看出有没有问题。
注意:展示层的刷新频率不要太高。我曾经把 Grafana 的刷新间隔设成 100ms,结果浏览器直接卡死了。对于人眼来说,1 秒刷新一次完全够用。
2.5 小结:三层架构的协作关系
最后,我用一张表格总结一下这三层的关系:
| 层级 | 输入 | 输出 | 典型技术 |
|---|---|---|---|
| 数据采集层 | 行情、系统指标、日志 | 原始数据(队列/消息) | UDP、Kafka Producer、Agent |
| 数据处理层 | 原始数据 | 清洗后的指标、聚合结果 | Flink、Kafka Streams、InfluxDB |
| 告警与展示层 | 处理后的指标 | 告警通知、可视化图表 | Grafana、Prometheus Alertmanager |
嗯,分层架构说到这里,其实核心就一句话:让每一层做它该做的事,别越界。你想想看,如果采集层跑去算指标,处理层又跑去发告警,那整个系统就乱套了。
下一章我会详细讲数据采集层的具体实现,包括怎么处理乱序数据、怎么保证采集的实时性。咱们到时候接着聊。