跳转到内容

监控 Aeron®:面向你的可观测性平台的指标与告警

Aeron 在共享内存中暴露了一套丰富的无锁计数器——但它不提供 /metrics 端点。要把这些信号接入你公司的 Prometheus/Grafana/Datadog 平台,你要么写一个小 exporter(OSS),要么运行 Aeron Insights(Premium)。本页涵盖这两条路,然后把真正重要的计数器映射到它们所预示的故障模式,以及应当接入的告警条件。

每个 Aeron media driver 都会在其 Aeron 目录中维护一个 command-and-control 文件 cnc.dat,以内存映射方式存在。它的各个区域中包含 counters metadata buffercounters values buffererror-log buffer。计数器就是由 driver 无锁更新的普通 64 位值;任何外部进程都可以以只读方式内存映射该文件并实时读取它们,用 Aeron 自己的话说——「对性能无显著影响」。

这就是全部的接入面。没有 push、没有 agent 协议、没有 HTTP——你映射文件并遍历。参考读取器是 AeronStataeron-stat 脚本),它每秒循环一次并打印所有计数器。底层它做的事和任何 exporter 完全一样:

// 规范的读取模式——用 Agrona 的 CountersReader 读取映射后的 cnc.dat
final CountersReader counters = cncFileReader.countersReader();
counters.forEach((counterId, typeId, keyBuffer, label) -> {
final long value = counters.getCounterValue(counterId);
// → 把 {counterId, typeId, label, value} 发给你的 metrics 客户端
});

计数器按 type id 分组:0–99 client/driver,100–199 archive,200–299 cluster。当你把计数器转成指标时,这个 type id 就是你的路由键。

路径 1 —— OSS:自己写(或复用)一个计数器 exporter

Section titled “路径 1 —— OSS:自己写(或复用)一个计数器 exporter”

Aeron OSS 没有原生的 Prometheus exporter。这是有意为之,Aeron 自己的 cookbook 也把你指向自建路线:「用 CountersReader 读取计数器数据」并喂给一个指标系统,「例如 DataDog 或 Prometheus」。模式是一个每节点 sidecar,它映射该节点的 cnc.dat,按定时遍历计数器,然后暴露 /metrics(供 Prometheus 抓取)或 push 给 StatsD/Datadog/CloudWatch。

你不必从零写起——已经有几个社区 exporter 实现了这一点:

Exporter是什么状态
singleplayer88/aeron-exporter通过 CncFileReader/CountersReader 读取 cnc.dat,用 Jetty 提供 /metrics。Apache-2.0。近期维护(2026)
fairtide/aeron-prometheus-stat同样的 CnC 读取模式,把计数器重命名为 Prometheus 惯例;附带 Docker Compose。Apache-2.0。较旧(约 2023)
scalecube/scalecube-metrics构建在 Agrona counters + HdrHistogram 之上的遥测,带一个 Prometheus-over-Aeron demo。活跃维护中

对于 Datadog、StatsD 或 CloudWatch,没有现成的集成——同样是那套 CountersReader.forEach 循环,只不过改成 push 给对应平台的客户端,而非暴露 /metrics。基于日志抓取的降级方案(解析每秒一次的 aeron-stat 控制台输出)也能用,但严格来说更差:更粗粒度、有损,而且是在重新解析你本已拥有为数值的文本。

Aeron Insights(Premium,当前为 beta)是路径 1 的开箱即用版本。它提供 Prometheus exporter、一个 Grafana 示例仪表盘,以及一个 CLI。这些 exporter「通过读取 Aeron 创建的文件——主要是 CnC 文件」——外加 archive/cluster mark 文件来采集数据,也就是同一套只读方法,只是被打包并受支持——提供两种每节点交付模式:

  • HTTP-server exporter(默认 :8080,localhost)—— Prometheus 直接抓取每个节点。这是常见做法。
  • Push-client exporter —— 按间隔(默认 1s)推送给一个 Prometheus Push Gateway。

回报是:Insights 开箱即发出有名字、有文档的 Prometheus 指标cluster_*driver_*archive_*),并带一个 Grafana「Cluster Overview」仪表盘,而不是一堆你得自己命名和维护的、只带 type id 的原始计数器。

OSS 自建 exporterPremium Aeron Insights
读取cnc.dat(靠你的代码)cnc.dat + mark 文件(已打包)
指标命名你自己定义有文档的 cluster_* / driver_* / archive_*
Grafana 仪表盘你自己搭附带「Cluster Overview」示例
交付方式你写什么就是什么HTTP 抓取或 Push Gateway
支持社区 / 自己Adaptive(beta)
成本免费(Apache-2.0)订阅

真正重要的计数器(以及「坏」长什么样)

Section titled “真正重要的计数器(以及「坏」长什么样)”

你不需要把 Aeron 的所有计数器都放上仪表盘。对一个集群化的撮合引擎来说,下面这些是承重的。OSS 列是 CnC 文件里的计数器标签 / type id;Insights 列是对应的 Prometheus 指标名(若存在)。

