告警规则

介绍Pigsty附带的数据库告警规则,以及如何定制报警规则

Pigsty有两套并行的告警系统:

两套系统功能等效,侧重能力不同,可同时使用,互为备份补充。

告警

告警对于日常故障响应,提高系统可用性至关重要。

漏报会导致可用性降低,误报会导致敏感性下降,有必要对告警规则进行审慎的设计。

  • 合理定义告警级别,以及相应的处理流程
  • 合理定义告警指标,去除重复告警项,补充缺失告警项
  • 根据历史监控数据科学配置告警阈值,减少误报率。
  • 合理疏理特例规则,消除维护工作,ETL,离线查询导致的误报。

告警分类学

按照来源模块分类

  • INFRA:基础设施类告警:Prometheus,Grafana,Consul,DNS,Nginx等基础设施软件等产生的告警。
  • NODES:主机节点告警,操作系统,硬件资源,基础设施软件,负载均衡等告警,通常由运维人员负责处理。
  • PGSQL:PostgreSQL数据库告警,数据库/连接池/负载均衡集群本身的告警,通常研发与DBA关注,DBA处理。
  • REDIS:Redis数据库告警,研发与DBA关注,DBA处理。
  • ……:应用板块告警,用告警由业务方自己负责,但DBA会为QPS,TPS,Rollback,Seasonality等业务指标设置告警
  • Pigsty使用category标签{infra,pgsql,nodes,redis,....}来标识告警的层次。

按紧急程度分类

  • P0:CRIT:产生重大场外影响的事故,需要紧急介入处理。例如主库宕机,复制中断。(事故)
  • P1:WARN:场外影响轻微,或有冗余处理的事故,需要在分钟级别内进行响应处理。(警告)
  • P2:INFO:即将产生影响,放任可能在小时级别内恶化,需在小时级别进行响应。(事件)
  • Pigsty使用与severity标签{CRIT,WARN,INFO}来标识告警的紧急程度。

按指标类型分类

  • 错误:PG Down, PGB Down, Exporter Down, 流复制中断,单集簇多主
  • 流量:QPS,TPS,Rollback,Seasonaility
  • 延迟: 平均响应时间,复制延迟
  • 饱和度:连接堆积,闲事务数,CPU,磁盘,年龄(事务号),缓冲区

告警可视化

在各类监控面板中,Pigsty使用时间轴状态图呈现告警信息。横轴代表时间段,一段色条代表告警事件。只有处于 激发(Firing) 状态的告警才会显示在告警图表中,处于Pending状态的告警通常会隐藏或以灰色显示。

告警规则 - 图1

告警规则

告警规则按类型可粗略分为四类:错误,延迟,饱和度,流量。其中:

  • 错误:主要关注各个组件的存活性(Aliveness),以及网络中断,脑裂等异常情况,级别通常较高(P0|P1)。
  • 延迟:主要关注查询响应时间,复制延迟,慢查询,长事务。
  • 饱和度:主要关注CPU,磁盘(这两个属于系统监控但对于DB非常重要所以纳入),连接池排队,数据库后端连接数,年龄(本质是可用事物号的饱和度),SSD寿命等。
  • 流量:QPS,TPS,Rollback(流量通常与业务指标有关属于业务监控范畴,但因为对于DB很重要所以纳入),QPS的季节性,TPS的突增。

Prometheus告警规则

告警规则使用Prometheus语法定义,完整的告警规则详见:

Pigsty典型告警

错误告警

数据库实例宕机将立刻触发P0报警。

  1. # database server down
  2. - alert: PostgresDown
  3. expr: pg_up < 1
  4. for: 1m
  5. labels: { level: 0, severity: CRIT, category: pgsql }
  6. annotations:
  7. summary: "CRIT PostgresDown {{ $labels.ins }}@{{ $labels.instance }}"
  8. description: |
  9. pg_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
  10. http://g.pigsty/d/pgsql-instance?var-ins={{ $labels.ins }}

在生产环境使用PostgreSQL时,Pgbouncer实例与Postgres是一一对应的命运共同体,Pgbouncer故障效果基本与Postgres故障等同,其存活性告警规则级别与Postgres统一。

  1. # database connection pool down
  2. - alert: PgbouncerDown
  3. expr: pgbouncer_up < 1
  4. for: 1m
  5. labels: { level: 0, severity: CRIT, category: pgsql }
  6. annotations:
  7. summary: "CRIT PostgresDown {{ $labels.ins }}@{{ $labels.instance }}"
  8. description: |
  9. pgbouncer_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
  10. http://g.pigsty/d/pgsql-instance?var-ins={{ $labels.ins }}

