一、 传统的select 1(不够可靠)
许多 HA(高可用)系统默认使用select 1来检测数据库状态。这种方法的局限性在于:它只能证明数据库进程还在,不能证明数据库能正常处理请求。
1. 线程并发限制导致的失效
- 现象:当 InnoDB 引擎的并发线程数达到
innodb_thread_concurrency设置的上限时,新的查询请求会进入等待状态 。 - 示例:
- 设置
innodb_thread_concurrency = 3。 - 如果有 3 个 Session 正在执行大查询(如
select sleep(100) from t),第 4 个 Session 执行业务查询会被堵住 。 - 但是,由于
select 1不需要进入引擎层访问表数据,它依然能执行成功 。
- 设置
- 结论:此时系统已不可用,但
select 1仍会返回正常 。
2. 关键概念:并发连接 vs. 并发查询
- 并发连接:指
show processlist看到的连接数。几千个并发连接通常只占用内存,影响较小 。 - 并发查询:指当前正在执行的语句。这是真正的 CPU 杀手,也是
innodb_thread_concurrency限制的对象 。 - 特例:为了避免系统锁死,进入锁等待(如等行锁、间隙锁)的线程不计入并发查询计数,因为它们不消耗 CPU 。
二、 外部检测方法
方案二:查表判断 (Select Table)
- 操作:在
mysql系统库中建立health_check表,定期执行select * from mysql.health_check。 - 进步:这种方法必须进入 InnoDB 引擎,因此能检测出由于并发线程过多导致的不可用 。
- 漏洞:当磁盘空间满(尤其是 binlog 磁盘)时,更新语句会被堵住,但读操作(如该 select 语句)可能依然正常返回 。
方案三:更新判断 (Update Table)
- 操作:定期更新
health_check表中的时间戳字段 。 - 解决冲突:为了防止在双 M 架构中主备同步产生行冲突,建议根据
server_id存储多行数据
insertintomysql.health_check(id,t_modified)values(@@server_id,now())onduplicatekeyupdatet_modified=now();[cite_start]三、内部统计方法
针对外部检测(如执行 SQL 语句)存在的随机性与延迟问题,MySQL 提供了内部统计方案,通过直接监控数据库引擎内部的 IO 执行耗时来判断系统是否出问题。
以下是基于performance_schema库进行内部统计监测的具体逻辑与示例:
1. 开启监控开关:setup_instruments
在 MySQL 中,并非所有监控默认都是开启的。要获取 IO 耗时,首先需要配置“仪器”(Instruments)。
- ENABLED (开启):告诉 MySQL 记录这类事件 。
- Timed (计时):这是关键参数。如果只开启 ENABLED 而不开启 Timed,MySQL 只会统计“发生了多少次”,而不会记录“每次花了多久”。
示例操作:开启 redo log 的写入计时监控。
UPDATEperformance_schema.setup_instrumentsSETENABLED='YES',Timed='YES'WHEREnameLIKE'%wait/io/file/innodb/innodb_log_file%';2. 读取统计数据:file_summary_by_event_name表
开启计时后,MySQL 会将 IO 耗时汇总到该表中。我们重点关注redo log和binlog的写入情况,因为它们直接反映了磁盘 IO 的真实压力 。
示例查询:查看 redo log 的 IO 统计。
SELECT*FROMperformance_schema.file_summary_by_event_nameWHEREevent_name='wait/io/file/innodb/innodb_log_file'\G核心字段解释(以示例行数据为例):
- COUNT_STAR (200192):所有 IO 操作的总次数 。
- SUM_TIMER_WAIT:总耗时(单位:皮秒,1秒 =101210^{12}1012皮秒) 。
- MAX_TIMER_WAIT (3279615848):这是最重要的指标。它记录了从统计开始以来,单次最慢的 IO 耗时。
3. 诊断异常:设定延迟阈值
外部检测(如update语句)可能因为刚好分配到 IO 资源而在超时前返回,从而掩盖系统极慢的事实 。而内部统计直接看的是“最慢的那次 IO 耗时”。
检测示例:
- 设定一个阈值,例如单次 IO 超过200毫秒即判定为磁盘 IO 异常 。
- 执行检测语句:
SELECTevent_name,MAX_TIMER_WAITFROMperformance_schema.file_summary_by_event_nameWHEREevent_nameLIKE'%innodb_log_file%';- 如果
MAX_TIMER_WAIT换算后超过了 200ms,说明主库的 IO 响应已经出现了严重抖动,即使当前的select 1还能成功,也应该考虑主备切换 。
4. 统计复位:truncate
由于MAX_TIMER_WAIT记录的是历史最大值,为了持续监控,我们需要在发现异常并处理后重置统计数据 。
示例操作:
TRUNCATETABLEperformance_schema.file_summary_by_event_name;这会把所有的计数和计时清零,这样接下来的监控看到的就是最新的最大值 。
5. 性能权衡
虽然内部统计非常精准,但它并非没有代价:
- 额外损耗:由于每一次 IO 操作都需要额外记录耗时信息,开启所有监控项会导致性能下降约10%。
- 策略建议:不要开启全部监控。只针对核心的 redo log 和 binlog 开启计时(Timed=‘YES’),将损耗降到最低 。
总结逻辑:通过setup_instruments开启计时器→\rightarrow→监控file_summary_by_event_name中的单次最大延迟→\rightarrow→发现超过阈值即判定故障→\rightarrow→定期执行truncate重置统计。