容量规划
夜莺的资源消耗由规则数、序列数、事件量和数据库负载决定;量出四个数就知道该往哪个方向扩,这里不提供规格表。
这页不给「X 核 Y 内存能跑 Z 条规则」这样的表——最后一节说明为什么。 它给的是四个可以直接量出来的数,以及每个数逼近上限时该往哪个方向扩。 量完你自己的环境,比抄别人的规格准。
什么在消耗资源
| 消耗什么 | 主要由什么决定 |
|---|---|
| CPU | 规则条数 × 判定频率,以及每次判定返回的序列数 |
| 内存 | 内存里缓存的配置(规则、设备、用户)+ 判定返回的序列 + 队列里积压的样本和事件 |
| 元数据库 | 事件写入、通知记录写入、各缓存每 9 秒一次的同步查询 |
| 磁盘 | 内置时序库的数据块、判定记录、日志 |
| 出向网络 | 每次判定对数据源的查询、每次转发给时序库的样本 |
注意判定的开销主要不在夜莺这一侧:一条规则每分钟对 Prometheus 发一次查询, 压力大头在 Prometheus。规则多了以后先扛不住的往往是数据源,不是夜莺。
先量这四个数
都在 /metrics 上,curl --noproxy '*' http://n9e:17000/metrics 就能取。
1. 活跃序列数
prometheus_tsdb_head_series
只有开着内置时序库的 Center 有这个指标,它是当前内存里活跃序列的真实条数。 用外部时序库时看外部库自己的对应指标。
上限参考:内置时序库适合 10 万活跃序列以内,再往上要换外部库。
这是产品自己给出的边界,写在 etc/config.toml 的 [EmbeddedTSDB] 注释里。
2. 判定耗时
n9e_alert_rule_eval_total # 总判定次数,不带标签
n9e_alert_rule_eval_duration_ms{rule_id="..."} # 每条规则最近一次判定耗时
按 rule_id 排序看 rule_eval_duration_ms 的 top 10,那几条就是你的成本中心。
单条规则的判定耗时接近它的执行频率(默认 @every 60s)时,这条规则已经排不开了。
处理办法通常是改规则,不是加机器:降低执行频率、缩小查询范围、把返回上万条序列的 查询先做聚合。
3. 数据库连接
n9e_db_pool_in_use_connections # 正在用的连接数
n9e_db_pool_wait_count_total # 等过连接的次数
n9e_db_pool_wait_duration_seconds_total
in_use 长期贴着 [DB] MaxOpenConns(默认 150)、并且 wait_count_total 在涨,
就是数据库这一层排队了。先看是不是有慢查询,再考虑调大连接池。
4. 写入量与队列
n9e_pushgw_samples_received_total{channel="prometheus"} # 每秒进来多少样本
n9e_pushgw_sample_queue_size{queueid="..."} # 各队列积压
n9e_pushgw_push_queue_error_total{queueid="..."} # 被丢的样本
队列个数默认等于 CPU 核数,全局准入上限是 队列数 × QueueMaxSize × 0.1。
push_queue_error_total 一旦非 0,就是真的在掉数据了,详见
Pushgw 队列、写入器与双写。
磁盘要单独算
三份数据都落在本地盘上,各有各的上限:
| 数据 | 配置项 | 默认上限 |
|---|---|---|
| 内置时序库 | [EmbeddedTSDB] RetentionDuration / MaxBytes | 15 天 / 10 GiB,哪个先到删哪个 |
| 判定记录 | [Alert.EvalLog] RetentionHours / MaxDiskGB / PerRuleDailyMB | 192 小时 / 20 GB / 单规则每天 1024 MB |
| 日志 | [Log] KeepHours / RotateNum / RotateSize | 默认输出到 stdout,不占盘 |
MaxBytes 留空或写 0 表示不限制内置时序库的磁盘用量——那就变成磁盘写满为止,
生产上不要这么配。
元数据库这边随时间增长的是三张表,清理任务的默认行为不一样:
| 表 | 配置项 | 默认 |
|---|---|---|
| 历史告警事件 | [Center] CleanAlertHisEventDay | 永久保留(<= 0 表示不清理),每天凌晨 2 点执行 |
| 通知记录 | [Center] CleanNotifyRecordDay | 7 天,每天凌晨 1 点执行 |
| 工作流执行记录 | [Center] CleanPipelineExecutionDay | 7 天,每天早上 6 点执行 |
历史告警事件默认不清理,事件量大的环境上线前就该显式设一个保留天数, 否则这张表会一直长。
按什么维度扩
先定位是哪个数到顶了,再决定扩什么。加机器不能解决所有问题。
| 到顶的是 | 该做的 |
|---|---|
| 判定耗时(规则排不开) | 加 n9e 实例——规则会自动重新分派到新实例上 |
| 判定耗时(少数几条规则很慢) | 改那几条规则,加机器没用 |
| 活跃序列数 | 换外部时序库,见内置时序库的单 Center 限制 |
| 写入量 | 拆出 n9e-pushgw,或者加 n9e 实例并在前面做负载均衡 |
| 数据库排队 | 先查慢查询,再调 [DB] MaxOpenConns,最后才是加数据库规格 |
| 磁盘 | 调保留期,或者把内置时序库换掉 |
| Web 卡但判定正常 | 拆出 n9e-alert,让判定和 Web 不抢 CPU |
还有一项容易忽略的成本:Pushgw 会为每一台被监控的机器在自己的 /metrics 上暴露
一条 n9e_pushgw_sample_received_by_ident{host_ident="..."}。机器数量上万时,
光这一个指标就是上万条序列,而且没有开关能关掉它——采集夜莺自身指标时要把这份成本算进去。
为什么这里没有规格表
「N 核 M 内存支持 K 条规则」这种数字,只有在写清楚「规则查的是什么数据源、
每次返回多少条序列、执行频率多少」之后才有意义,而这三项在不同环境里能差两个数量级:
一条 up == 0 的规则和一条扫一万条序列再做 topk 的规则,成本不在一个量级上。
给一个没有前提条件的数字,读者照着买机器,出问题的时候这份文档要负责任。 所以这里给的是量法和扩的方向:先在你自己的规模上跑起来,量上面四个数,再按需要扩。