监控代理Exporter宕机通常预示着严重故障:HAProxy 与Node Exporter宕机通常意味着负载均衡器与数据库节点本身宕机,需要重点关注

  1. #==============================================================#
  2. # Agent Aliveness #
  3. #==============================================================#
  4. # node & haproxy aliveness are determined directly by exporter aliveness
  5. # including: node_exporter, pg_exporter, pgbouncer_exporter, haproxy_exporter
  6. - alert: AgentDown
  7. expr: agent_up < 1
  8. for: 1m
  9. labels: { level: 0, severity: CRIT, category: infra }
  10. annotations:
  11. summary: 'CRIT AgentDown {{ $labels.ins }}@{{ $labels.instance }}'
  12. description: |
  13. agent_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.2f" }} < 1
  14. http://g.pigsty/d/pgsql-alert?viewPanel=22

所有存活性检测的持续时间阈值设定为1分钟,对15s的采集周期通常意味着连续4次探活失败。常规的快速重启操作通常不会触发存活性告警。

集群脑裂分区

一个数据库集群,应当有且仅有一个主库领导者实例。即集群正常情况下应当只有一个分区。如果集群的分区数量不为1(为0代表群龙无首,大于1代表群雄逐鹿)则代表集群进入了异常状态:不可写入或脑裂,会立即触发P0报警。因为检测阈值为1分钟,所以常规的Failover与Switchover通常不容易触发此告警。

  1. # cluster partition: split brain
  2. - alert: PostgresPartition
  3. expr: pg:cls:partition != 1
  4. for: 1m
  5. labels: { level: 0, severity: CRIT, category: pgsql }
  6. annotations:
  7. summary: "CRIT PostgresPartition {{ $labels.cls }}@{{ $labels.job }} {{ $value }}"
  8. description: |
  9. pg:cls:partition[cls={{ $labels.cls }}, job={{ $labels.job }}] = {{ $value }} != 1

延迟告警

