高可用
在负载均衡后面跑多个 Center 和 Alert 实例,以及哪些部分仍然必须单实例。
夜莺的集群没有额外组件:多跑几个 n9e 进程,配置文件完全一样,共享同一套 MySQL 和 Redis。
这页讲怎么把这件事做对——前面的负载均衡怎么配、实例之间还需要什么、
以及哪些东西即使跑了多份也仍然是单点。
搭起来
在几台机器上各装一个 n9e(二进制包),配置文件用同一份。
必须一致的是这三段:
[DB]
DSN = "n9e:<password>@tcp(mysql:3306)/n9e_v6?charset=utf8mb4&parseTime=True&loc=Local"
[Redis]
RedisType = "standalone"
Address = "redis:6379"
# 同一个引擎集群里的实例才会互相分担规则
[Alert.Heartbeat]
EngineName = "default"
启动完到系统配置 → 告警引擎看一眼,几个实例都应该在列表里,心跳时间在走。 规则会按一致性哈希分到各个实例上,一条规则只在一个实例上跑,不会重复告警。
先把内置时序库关掉,理由见下面「仍然是单点的部分」。
实例之间要能互通
这一步经常被漏掉:实例不只是各自连数据库,它们之间还有直接的 HTTP 调用。
查看告警规则的「判定执行记录」时,记录存在当时负责这条规则的那个实例的本地磁盘上,
你的浏览器连到哪个实例,那个实例就要向兄弟实例转发查询。转发用的是
http://<对方 IP:端口>/v1/n9e/eval-records,走的是服务间接口。
所以集群里每个实例都要打开这组接口,并且用同一组凭据:
[HTTP.APIForService]
Enable = true
[HTTP.APIForService.BasicAuth]
n9e-cluster = "<your-own-password>"
[HTTP.APIForService] 默认是关的,配置文件里自带的那组 user001 口令是公开示例,
必须换成自己的。不打开的后果不是报错,而是你只能看到当前实例负责的那部分规则的执行记录。
实例的身份是 <IP>:<HTTP 端口>,IP 默认自动探测。容器里、或者机器有多块网卡时,
把它显式写死,否则兄弟实例可能拿到一个访问不到的地址:
[Alert.Heartbeat]
IP = "n9e-1.example.internal"
网络上也要放通:实例之间的 17000 端口互访。
负载均衡怎么配
前面挂一个四层或七层的负载均衡,把流量分到各实例的 17000:
- 健康检查用
GET /ping,返回pong; - 不需要会话保持。登录态是 JWT,签发和吊销都在共享的 Redis 里, 请求落到哪个实例都认;
- 别只转发页面路径。写入端点
/prometheus/v1/write、心跳/v1/n9e/heartbeat、 Web UI 和/api/n9e/*全在同一个 17000 端口上,采集器和浏览器走的是同一个入口; - 超时给宽一点。仪表盘和执行记录的查询可能跑十几秒,默认 60 秒的后端超时够用。
自愈任务用的 ibex RPC 在 20090,那是长连接的 TCP,不要放到七层代理后面, 四层转发或者让采集器直连都行。
仍然是单点的部分
多实例只消掉了「n9e 进程本身」这一个故障域,下面这些不在其中:
| 东西 | 状况 |
|---|---|
| 内置时序库 | 数据在单个实例的本地磁盘上,多实例必须关掉它,改用外部时序库 |
| MySQL、Redis | 它们挂了整个系统就挂,夜莺不做降级,高可用要它们自己做 |
| 判定执行记录 | 存在各实例本地磁盘,不做副本;实例没了,它那份记录也没了 |
| 钉钉 Stream 模式 | 只在 leader 实例上跑——leader 是活跃实例里 IP:端口 排序最小的那个,自动选举 |
关掉内置时序库:
[EmbeddedTSDB]
Enable = false
迁移办法见外置时序库与双写迁移。
关于 n9e-alert 和 n9e-pushgw
夜莺的告警判定和数据接收本来就在 n9e 里,扩容就是多跑几个 n9e。
把它们拆成独立进程是可选的,而且发布包里没有这两个二进制——
Makefile 里有 build-alert、build-pushgw 目标,需要拆分部署得自己从源码编译。
下一步
- 高可用与故障域——能扛住什么、扛不住什么,以及怎么演练
- 外置时序库与双写迁移
- 升级——集群怎么滚动升级