前言
夜莺类似 Grafana,可以接入多个数据源,查询数据源的数据做告警和展示。
问题在于:有些数据源所在的机房和中心机房之间网络链路不好。如果由中心 n9e 进程周期性查询边缘机房的数据并判定告警,那么在网络链路抖动或拥塞时,告警就会不稳定。
为了解决这个问题,夜莺引入了边缘告警引擎:n9e-edge。n9e-edge 部署在边缘机房,和边缘机房的时序库部署在一起,由 n9e-edge 负责边缘机房的告警判定。这样,告警判定不再强依赖中心机房到边缘机房的跨机房链路,整体架构会稳定很多。
核心要点
- 中心 n9e 负责统一管理数据源、告警规则、通知规则和 Web 查询入口。
- n9e-edge 部署在边缘机房,负责本机房数据源的告警规则和 recording rule 判定。
- n9e-edge 会从中心 n9e 同步告警规则并缓存在内存中,中心链路短暂不可用时,不影响已缓存规则的本地判定。
- 数据源配置中要区分中心 n9e 访问地址、n9e-edge 访问内网地址、Remote Write URL 和关联告警引擎集群。
- 新版本 n9e-edge 依赖本地 Redis;中心 n9e 使用的 Redis 和 n9e-edge 使用的 Redis 不是同一个。
- 边缘机房的 Categraf 应该上报到本机房 n9e-edge,而不是跨机房直接上报中心 n9e。
架构背景:为什么需要边缘告警引擎
为了说明这个架构下的告警引擎工作原理,我画了一张架构图:

假设贵司有 3 个机房:
- 中心主力机房
- 边缘机房 A
- 边缘机房 B
其中,边缘机房 A 和中心机房之间有专线,网络链路很好;边缘机房 B 和中心机房之间没有专线,走公网,网络链路不够可靠。
中心 n9e 进程部署在中心主力机房。n9e 依赖 MySQL 和 Redis,所以 MySQL 和 Redis 也部署在中心主力机房。如果要做高可用,中心机房的 n9e 可以部署多个实例,配置文件保持一致,连接同一个 MySQL 和 Redis 即可。
示例中的数据源分布
架构图中有 5 个数据源:
- 中心机房有一套 Loki,一套 ElasticSearch。
- 边缘机房 A 有一套 ElasticSearch,一套 Prometheus。
- 边缘机房 B 有一套 VictoriaMetrics。
我们希望在中心 n9e 统一查看这 5 个数据源的数据,所以需要把这 5 个数据源的访问地址配置到夜莺中。菜单位置是:集成中心-数据源。

中心 n9e 可以通过内网地址直接连通中心机房和边缘机房 A 的数据源,但无法直接连通边缘机房 B 的数据源,因为没有专线。
这时只能把边缘机房 B 的 VictoriaMetrics 暴露一个公网地址出来,假设地址为 ex.a.com,中心 n9e 通过公网地址访问边缘机房 B 的 VictoriaMetrics。

架构图中的 1、2、3、4、5 这 5 条线,表示中心 n9e 和 5 个数据源的连接关系。用户查询数据时,是在 n9e Web 上查的,请求先发给 n9e 进程。n9e 此时相当于一个 proxy,把请求代理给后端各个数据源,再把数据源返回的数据展示给用户。
n9e-edge 如何承担边缘告警判定
n9e-edge 部署在边缘机房 B,用于处理 B 机房 VictoriaMetrics 的告警判定。
它的工作流程是:
- n9e-edge 从中心 n9e 同步告警规则,即架构图中的 A 线。
- n9e-edge 把告警规则缓存在内存里。
- n9e-edge 使用本机房内网地址查询 VictoriaMetrics。
- n9e-edge 在边缘机房本地完成告警判定。
在这种架构下,n9e-edge 和 VictoriaMetrics 是内网连通的,所以告警判定更可靠。即便 n9e-edge 暂时连不通中心机房的 n9e,也不影响 B 机房已有告警规则的判定,因为 n9e-edge 内存中已经缓存了告警规则。
不过要注意,n9e-edge 产生的告警事件会调用 n9e 的接口写回中心 MySQL,也会调用钉钉、飞书、Flashduty 等接口发送通知。
如果 n9e-edge 和中心 n9e 之间网络断了,告警事件就写不到中心 MySQL;但只要 n9e-edge 所在机房的外网出口是好的,告警通知仍然可以发出去。
中心 n9e 和 n9e-edge 的职责边界
在上面的架构中,告警判定职责可以这样划分:
| 组件 | 负责的数据源 | 主要职责 |
|---|---|---|
| 中心机房 n9e | 中心机房 Loki、ElasticSearch;边缘机房 A 的 ElasticSearch、Prometheus | 查询代理、规则管理、中心和链路可靠机房的数据源告警判定 |
| 边缘机房 B 的 n9e-edge | 边缘机房 B 的 VictoriaMetrics | 本机房 VictoriaMetrics 的告警规则和 recording rule 判定 |
也就是说,n9e-edge 不是替代中心 n9e,而是把链路不可靠的数据源的告警判定下沉到数据源所在机房。
数据源如何关联到不同告警引擎
那如何指定不同数据源和告警引擎之间的关联关系?
答案是在数据源管理页面中配置:

上图中有几个关键字段:
| 配置项 | 用途 | 示例架构中的配置建议 |
|---|---|---|
| URL | 中心 n9e 读取数据的地址 | B 机房 VictoriaMetrics 的公网地址 |
| 时序库内网地址 | n9e-edge 连接时序库的地址 | B 机房内网地址 |
| Remote Write URL | VictoriaMetrics 的 remote write 写入地址,用于 recording rule | 给 n9e-edge 使用,应配置内网地址 |
| 关联告警引擎集群 | 指定由哪个告警引擎处理该数据源规则 | 选择 edge-b |
这里要特别注意两个地址的差异:
URL是中心 n9e 读取数据的地址。上例中,中心 n9e 只能通过公网访问 B 机房 VictoriaMetrics,所以这里配置公网地址。时序库内网地址是 n9e-edge 连接 VictoriaMetrics 的地址。因为 n9e-edge 和 VictoriaMetrics 在同一个机房,所以应该配置内网地址,告警判定更可靠。
如果 URL 本来就是内网地址,时序库内网地址 可以留空。留空后,n9e-edge 会使用 URL 中的地址。
Remote Write URL 是 VictoriaMetrics 的 remote write 写入地址,用于记录规则,也就是 recording rule。n9e-edge 负责处理记录规则,并把结果写回时序库,所以需要知道时序库的 remote write 地址。因为这是给 n9e-edge 使用的,也应该使用内网地址。如果你没有用到夜莺的记录规则,这里可以不配置。
关联告警引擎集群 上图选择的是 edge-b,这是 B 机房 n9e-edge 的名字,由 edge.toml 中的 EngineName 字段指定。配置完成后,就建立了 B 机房 n9e-edge 和 B 机房 VictoriaMetrics 之间的关联关系,B 机房 VictoriaMetrics 的告警规则和记录规则就会由这个 n9e-edge 处理。
Redis、Categraf 和 Ibex 的部署关系
新版本夜莺中,n9e-edge 依赖一个 Redis,所以需要在 B 机房部署一个 Redis 给 n9e-edge 使用。
注意:n9e-edge 使用的 Redis 和中心机房 n9e 使用的 Redis 不是同一个。架构图中特意标注了 R1、R2 两个名字,表示两个 Redis,分别给中心 n9e 和 n9e-edge 使用。
再说 Categraf。
如果网络链路比较好,Categraf 可以把数据直接上报到中心机房 n9e。例如中心机房和 A 机房的 Categraf 都可以直接对接中心机房 n9e。
但 B 机房部署了 n9e-edge,因此 B 机房的 Categraf 应该对接到 B 机房的 n9e-edge,避免采集链路跨越不稳定网络。
配置样例
要达到上述架构,各个组件应该如何配置?下面给出一个示例。
中心机房 n9e 配置
中心机房 n9e 的默认配置文件是 etc/config.toml:
[HTTP.APIForService]
Enable = true
[HTTP.APIForService.BasicAuth]
user001 = "ccc26da7b9aba533cbb263a36c07dcc5"
user002 = "ccc26da7b9aba533cbb263a36c07dcc6"
重点是 HTTP.APIForService 这块配置。
默认 Enable 是 false,这是出于安全考虑:默认不支持 n9e-edge 架构。如果要支持 n9e-edge,需要改成 true。
n9e-edge 调用中心 n9e 接口时,可以使用 BasicAuth 认证,也就是 HTTP.APIForService.BasicAuth 下面的配置。上例配置了两个用户:user001 和 user002,密码分别是 ccc26da7b9aba533cbb263a36c07dcc5 和 ccc26da7b9aba533cbb263a36c07dcc6。
实际配置一个用户就可以。这里配置两个只是为了演示。
如果你的 n9e 暴露在公网,千万要修改 BasicAuth 的默认密码,否则很容易被攻击。
边缘机房 n9e-edge 配置
边缘机房 n9e-edge 的默认配置文件是 etc/edge/edge.toml。
首先,n9e-edge 要调用中心 n9e 的接口,所以要配置中心 n9e 地址:
[CenterApi]
Addrs = ["http://N9E-CENTER-SERVER:17000"]
BasicAuthUser = "user001"
BasicAuthPass = "ccc26da7b9aba533cbb263a36c07dcc5"
# unit: ms
Timeout = 9000
N9E-CENTER-SERVER:17000 表示中心 n9e 的地址,需要按自己的环境调整。
BasicAuthUser 和 BasicAuthPass 是中心 n9e 的 BasicAuth 用户名和密码。如果中心 n9e 没有开启 BasicAuth,这两个字段可以不填。
还是那句话,千万要修改 BasicAuth 的默认密码,否则很容易被攻击。
新版本 n9e-edge 依赖 Redis,所以还要配置 Redis 地址。默认配置一般在 edge.toml 最下面,自行修改即可。
如果你是老版本,不依赖 Redis,就不用配置。如何判断当前版本的 n9e-edge 是否依赖 Redis?看下载下来的 edge.toml 默认配置中是否带有 Redis 配置;带了就说明依赖 Redis。
边缘机房 Categraf 配置
边缘机房 Categraf 主要注意两个地方:writer 地址和 heartbeat 地址,都要配置为 n9e-edge 地址。
...
[[writers]]
url = "http://N9E-EDGE:19000/prometheus/v1/write"
...
[heartbeat]
enable = true
# report os version cpu.util mem.util metadata
url = "http://N9E-EDGE:19000/v1/n9e/heartbeat"
...
N9E-EDGE:19000 表示 n9e-edge 的地址。n9e-edge 默认监听端口是 19000,也可以在 edge.toml 中自行修改。
Ibex 配置
Ibex 是故障自愈功能。有些公司担心安全问题,不开放这个功能。如果要在边缘机房开启 Ibex,同样需要在 edge.toml 中开启:
[Ibex]
Enable = true
RPCListen = "0.0.0.0:20090"
然后让边缘机房的 Categraf 连接边缘机房 n9e-edge 的 20090 端口。Categraf 的 config.toml 需要做如下配置:
[ibex]
enable = true
## ibex flush interval
interval = "1000ms"
## n9e ibex server rpc address
servers = ["N9E-EDGE-IP:20090"]
## temp script dir
meta_dir = "./meta"
N9E-EDGE-IP:20090 表示 n9e-edge 的 RPC 地址。注意这是 RPC 地址,不是 HTTP 地址,所以不要在 N9E-EDGE-IP 前面加 http://。
其他适用场景
除了网络链路不好的场景,n9e-edge 也适用于网络安全分区场景。
例如,某个网络区域只有一台中转机可以连通中心 n9e,其他机器都不能连通中心 n9e。这时可以在中转机上部署 n9e-edge,然后让该区域其他机器的 Categraf 连接中转机上的 n9e-edge。
这种部署方式的本质仍然是:把采集接入和告警判定放在离数据源更近、网络更稳定的位置。
部署检查清单
落地 n9e-edge 架构时,建议逐项检查:
- 中心 n9e 的
HTTP.APIForService.Enable是否开启。 - BasicAuth 用户名和密码是否已经修改,尤其是中心 n9e 暴露到公网时。
- n9e-edge 的
CenterApi.Addrs是否能访问中心 n9e。 - 数据源
URL是否是中心 n9e 可以访问的地址。 - 数据源
时序库内网地址是否是 n9e-edge 可以访问的内网地址。 - 使用 recording rule 时,
Remote Write URL是否配置为 n9e-edge 可访问的写入地址。 - 数据源是否关联了正确的告警引擎集群,例如
edge-b。 - 新版本 n9e-edge 是否配置了本机房 Redis。
- 边缘机房 Categraf 的 writer 和 heartbeat 是否都指向 n9e-edge。
- 如需 Ibex,Categraf 是否连接 n9e-edge 的 RPC 地址,并且没有误加
http://。
常见问题
Q1:n9e-edge 和中心 n9e 断开后,告警还会判定吗? A:已同步并缓存在 n9e-edge 内存中的规则仍然可以在边缘机房本地判定。但告警事件写回中心 MySQL 会受影响;只要边缘机房外网出口正常,通知仍然可以发出。
Q2:为什么数据源要配置两个地址?
A:中心 n9e 和 n9e-edge 所处网络位置不同。URL 给中心 n9e 查询数据用,时序库内网地址 给 n9e-edge 本地告警判定用。两者分开配置,可以兼顾中心展示和边缘判定可靠性。
Q3:n9e-edge 使用的 Redis 能不能和中心 n9e 共用? A:这里的架构要求边缘机房部署一个 Redis 给 n9e-edge 使用。它和中心机房 n9e 使用的 Redis 不是同一个。
总结
n9e-edge 的价值是把边缘机房的数据源告警判定下沉到本机房,避免跨机房链路不稳定导致告警抖动。中心 n9e 仍然负责统一管理和展示,n9e-edge 负责本地规则判定、recording rule 处理和边缘采集接入。理解中心地址、内网地址、告警引擎集群、Redis、Categraf 和 Ibex 的职责边界之后,n9e-edge 架构就不复杂了。