与复制延迟有关的告警有二个:复制中断,复制延迟高,定级为P1警告。

  • 其中复制中断是一种错误,使用指标:pg_downstream_count{state="streaming"}进行判断,当前streaming状态的从库如果数量发生负向变动,则触发break告警。walsender会决定复制的状态,从库直接断开会产生此现象,缓冲区出现积压时会从streaming进入catchup状态也会触发此告警。此外,采用-Xs手工制作备份结束时也会产生此告警,此告警会在5分钟后自动Resolve。复制中断会导致客户端读到陈旧的数据,具有一定的场外影响,定级为P1。

  • 复制延迟可以使用延迟时间或者延迟字节数判定。以延迟字节数为权威指标。常规状态下,复制延迟时间在百毫秒量级,复制延迟字节在百KB量级均属于正常。根据历史经验数据,目前采用的是1MB与1s的时间告警阈值。

  1. #==============================================================#
  2. # Replication #
  3. #==============================================================#
  4. # replication break for 1m triggers a P1 alert (WARN: heal in 5m)
  5. - alert: PostgresReplicationBreak
  6. expr: changes(pg_downstream_count{state="streaming"}[5m]) > 0
  7. # for: 1m
  8. labels: { level: 1, severity: WARN, category: pgsql }
  9. annotations:
  10. summary: "WARN PostgresReplicationBreak: {{ $labels.ins }}@{{ $labels.instance }}"
  11. description: |
  12. changes(pg_downstream_count{ins={{ $labels.ins }}, instance={{ $labels.instance }}, state="streaming"}[5m]) > 0
  13. # replication lag bytes > 1MiB or lag seconds > 1s
  14. - alert: PostgresReplicationLag
  15. expr: pg:ins:lag_bytes > 1048576 or pg:ins:lag_seconds > 1
  16. for: 1m
  17. labels: { level: 1, severity: WARN, category: pgsql }
  18. annotations:
  19. summary: "WARN PostgresReplicationLag: {{ $labels.ins }}@{{ $labels.instance }}"
  20. description: |
  21. pg:ins:lag_bytes[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.0f" }} > 1048576 or
  22. pg:ins:lag_seconds[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.2f" }} > 1

此外,查询延迟与磁盘延迟也有相应的报警规则:

例如,磁盘读写平均响应时间持续一分钟超过32ms,或Pgbouncer中平均查询RT超过16ms均会触发P1告警。

  1. # read latency > 32ms (typical on pci-e ssd: 100µs)
  2. - alert: NodeDiskSlow
  3. expr: node:dev:disk_read_rt_1m > 0.032 or node:dev:disk_write_rt_1m > 0.032
  4. for: 1m
  5. labels: { level: 1, severity: WARN, category: node }
  6. annotations:
  7. summary: 'WARN NodeReadSlow {{ $labels.ins }}@{{ $labels.instance }} {{ $value | printf "%.6f" }}'
  8. description: |
  9. node:dev:disk_read_rt_1m[ins={{ $labels.ins }}] = {{ $value | printf "%.6f" }} > 32ms
  10. # pgbouncer avg response time > 16ms (database level)
  11. - alert: PgbouncerQuerySlow
  12. expr: pgbouncer:db:query_rt_1m > 0.016
  13. for: 3m
  14. labels: { level: 1, severity: WARN, category: pgsql }
  15. annotations:
  16. summary: "WARN PgbouncerQuerySlow: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
  17. description: |
  18. pgbouncer:db:query_rt_1m[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.3f" }} > 0.016

饱和度告警

饱和度指标主要资源,包含很多系统级监控的指标。主要包括:CPU,磁盘(这两个属于系统监控但对于DB非常重要所以纳入),连接池排队,数据库后端连接数,年龄(本质是可用事物号的饱和度),SSD寿命等。

数据库压力

数据库压力是:机器CPU使用率,Pgbouncer时间利用率,Postgres时间利用率(14引入)的综合最大值(百分比,但过载时可以超过100%)。压力是Pigsty中最重要的指标,集中体现了数据库实例与集群的负载水位。

  1. #==============================================================#
  2. # Saturation #
  3. #==============================================================#
  4. # instance pressure higher than 70% for 1m triggers a P1 alert
  5. - alert: PostgresPressureHigh
  6. expr: ins:pressure1 > 0.70
  7. for: 1m
  8. labels: { level: 1, severity: WARN, category: pgsql }
  9. annotations:
  10. summary: "WARN PostgresPressureHigh: {{ $labels.ins }}@{{ $labels.instance }}"
  11. description: |
  12. ins:pressure1[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.3f" }} > 0.70

堆积检测

堆积主要包含两类指标,一方面是PG本身的后端连接数与活跃连接数,另一方面是连接池的排队情况。

PGB排队是决定性的指标,它代表用户端可感知的阻塞已经出现,因此出现排队持续1分钟触发P0告警。

当使用Session Pooling模式时,可适当放宽此报警指标。

  1. # pgbouncer client queue exists
  2. - alert: PgbouncerClientQueue
  3. expr: pgbouncer:db:waiting_clients > 1
  4. for: 1m
  5. labels: { level: 0, severity: CRIT, category: pgsql }
  6. annotations:
  7. summary: "CRIT PgbouncerClientQueue: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
  8. description: |
  9. pgbouncer:db:waiting_clients[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.0f" }} > 1

后端连接数是一个重要的告警指标,如果后端连接持续达到最大连接数,往往也意味着雪崩。连接池的排队连接数也能反映这种情况,但不能覆盖应用直连数据库的情况。

目前,Pigsty使用连接使用率作为告警指标,即数据库可用连接数量已经使用的百分比,超过70%持续3分钟即出发P1告警。

  1. # database connection usage > 70%
  2. - alert: PostgresConnUsageHigh
  3. expr: pg:db:conn_usage > 0.70
  4. for: 3m
  5. labels: { level: 1, severity: WARN, category: pgsql }
  6. annotations:
  7. summary: "WARN PostgresConnUsageHigh: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
  8. description: |
  9. pg:db:conn_usage[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.3f" }} > 0.70

空闲事务

即数据库出现Idle in Transaction状态的连接数量,超过2条持续3分钟即出发P1告警。

  1. # database connection usage > 70%
  2. - alert: PostgresIdleInXact
  3. expr: pg:db:ixact_backends > 1
  4. for: 3m
  5. labels: { level: 2, severity: INFO, category: pgsql }
  6. annotations:
  7. summary: "Info PostgresIdleInXact: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
  8. description: |
  9. pg:db:ixact_backends[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.0f" }} > 1

资源告警

年龄(XID)使用量超过80%出发P0告警,这意味着系统快要消耗完事务号资源,进入XID Wraparound状态

  1. # database age saturation > 80%
  2. - alert: PostgresXidWarpAround
  3. expr: pg:db:age > 0.80
  4. for: 1m
  5. labels: { level: 0, severity: CRIT, category: pgsql }
  6. annotations:
  7. summary: "CRIT PostgresXidWarpAround: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
  8. description: |
  9. pg:db:age[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.0f" }} > 80%

最后修改 2022-05-27: init commit (1e3e284)