信号OSS 计数器 (type id)Insights 指标如何解读
Commit positionCluster commit-pos: (203)cluster_commit_position_total集群的心跳——被 quorum 复制到的 log 位置
Append positionlog recording 的 archive rec-pos(无专门指标)leader 已追加到哪里;与 commit 的差距 = follower 滞后
节点角色Cluster node role (201)cluster_node_role2 = Leader,0 = Follower,1 = Candidate
共识状态Consensus Module state (200)cluster_consensus_module_state1 = Active,3 = 正在打快照
选举状态 / 计数Cluster election state (207) / election count (238)cluster_election_state稳态 = 17(Closed);计数不应上升
CM 周期时间Cluster max cycle time in ns (216) / exceeded (217)cluster_max_cycle_time_secondsconsensus module 的 duty-cycle 延迟
Service 周期时间Cluster container max cycle time in ns (218) / exceeded (219)(带 service 标签的 cycle 指标)你的服务代码的 duty-cycle 延迟
错误Cluster Errors (212) / Cluster Container Errors (215)cluster_errors_total单调累计——任何增量都值得一看
有效快照Cluster snapshot count (205)cluster_valid_snapshots可用快照的数量
快照年龄(由 recording-log 时间戳推算)cluster_last_snapshot_timestamp_seconds旧快照 ⇒ 恢复时回放漫长
快照时长Total max snapshot duration in ns (234) / exceeded (235)cluster_snapshot_duration_threshold_exceeded_total长快照会拖住热路径(OSS)
背压snd-bpe (13) / Sender flow control limitsdriver_sender_bpe_total「健康系统中应为零」
丢包 / NAKNAKs sent/receivedRetransmits sent(type 0)driver_nak_messages_*_totaldriver_retransmits_sent_total网络丢包 ⇒ 复制被拖慢
存活性(计数器更新的新鲜度)cluster_activity_age_secondsdriver_heartbeat_age_seconds距该组件上次活跃过去了多少秒

下面每一项都把一个指标绑定到某个故障模式运维手册场景。Aeron 几乎不发布任何数值阈值——下表中的计时器是有文档的;其余都属于运维判断,因此要对照你自己的基线来校准,并从宽松阈值起步以避免告警疲劳。

告警条件依据 / 文档来源
Commit 停滞(严重)状态为 Active 时 commit-pos 增量 == 0 持续 > 约 10sAeron 自己的「No catchup progress」警告会在 commit 停止推进、超过 **leader 心跳超时(默认 10s)**时触发。成因:应用代码慢、机器负载、GC。
无 leader(严重)超过选举超时仍无节点报告角色 == Leader (2)选举进行中 = 集群没在提交。
选举频繁(高)election count (238) 在上升,或 election state 不回到 17(Closed)每一次自增都是一次 p99 悬崖。触发条件:心跳超时、丢失 quorum。(「Election storm」不是文档术语——自己定速率。)
Follower 滞后(中)rec-pos(log) − commit-pos 随时间增长leader 追加的速度快于 quorum 确认——正走向背压或 quorum 丢失。无文档化的差距阈值。
周期时间超限(中)cycle time exceeded 计数器(217/219)在自增CM 与 service 的 duty-cycle 阈值默认为 100ms。尖刺 = GC / CPU 饥饿;一次 10ms 的周期就是 p99 上一个 10ms 的坑。
错误上升(高)Cluster Errors (212) 增量 > 0然后通过 ClusterTool errors 读文本。无文档化的数值速率。
快照过旧(中)当前时间 − cluster_last_snapshot_timestamp_seconds > 你的恢复预算Aeron 中快照是手动的——旧快照意味着重启时漫长的 log 回放。见快照失败与恢复
快照过慢(低/中)快照时长 exceeded (235) 在自增阈值默认 1s。在 OSS 中快照会拖住热路径;在 leader 上则会落在最大延迟上。
背压 / 丢包(中)snd-bpe、NAK 或重传速率高于基线subscriber/follower 跟不上,或网络丢包拖慢复制。无文档化的速率阈值。
存储耗尽(严重)archive/cluster 卷的可用空间低于你的下限archive 存储耗尽会抛 ClusterTerminationException终止节点——这是唯一一种总是终止性的快照/archive 故障。要在它发生之前告警。
节点失联(严重)cluster_activity_age_seconds / driver_heartbeat_age_seconds 在上升,或抓取目标掉线该组件停止更新计数器——进程已死或卡死。

如果你只搭一组面板,就照这个来——从上到下按你排障的顺序排列:

  1. 它还活着吗? 每个节点的角色(恰好一个 Leader)、存活/心跳年龄、抓取目标是否在线。
  2. 它在推进吗? commit-position 速率(你真正的吞吐量)以及 append−commit 差距。
  3. 它稳定吗? 选举计数(一条平线 = 健康)以及 consensus-module 状态。
  4. 瓶颈是你的代码吗? service 周期时间 vs. consensus 周期时间——若 service ≫ consensus,问题在你的 handler,而非 Raft。
  5. 底层健康吗? 背压、NAK/重传速率、archive/磁盘可用空间。
  6. 你能快速恢复吗? 快照年龄、有效快照数、快照时长超限。