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 数据处理层:把数据「洗干净」

数据到了处理层,就像原材料进了工厂。你要做的第一件事是清洗

为什么?因为高频交易的数据太「脏」了。行情数据可能乱序、重复、甚至缺失。我遇到过最离谱的一次,交易所因为网络抖动,同一笔成交发了三遍。如果不做去重,你的延迟统计直接就炸了。

数据处理层通常包含这几个步骤:

  1. 数据清洗:去重、补全、排序。
  2. 数据聚合:比如把毫秒级的 tick 数据聚合成秒级的 K 线。
  3. 指标计算:延迟、吞吐量、订单成交率等。
  4. 数据存储:写入时序数据库或消息队列。

这里我分享一个经验:能流式处理就别批处理。高频交易的数据是源源不断的,你不可能等数据攒够了再处理。用流式计算框架(比如 Flink 或 Kafka Streams)来做实时聚合,效果会好很多。

避坑指南:我曾经用批处理的方式计算每秒的订单延迟,结果发现数据窗口总是对不齐。后来改成流式处理,用事件时间而不是处理时间,问题才解决。

数据处理层的输出,一般会写入两个地方:一个是时序数据库(比如 InfluxDB、ClickHouse),用于历史回溯;另一个是消息队列(比如 Kafka),用于实时告警。

2.4 告警与展示层:让数据「说话」

这一层是直接面对人的。你想想看,如果数据采集和处理都做得很好,但告警发不出来、图表看不清,那前面全白干。

告警这块,我个人的原则是:宁可漏报,不要误报。高频交易系统里,误报的代价太大了。一次假告警可能让交易员分心,错过真正的交易机会。

所以告警规则一定要设计得「钝」一点。比如:

  • 不要单点触发告警,而是连续 N 次超过阈值才告警。
  • 不要只看瞬时值,要看滑动窗口内的平均值。
  • 告警级别要分清楚:P0(系统不可用)、P1(功能受损)、P2(性能下降)。

展示层呢,说白了就是「一眼能看出问题」。我见过很多监控大屏,花花绿绿的图表堆了一堆,但真正有用的信息反而被淹没了。

我的建议是:展示层只放三个东西——

  1. 核心指标:延迟、吞吐量、错误率。这三个指标必须放在最显眼的位置。
  2. 异常事件:最近发生的告警和异常,按时间倒序排列。
  3. 系统健康度:用红黄绿三色表示整体状态,一眼就能看出有没有问题。

注意:展示层的刷新频率不要太高。我曾经把 Grafana 的刷新间隔设成 100ms,结果浏览器直接卡死了。对于人眼来说,1 秒刷新一次完全够用。

2.5 小结:三层架构的协作关系

最后,我用一张表格总结一下这三层的关系:

层级 输入 输出 典型技术
数据采集层 行情、系统指标、日志 原始数据(队列/消息) UDP、Kafka Producer、Agent
数据处理层 原始数据 清洗后的指标、聚合结果 Flink、Kafka Streams、InfluxDB
告警与展示层 处理后的指标 告警通知、可视化图表 Grafana、Prometheus Alertmanager

嗯,分层架构说到这里,其实核心就一句话:让每一层做它该做的事,别越界。你想想看,如果采集层跑去算指标,处理层又跑去发告警,那整个系统就乱套了。

下一章我会详细讲数据采集层的具体实现,包括怎么处理乱序数据、怎么保证采集的实时性。咱们到时候接着聊。