# Edge 为什么与中心失联？

边缘断网期间判定和通知照常在本地进行，但事件不会回传中心——这是预期行为；从未连上过才是配置错误，两者的判断方法不同。

最后校对于 2026-10-10

**系统配置 → 告警引擎**里那个边缘实例的心跳停了，或者整行消失了； 或者机房里的人收到了告警，中心的事件列表却一条都没有。

后面这个才是本页的重点现象：**有人被叫醒了，系统里查无此事。** 这是断网期间的**预期行为**，不是故障——先弄清这一点，能省掉大半的排查。

## 先分清「断网」和「从来没连上」[​](#先分清断网和从来没连上 "先分清「断网」和「从来没连上」的直接链接")

这一步定方向，两个方向的排查完全不同：

| 问自己                                         | 结论                                              |
| ---------------------------------------------- | ------------------------------------------------- |
| 这个 edge **以前正常出现过**在告警引擎列表里吗 | 出现过 → 是真断网，看下面「断网期间什么还在工作」 |
| 从部署到现在**一次都没出现过**                 | 是配置问题，看下面前两个根因                      |

判据很硬：**跑着的 edge 能无限期扛过断网，正在启动的 edge 扛不过。** 启动时它要做一次完整的配置同步，十几个缓存里任何一个同步失败都会直接 `exit(1)`—— 不会降级运行，是立刻硬退。所以「进程起不来」和「进程活着但心跳没了」是两件事： 前者一定是配置或网络在启动那一刻就不通，后者才是断网。

顺带：**edge 需要自己的 Redis**，不能和中心共用；启动时连不上 Redis 同样直接退出。

## 断网期间什么还在工作，什么不在[​](#断网期间什么还在工作什么不在 "断网期间什么还在工作，什么不在的直接链接")

edge 每 9 秒从中心拉一次配置放在内存里。**拉取失败时缓存保留上一份好的、永不清空**， 一致性哈希环也不重建，所以规则归属在断网期间是冻结的。这是刻意设计。

| 能力                | 断网期间                                               |
| ------------------- | ------------------------------------------------------ |
| 规则判定            | **继续**，用最后一次同步到的规则，查本机房自己的数据源 |
| 屏蔽、订阅、工作流  | **继续**，用最后一次同步到的配置                       |
| 发通知              | **继续，而且是从 edge 直接发出去的**，不经过中心       |
| 判定记录（evallog） | **继续**，写在 edge 自己的本地磁盘上                   |
| 新建 / 修改规则     | 停止。中心改的规则，链路恢复前 edge 看不到             |

「通知从 edge 直接发出去」有一个容易漏掉的网络前提： **边缘机房必须能直连钉钉、飞书、企业微信、你的 SMTP 和各个 webhook 地址。** 只放行了「edge → 中心」的防火墙，断网时照样发不出通知。

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

这是本页最重要的一节。

edge 产生的事件要 POST 到中心的 `/v1/n9e/event-persist` 才能落库。断网时这个 POST 重试 **3 轮**（初始间隔 100 毫秒、逐轮翻倍、单次超时 2 秒，单地址最坏约 6.3 秒）， **然后事件被丢弃**。没有本地队列、没有磁盘暂存、链路恢复后也**不会补**。

后果：

* 告警事件表里没有这一行，活跃事件和历史事件里都查不到；
* 事件 ID 是 0，于是通知记录和模板里的 `event_id` 也都是 0；
* 通知记录本身也丢了——它是一次没有任何重试的 POST。

**但通知照发**：落库失败从不阻断发送。所以断网期间的真实体验就是那句 「有人收到了告警，系统里没有记录」。

**怎么确认是它**：到 **edge 自己的** `/metrics`（端口 19000）上看这个：

```
curl -s --noproxy '*' http://n9e-edge:19000/metrics \

  | grep 'n9e_alert_rule_eval_error_total' | grep 'persist_event'
```

`stage="persist_event"` 这一维**只在事件落库失败时增长**，是断网丢事件最直接的计数。 edge 日志里同时有：

```
ERROR event:<事件哈希> persist err:<错误>
```

另外内存里那个上千万上限的事件队列**不是断网缓冲**——消费者一直在排空， 落库失败也不阻塞，所以它根本不会堆积起来。

## 常见根因与确认方法[​](#常见根因与确认方法 "常见根因与确认方法的直接链接")

### 中心的 `APIForService` 没开——出厂默认就是关的[​](#中心的-apiforservice-没开出厂默认就是关的 "中心的-apiforservice-没开出厂默认就是关的的直接链接")

edge 拉配置走的是中心的 `/v1/n9e/*`，这组接口由 `[HTTP.APIForService]` 控制， 而**它在 `etc/config.toml` 里的出厂值是 `Enable = false`**。 所以「新部署的 edge 一次都没连上」绝大多数是这一条。

**怎么确认**：edge 日志里反复出现对 `/v1/n9e/...` 的请求失败； 中心那边这个端点直接不存在。BasicAuth 对不上则是 401。

