# 边缘断网行为

n9e-edge 失联时会怎样：判定继续、通知走本地、之后什么会同步回来。

最后校对于 2026-10-10

`n9e-edge` 存在的意义就是断链时还能告警。这页把「断链时具体发生什么」讲清楚—— 包括**断链期间产生的告警事件会永久丢失**这件事，以及由此推出的一条运维铁律。

## 正常时边缘在做什么[​](#正常时边缘在做什么 "正常时边缘在做什么的直接链接")

边缘进程自己不连数据库。它每 9 秒从中心拉一次配置——告警规则、屏蔽规则、订阅规则、 业务组、设备、通知规则、通知媒介、消息模板、数据源、用户和团队——全部缓存在内存里。

这些请求打的是中心的 `/v1/n9e/*`，所以中心必须打开：

```
# 中心的 etc/config.toml

[HTTP.APIForService]

Enable = true

[HTTP.APIForService.BasicAuth]

user001 = "<换掉这个默认口令>"
```

边缘用 `[CenterApi]` 里的同一组用户名口令去认证：

```
# 边缘的 etc/edge/edge.toml

[CenterApi]

Addrs = ["http://n9e:17000"]

BasicAuthUser = "user001"

BasicAuthPass = "<同上>"

Timeout = 9000
```

`Addrs` 配多个地址时是**依次尝试、第一个成功就用**，不是并发广播。

## 断链时还在做的事[​](#断链时还在做的事 "断链时还在做的事的直接链接")

| 能力                   | 断链时                                               |
| ---------------------- | ---------------------------------------------------- |
| 规则判定               | **继续**，用最后一次同步到的规则集，查本机房的数据源 |
| 屏蔽、订阅、事件流水线 | **继续**，同样用最后一次同步到的配置                 |
| 发通知                 | **继续**，而且是**从边缘直接发出去的**，不经过中心   |
| 判定记录（evallog）    | **继续**，写在边缘本地磁盘上                         |
| 规则的增删改           | 停止——中心改了规则，边缘看不到，直到链路恢复         |

配置缓存在拉取失败时**保留上一次的好数据，不会被清空**； 一致性哈希环也不会重建，所以规则归属在断链期间是冻结的。这些都是刻意设计的。

「通知从边缘直接发出去」这条有一个网络含义经常被漏掉： **边缘机房必须能直接访问钉钉、飞书、企业微信、SMTP 服务器、你的 webhook 地址**。 只放通了「边缘 → 中心」的防火墙策略，断链时通知照样发不出去。

## 断链期间产生的事件会丢[​](#断链期间产生的事件会丢 "断链期间产生的事件会丢的直接链接")

这是这页最重要的一段。

告警事件在边缘产生后，会 POST 到中心的 `/v1/n9e/event-persist` 落库。 断链时这个 POST 会重试 **3 轮**（初始间隔 100 毫秒，逐次翻倍，上限 3 秒，单次超时 2 秒）， **然后事件被丢弃**。没有本地队列、没有落盘缓冲、没有恢复后的补传。

后果：

* 告警事件表里没有这条记录，事件列表和历史事件里都查不到；
* 事件 ID 是 0，通知记录和模板里的 `event_id` 也是 0；
* 通知记录同样丢——它走的是单次 POST，连重试都没有。

**通知本身照发**：落库失败不会阻断发送。所以断链期间的真实情况是 「手机上收到了告警，但系统里查不到这条事件」。

内存里那个上限一千万的事件队列**不是断链缓冲区**——消费协程一直在排空它， 落库失败也不阻塞，所以它在断链期间根本不会积累。

还有一个边界情况：如果中心其实写成功了、只是响应丢在路上，重试会插入第二条历史事件记录。 所以断链恢复后偶尔看到重复的历史事件是正常的。

## 铁律：断链期间不要重启边缘[​](#铁律断链期间不要重启边缘 "铁律：断链期间不要重启边缘的直接链接")

**运行中的边缘可以无限期扛住断链，启动中的边缘会直接退出。**

边缘进程启动时要做一次全量配置同步，十几个缓存（告警规则、业务组、设备、数据源……） 在首次同步失败时会直接 `exit(1)`。链路不通就起不来，而且是立刻失败，不是降级运行。

所以：

* 断链期间不要重启、不要升级、不要改边缘的配置文件；
* 用 systemd 之类的守护进程时，注意它的自动重启策略—— 一次意外重启会把「还能告警」变成「彻底不能告警」；
* 边缘也需要自己的 Redis，**启动时连不上 Redis 同样直接退出**。

## 恢复之后[​](#恢复之后 "恢复之后的直接链接")

链路恢复后：

* 配置缓存在下一个 9 秒周期自动追上；
* 心跳恢复，边缘重新出现在**系统配置 → 告警引擎**里（引擎集群名取 `[Alert.Heartbeat] EngineName`，示例配置里是 `edge`）；
* **断链期间丢掉的事件和通知记录不会补回来。** 没有补传机制。

不需要人工干预，也没有什么可以人工补的。要为断链期间留下证据， 靠的是边缘本地的**判定记录**——它写在边缘磁盘上，不依赖中心。

想在中心的界面上看边缘的判定记录，边缘那边也要打开 `[HTTP.APIForService] Enable = true` （示例配置里默认是 `false`），并且它的 BasicAuth 用户名口令要和中心的那组一致—— 中心是拿自己的凭据去转发请求的。

## 怎么判断断没断[​](#怎么判断断没断 "怎么判断断没断的直接链接")

| 看哪里              | 断链的样子                                           |
| ------------------- | ---------------------------------------------------- |
| 系统配置 → 告警引擎 | 边缘那个实例的「上次心跳时间」停住，超过 30 秒就消失 |
| 边缘的日志          | 反复出现 `/v1/n9e/...` 的请求失败                    |
| 边缘的判定记录      | 仍在正常产生——这正是它该有的样子                     |
| 中心的事件列表      | 边缘机房的告警没有新增，但机房里的人收到了通知       |

最后一行是最典型的症状：**有人收到告警，系统里查无此事**。

## 相关[​](#相关 "相关的直接链接")

* [边缘机房](https://n9e.github.io/zh/docs/install/edge.md)
* [生产拓扑](https://n9e.github.io/zh/docs/operations/topology.md)
* [边缘节点失联](https://n9e.github.io/zh/docs/troubleshooting/edge-disconnected.md)
* [高可用与故障域](https://n9e.github.io/zh/docs/operations/high-availability.md)
