告警规则
介绍Pigsty附带的数据库告警规则,以及如何定制报警规则
Pigsty有两套并行的告警系统:
- Prometheus + AlertManager (主)
- Grafana(备),默认不启用
两套系统功能等效,侧重能力不同,可同时使用,互为备份补充。
告警
告警对于日常故障响应,提高系统可用性至关重要。
漏报会导致可用性降低,误报会导致敏感性下降,有必要对告警规则进行审慎的设计。
- 合理定义告警级别,以及相应的处理流程
- 合理定义告警指标,去除重复告警项,补充缺失告警项
- 根据历史监控数据科学配置告警阈值,减少误报率。
- 合理疏理特例规则,消除维护工作,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状态的告警通常会隐藏或以灰色显示。
告警规则
告警规则按类型可粗略分为四类:错误,延迟,饱和度,流量。其中:
- 错误:主要关注各个组件的存活性(Aliveness),以及网络中断,脑裂等异常情况,级别通常较高(P0|P1)。
- 延迟:主要关注查询响应时间,复制延迟,慢查询,长事务。
- 饱和度:主要关注CPU,磁盘(这两个属于系统监控但对于DB非常重要所以纳入),连接池排队,数据库后端连接数,年龄(本质是可用事物号的饱和度),SSD寿命等。
- 流量:QPS,TPS,Rollback(流量通常与业务指标有关属于业务监控范畴,但因为对于DB很重要所以纳入),QPS的季节性,TPS的突增。
Prometheus告警规则
告警规则使用Prometheus语法定义,完整的告警规则详见:
Pigsty典型告警
错误告警
数据库实例宕机将立刻触发P0报警。
# database server down
- alert: PostgresDown
expr: pg_up < 1
for: 1m
labels: { level: 0, severity: CRIT, category: pgsql }
annotations:
summary: "CRIT PostgresDown {{ $labels.ins }}@{{ $labels.instance }}"
description: |
pg_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
http://g.pigsty/d/pgsql-instance?var-ins={{ $labels.ins }}
在生产环境使用PostgreSQL时,Pgbouncer实例与Postgres是一一对应的命运共同体,Pgbouncer故障效果基本与Postgres故障等同,其存活性告警规则级别与Postgres统一。
# database connection pool down
- alert: PgbouncerDown
expr: pgbouncer_up < 1
for: 1m
labels: { level: 0, severity: CRIT, category: pgsql }
annotations:
summary: "CRIT PostgresDown {{ $labels.ins }}@{{ $labels.instance }}"
description: |
pgbouncer_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value }} < 1
http://g.pigsty/d/pgsql-instance?var-ins={{ $labels.ins }}
监控代理Exporter宕机通常预示着严重故障:HAProxy 与Node Exporter宕机通常意味着负载均衡器与数据库节点本身宕机,需要重点关注
#==============================================================#
# Agent Aliveness #
#==============================================================#
# node & haproxy aliveness are determined directly by exporter aliveness
# including: node_exporter, pg_exporter, pgbouncer_exporter, haproxy_exporter
- alert: AgentDown
expr: agent_up < 1
for: 1m
labels: { level: 0, severity: CRIT, category: infra }
annotations:
summary: 'CRIT AgentDown {{ $labels.ins }}@{{ $labels.instance }}'
description: |
agent_up[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.2f" }} < 1
http://g.pigsty/d/pgsql-alert?viewPanel=22
所有存活性检测的持续时间阈值设定为1分钟,对15s的采集周期通常意味着连续4次探活失败。常规的快速重启操作通常不会触发存活性告警。
集群脑裂分区
一个数据库集群,应当有且仅有一个主库领导者实例。即集群正常情况下应当只有一个分区。如果集群的分区数量不为1(为0代表群龙无首,大于1代表群雄逐鹿)则代表集群进入了异常状态:不可写入或脑裂,会立即触发P0报警。因为检测阈值为1分钟,所以常规的Failover与Switchover通常不容易触发此告警。
# cluster partition: split brain
- alert: PostgresPartition
expr: pg:cls:partition != 1
for: 1m
labels: { level: 0, severity: CRIT, category: pgsql }
annotations:
summary: "CRIT PostgresPartition {{ $labels.cls }}@{{ $labels.job }} {{ $value }}"
description: |
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的时间告警阈值。
#==============================================================#
# Replication #
#==============================================================#
# replication break for 1m triggers a P1 alert (WARN: heal in 5m)
- alert: PostgresReplicationBreak
expr: changes(pg_downstream_count{state="streaming"}[5m]) > 0
# for: 1m
labels: { level: 1, severity: WARN, category: pgsql }
annotations:
summary: "WARN PostgresReplicationBreak: {{ $labels.ins }}@{{ $labels.instance }}"
description: |
changes(pg_downstream_count{ins={{ $labels.ins }}, instance={{ $labels.instance }}, state="streaming"}[5m]) > 0
# replication lag bytes > 1MiB or lag seconds > 1s
- alert: PostgresReplicationLag
expr: pg:ins:lag_bytes > 1048576 or pg:ins:lag_seconds > 1
for: 1m
labels: { level: 1, severity: WARN, category: pgsql }
annotations:
summary: "WARN PostgresReplicationLag: {{ $labels.ins }}@{{ $labels.instance }}"
description: |
pg:ins:lag_bytes[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.0f" }} > 1048576 or
pg:ins:lag_seconds[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.2f" }} > 1
此外,查询延迟与磁盘延迟也有相应的报警规则:
例如,磁盘读写平均响应时间持续一分钟超过32ms,或Pgbouncer中平均查询RT超过16ms均会触发P1告警。
# read latency > 32ms (typical on pci-e ssd: 100µs)
- alert: NodeDiskSlow
expr: node:dev:disk_read_rt_1m > 0.032 or node:dev:disk_write_rt_1m > 0.032
for: 1m
labels: { level: 1, severity: WARN, category: node }
annotations:
summary: 'WARN NodeReadSlow {{ $labels.ins }}@{{ $labels.instance }} {{ $value | printf "%.6f" }}'
description: |
node:dev:disk_read_rt_1m[ins={{ $labels.ins }}] = {{ $value | printf "%.6f" }} > 32ms
# pgbouncer avg response time > 16ms (database level)
- alert: PgbouncerQuerySlow
expr: pgbouncer:db:query_rt_1m > 0.016
for: 3m
labels: { level: 1, severity: WARN, category: pgsql }
annotations:
summary: "WARN PgbouncerQuerySlow: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
description: |
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中最重要的指标,集中体现了数据库实例与集群的负载水位。
#==============================================================#
# Saturation #
#==============================================================#
# instance pressure higher than 70% for 1m triggers a P1 alert
- alert: PostgresPressureHigh
expr: ins:pressure1 > 0.70
for: 1m
labels: { level: 1, severity: WARN, category: pgsql }
annotations:
summary: "WARN PostgresPressureHigh: {{ $labels.ins }}@{{ $labels.instance }}"
description: |
ins:pressure1[ins={{ $labels.ins }}, instance={{ $labels.instance }}] = {{ $value | printf "%.3f" }} > 0.70
堆积检测
堆积主要包含两类指标,一方面是PG本身的后端连接数与活跃连接数,另一方面是连接池的排队情况。
PGB排队是决定性的指标,它代表用户端可感知的阻塞已经出现,因此出现排队持续1分钟触发P0告警。
当使用Session Pooling模式时,可适当放宽此报警指标。
# pgbouncer client queue exists
- alert: PgbouncerClientQueue
expr: pgbouncer:db:waiting_clients > 1
for: 1m
labels: { level: 0, severity: CRIT, category: pgsql }
annotations:
summary: "CRIT PgbouncerClientQueue: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
description: |
pgbouncer:db:waiting_clients[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.0f" }} > 1
后端连接数是一个重要的告警指标,如果后端连接持续达到最大连接数,往往也意味着雪崩。连接池的排队连接数也能反映这种情况,但不能覆盖应用直连数据库的情况。
目前,Pigsty使用连接使用率作为告警指标,即数据库可用连接数量已经使用的百分比,超过70%持续3分钟即出发P1告警。
# database connection usage > 70%
- alert: PostgresConnUsageHigh
expr: pg:db:conn_usage > 0.70
for: 3m
labels: { level: 1, severity: WARN, category: pgsql }
annotations:
summary: "WARN PostgresConnUsageHigh: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
description: |
pg:db:conn_usage[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.3f" }} > 0.70
空闲事务
即数据库出现Idle in Transaction
状态的连接数量,超过2条持续3分钟即出发P1告警。
# database connection usage > 70%
- alert: PostgresIdleInXact
expr: pg:db:ixact_backends > 1
for: 3m
labels: { level: 2, severity: INFO, category: pgsql }
annotations:
summary: "Info PostgresIdleInXact: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
description: |
pg:db:ixact_backends[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.0f" }} > 1
资源告警
年龄(XID)使用量超过80%出发P0告警,这意味着系统快要消耗完事务号资源,进入XID Wraparound状态
# database age saturation > 80%
- alert: PostgresXidWarpAround
expr: pg:db:age > 0.80
for: 1m
labels: { level: 0, severity: CRIT, category: pgsql }
annotations:
summary: "CRIT PostgresXidWarpAround: {{ $labels.ins }}@{{ $labels.instance }} [{{ $labels.datname }}]"
description: |
pg:db:age[ins={{ $labels.ins }}, instance={{ $labels.instance }}, datname={{ $labels.datname }}] = {{ $value | printf "%.0f" }} > 80%
最后修改 2022-05-27: init commit (1e3e284)