4. 哨兵架构设计:哨兵系统的分层架构
高频行情坏账率哨兵系统需要处理海量实时行情数据,并在毫秒级内完成计算与告警。为满足高吞吐、低延迟、可扩展的要求,系统采用经典的四层分层架构:采集层、计算层、告警层、存储层。每一层职责清晰,层间通过轻量级消息队列或API解耦,便于独立扩展与维护。
架构设计原则:每一层只关注自己的核心职责,不跨层调用数据库或外部服务。层间通信使用异步消息(Kafka / Pulsar),避免同步阻塞导致行情积压。
4.1 四层架构总览
下图展示了哨兵系统的完整分层结构,以及数据在各层之间的流转路径:
4.2 采集层:行情入口与第一道防线
采集层是哨兵系统的数据入口,负责从交易所、行情源或消息中间件接收原始高频行情数据。该层必须处理协议多样性、数据乱序、重复数据等现实问题。
| 组件 | 职责 | 关键技术 |
|---|---|---|
| 行情网关 | 对接不同交易所的行情协议(FIX/FAST/Binary) | Netty / Reactor 模型 |
| 协议解析器 | 将二进制或文本协议转为统一内部格式 | Protobuf / FlatBuffers |
| 数据清洗 | 去重、时间戳校准、异常值过滤 | 布隆过滤器 / 滑动去重 |
| 流量控制 | 背压机制防止下游过载 | Reactive Streams / 令牌桶 |
采集层关键指标:单节点吞吐量 ≥ 100万 msg/s,端到端延迟 ≤ 1ms(从行情到达网关到输出清洗后数据)。
4.3 计算层:坏账率实时计算引擎
计算层是哨兵系统的核心大脑,接收采集层输出的标准化行情流,执行坏账率相关的实时计算逻辑。该层采用事件驱动 + 微批处理混合模式,兼顾延迟与计算精度。
- 滑动窗口聚合:按时间窗口(如1秒、5秒、1分钟)统计成交笔数、失败笔数、坏账金额。
- 坏账率公式:坏账率 = (失败成交笔数 + 异常撤销笔数) / 总成交笔数 × 100%
- 异常检测模型:基于统计阈值(3σ)或轻量级机器学习模型(Isolation Forest)识别突发异常。
- 状态管理:使用 RocksDB 或 Redis 维护窗口状态,支持故障恢复。
// 坏账率计算核心伪代码(Flink DataStream API)
DataStream<MarketTrade> trades = env.addSource(kafkaSource);
trades
.keyBy(trade -> trade.getSymbol())
.window(SlidingProcessingTimeWindows.of(Time.seconds(5), Time.seconds(1)))
.aggregate(new BadRateAggregate())
.filter(rate -> rate.getValue() > BAD_RATE_THRESHOLD)
.map(rate -> new AlertEvent(rate.getSymbol(), rate.getValue(), System.currentTimeMillis()))
.addSink(alertSink);
注意:计算层必须处理数据倾斜问题。热门股票(如AAPL、TSLA)的行情量可能是冷门股票的1000倍以上,需要采用二级Key拆分或动态负载均衡策略。
4.4 告警层:分级通知与智能抑制
告警层接收计算层输出的异常事件,根据预设规则进行分级、聚合、抑制,并路由到不同的通知渠道。避免告警风暴是告警层设计的首要目标。
告警层核心功能包括:
- 告警分级:P0(坏账率 > 5% 且持续10秒)→ 立即电话通知;P1(坏账率 > 3%)→ 短信+即时消息;P2(坏账率 > 1%)→ 邮件日报。
- 告警抑制:同一标的在5分钟内不重复发送同级别告警,避免轰炸。
- 告警恢复:当坏账率回落至阈值以下并持续30秒,自动发送恢复通知。
4.5 存储层:多模态数据持久化
存储层负责保存原始行情、计算结果、告警事件和元数据,为事后分析、模型训练和审计提供数据基础。不同数据类型使用不同的存储引擎,以优化读写性能。
| 数据类型 | 存储引擎 | 保留周期 | 主要查询模式 |
|---|---|---|---|
| 原始行情Tick | InfluxDB / TimescaleDB | 7天(热)→ 30天(温)→ 1年(冷) | 按时间范围 + 标的查询 |
| 坏账率指标 | Prometheus + Thanos | 90天 | 实时仪表盘、趋势分析 |
| 告警事件 | Elasticsearch | 180天 | 全文检索、聚合统计 |
| 元数据/配置 | MySQL / PostgreSQL | 永久 | CRUD、关联查询 |
存储层优化建议:原始行情数据写入量极大(每天TB级),建议使用列式存储 + 时间分区 + 数据降采样策略。热数据保留在SSD上,冷数据自动迁移到对象存储(S3/MinIO)。
4.6 层间通信与数据一致性
四层架构通过Apache Kafka作为核心消息总线解耦。每层只与Kafka交互,不直接调用其他层的API。这种设计带来以下优势:
- 流量削峰:行情突发时,Kafka作为缓冲区吸收瞬时流量。
- 故障隔离:某一层宕机不影响其他层正常运行。
- 水平扩展:每层可独立增加消费者或生产者实例。
# 层间Topic命名规范
采集层输出: raw.market.tick.{exchange}.{symbol}
计算层输出: computed.badrate.{symbol}.{window}
告警层输出: alert.event.{level}
存储层消费: storage.raw.tick, storage.badrate, storage.alert
数据一致性保障:由于采用异步消息,计算层可能收到乱序数据。必须为每条行情数据携带单调递增的序列号,计算层在窗口聚合前先做序列号校验,丢弃或重排乱序数据,确保坏账率计算的准确性。