跳到主要内容

高可用

在负载均衡后面跑多个 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 目标,需要拆分部署得自己从源码编译。

下一步​