**怎么修**：中心和 edge 两边都要配，用户名口令必须一致：

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

[HTTP.APIForService]

Enable = true

[HTTP.APIForService.BasicAuth]

user001 = "<把出厂默认口令换掉>"
```

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

[CenterApi]

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

BasicAuthUser = "user001"

BasicAuthPass = "<和上面一致>"

Timeout = 9000
```

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

还有一处同名配置容易漏：想在中心的界面上看 edge 的**判定记录**， **edge 自己的** `[HTTP.APIForService]` 也要 `Enable = true`（它的出厂值同样是 `false`）， 口令和中心一致——中心是拿自己的凭据去转发这个请求的。

### 启动时指错了配置目录[​](#启动时指错了配置目录 "启动时指错了配置目录的直接链接")

```
n9e-edge --configs etc/edge
```

**`--configs` 的默认值是 `etc`**，而 `etc` 下放的是**中心**的 `config.toml`。 指错了它会当成中心配置加载，**不报错**，行为却完全不对。

**怎么确认**：看进程启动命令行；再看 edge 的监听端口是不是 19000 （`etc/edge/edge.toml` 里的 `[HTTP] Port`）。听成 17000 就是加载了中心那份配置。 心跳集群名也是线索：`etc/edge/edge.toml` 里 `EngineName = "edge"`， 中心那份是 `"default"`——**告警引擎页面上这个实例归在哪个集群下，直接说明它读了哪份配置。**

**怎么修**：把 `--configs etc/edge` 补上，重启。

### 边缘到通知媒介的网络没开[​](#边缘到通知媒介的网络没开 "边缘到通知媒介的网络没开的直接链接")

**怎么确认**：从 **edge 那台机器上**直接 curl 一次 webhook 地址或 telnet SMTP 端口。 中心能通不代表 edge 能通——断网时发信的是 edge。

**怎么修**：按 edge 所在机房的出向策略开通，而不是按中心的。

### 断网期间重启了 edge[​](#断网期间重启了-edge "断网期间重启了 edge的直接链接")

**跑着的 edge 能扛过断网，重启一次就再也起不来了**，直到链路恢复。 这会把「还在告警」变成「完全不告警」，是本页破坏力最大的一种。

**怎么确认**：进程根本不在，日志末尾是启动阶段的配置同步失败。

**怎么修**：**断网期间不要重启、不要升级、不要改 edge 的配置文件。** 提前检查 supervisor / systemd 的自动重启策略，别让它在断网时自动帮你重启一次。

## 确认恢复了[​](#确认恢复了 "确认恢复了的直接链接")

链路恢复后不需要任何手工操作，也没有任何手工操作可做。按这个顺序确认：

1. **系统配置 → 告警引擎**，这个 edge 实例重新出现， 归在 `EngineName` 指定的集群下，**最近心跳**在跳动。 （超过 30 秒没心跳的行会被移出列表，所以「行在且时间在动」是硬指标；）
2. edge 日志里不再有 `/v1/n9e/...` 的请求失败——配置缓存会在下一个 9 秒周期追上；
3. `n9e_alert_rule_eval_error_total{stage="persist_event"}` **停止增长**；
4. 在中心的事件列表里，能看到这个边缘机房**新产生**的事件；
5. 挑一条这个机房的规则做**测试触发**，走完查询、判定、事件、通知一整条。

**断网期间丢掉的事件和通知记录不会回来，没有补写机制。** 那段时间唯一留存的证据是 edge 本地磁盘上的**判定记录**——它不依赖中心。

还有一个正常现象：中心其实已经提交、只是响应丢了的那个窄窗口里，重试会再插一条历史事件。 **断网之后偶尔看到重复的历史事件是预期的。**

## 收集这些再去提问[​](#收集这些再去提问 "收集这些再去提问的直接链接")

1. edge 的启动命令行（重点是 `--configs`）和 `etc/edge/edge.toml` 全文；
2. 中心 `etc/config.toml` 里 `[HTTP.APIForService]` 那一节；
3. 断网时间段内 edge 的日志，重点是 `/v1/n9e/` 和 `persist err:` 两类行；
4. `curl --noproxy '*' http://n9e-edge:19000/metrics | grep n9e_alert_rule_eval_error_total`；
5. 告警引擎页面的截图或那一行的内容（实例、集群名、最近心跳）。

**脱敏**：`BasicAuthPass`、Redis 口令、通知媒介的 webhook 和 token 一律替换； 机房地址写成 `n9e-edge:19000`、`n9e:17000` 这样的占位。 `stage=` 后面的值和错误文本要原样保留。

## 下一步[​](#下一步 "下一步的直接链接")

* 断网期间的完整行为模型：[Edge 断网行为](https://n9e.github.io/zh/docs/operations/edge-partition.md)
* edge 怎么部署：[边缘机房](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/no-notification.md)
* 中心侧也没数据：[数据源连接正常但查询无数据](https://n9e.github.io/zh/docs/troubleshooting/no-data.md)
