MySQL 告警举例(商业版)
夜莺 v9 MySQL 数据源告警举例:以打车订单业务为例,展示如何用告警表达式语法表达常见 SQL 业务告警场景。
[PLUS] MySQL 作为告警数据源是夜莺企业版(PLUS)独有功能。
概述
MySQL 告警 = 直接用 SQL 查业务库做告警判定 — 不用把业务数据先 export 成 metric,省去采集层。
本文以一个打车订单业务为例,演示如何把 告警表达式语法 应用到 MySQL 数据源的常见场景。
适用场景:
- 业务实时监控:订单成功率、退款率、客单价异常等指标,数据直接在业务库里;
- 数据完整性告警:表数据 N 分钟未更新就告警;
- 业务异常状态扫描:按订单状态/异常等级筛选触发告警。
阅读前必读
本文假设你已经了解:
- 告警表达式语法 的基本运算符;
- MySQL 数据源 的接入方式;
- MySQL 查询条件 的配置。
业务表结构
假设业务库 taxi_service,订单表 orders:
| 字段 | 含义 | 取值 |
|---|---|---|
order_id |
订单 ID | 自增 |
passenger_name |
乘客姓名 | 字符串 |
driver_name |
司机姓名 | 字符串 |
status |
订单状态 | Payment Successful / Order Canceled |
abnormal_status |
异常等级 | No Abnormality / Low Level Abnormality / Medium Level Abnormality / High Level Abnormality |
created_at |
创建时间 | timestamp |
updated_at |
更新时间 | timestamp |
completed_at |
完成时间 | timestamp |
order_amount |
订单金额 | float |
order_duration |
订单时长(分钟) | int |
1. 算术运算
1.1 单查询条件
目标:最近 3 天的支付成功订单平均金额 < 60 触发告警。
-- $A
SELECT AVG(order_amount) AS avg_successful_payments
FROM orders
WHERE status = 'Payment Successful'
AND created_at > DATE_SUB(NOW(), INTERVAL 3 DAY);
告警表达式:
$A.avg_successful_payments < 60
1.2 多查询条件优先级
目标:近 3 天取消订单金额占总金额 > 5% 触发告警。
-- $A:成功订单金额
SELECT SUM(order_amount) AS total_successful_payments
FROM orders WHERE status = 'Payment Successful';
-- $B:取消订单金额
SELECT SUM(order_amount) AS total_canceled_orders
FROM orders WHERE status = 'Order Canceled';
告警表达式:
$B.total_canceled_orders / ($A.total_successful_payments + $B.total_canceled_orders) * 100 > 5
2. 关系运算符
目标:近 6 小时订单(无异常 OR 高级别异常)且取消金额 > 100 触发告警。
-- $A:6 小时取消订单按异常等级分组
SELECT status, abnormal_status, SUM(order_amount) AS total_order_amount
FROM orders
WHERE status = 'Order Canceled'
AND created_at > DATE_SUB(NOW(), INTERVAL 6 HOUR)
GROUP BY status, abnormal_status;
告警表达式:
$A.status == 'Order Canceled' && $A.abnormal_status == "No Abnormality" && $A.total_order_amount > 100
||
$A.status == 'Order Canceled' && $A.abnormal_status == "High Level Abnormality" && $A.total_order_amount > 100
3. 逻辑运算符(AND / OR 组合)
目标:昨日取消订单量 > 前日 AND 昨日成功订单占比前日 < 60% 触发告警。
-- $A:昨日数据
-- $B:前日数据
告警表达式:
$A.failed_orders > $B.failed_orders && $A.successful_orders / $B.successful_orders < 0.6
4. 集合运算(in / not in)
目标:司机 Driver13 / Driver33 任一订单金额 > 1000 或订单数 > 50 触发告警。
-- $A:按司机分组
SELECT driver_name, COUNT(*) AS counts, SUM(order_amount) AS total_order_amount
FROM orders GROUP BY driver_name;
告警表达式:
($A.driver_name in ["Driver13", "Driver33"] && $A.total_order_amount > 1000)
||
($A.driver_name in ["Driver13", "Driver33"] && $A.counts > 50)
in是精确匹配数组成员,不是模糊匹配。要做"姓名包含" 用contains。
5. 字符串包含(contains)
目标:司机姓名包含 “Driver9” 且订单总金额 > 3000 触发告警(关键词可以是 error code)。
告警表达式:
$A.driver_name contains "Driver9" && $A.total_order_amount > 3000
适合含一类错误关键字的所有项告警,比如
$A.error_code contains "TIMEOUT"。
6. 正则匹配(matches)
目标:订单异常状态匹配 ^.* Level Abnormality$ 正则且 count > 55 触发告警(覆盖 Low/Medium/High 三个级别)。
告警表达式:
$A.abnormal_status matches ".* Level Abnormality$" && $A.total_counts > 55
7. 值范围(between)
目标:订单金额在 50-100 区间的单数 > 1 触发告警。
告警表达式:
$A.total_counts > 1 && between($A.order_amount, [50, 100])
between闭区间。仅适用数值类型,字符串区间不支持。
8. 时间戳运算(数据新鲜度)
目标:表数据超过 60s 未更新触发告警(数据停止上报)。
-- $A:最新一条数据的时间戳
SELECT MAX(UNIX_TIMESTAMP(created_at)) AS create_at FROM orders;
告警表达式:
now().Unix() - $A.create_at > 60
时间戳仅支持加减,不能乘除。
常见问题
Q1:MySQL 数据源每多久跑一次查询?会不会压垮业务库?
A:由告警规则的"执行频率"决定(默认 15s)。核心业务库强烈建议:
- 给 n9e 用单独的只读账号;
- 把执行频率降到 1m+;
- 用 SQL
LIMIT限制返回行数; - 复杂查询前提前看 explain。
Q2:SQL 返回的列怎么映射成 $A.字段名?
A:告警规则的"查询条件"里有"值字段"和"标签字段"两个配置:
- 值字段:选 SQL 结果的某列作为
$A.xxx引用的 xxx; - 标签字段:选 SQL 结果的某些列作为告警事件的标签(影响通知里能引用哪些维度)。
如 SQL SELECT product, count(*) AS cnt FROM ...,值字段选 cnt,标签字段选 product,表达式里就是 $A.cnt。
Q3:能不能在 SQL 里用变量(如时间范围)?
A:可以。SQL 输入框里支持模板变量,常用 {{ time_now }} / {{ time_range }} 占位。具体支持的占位符见 MySQL 查询配置 文档。
Q4:MySQL 告警和 Prometheus 告警在表达式上有区别吗?
A:表达式完全一致(同一套语法)。区别只在:
- 查询语言:Prometheus 用 PromQL;MySQL 用 SQL;
- 数据形态:PromQL 自带时间序列;MySQL 是表,需要值字段 + 标签字段配置才转成"伪时序"。
理解了一种数据源后,另一种只是查询语言不同。