跳到主要内容

用夜莺监控 MySQL

连上实例跑 SHOW STATUS、SHOW VARIABLES 和复制状态,慢查询堆积、连接数打满、主从中断与延迟都有现成规则和处置步骤。

最后校对于

MySQL 插件的原理很直接:连到实例,执行 SHOW GLOBAL STATUS、SHOW GLOBAL VARIABLES、SHOW SLAVE STATUS 等语句,把结果整理成指标。默认采集基础状态和复制状态,InnoDB 扩展指标、processlist、库表大小这些按需打开。还可以写自定义 SQL,把查询结果当指标上报。

模板里的告警规则覆盖运维上最常见的几类事故:慢查询堆积、连接数接近 max_connections、线程大面积 running、主从 IO/SQL 线程中断、复制延迟、实例重启、打开文件数逼近上限,每条都附处置步骤。仪表盘分「本机采集」「按 address 筛选远端多实例」「按 instance 标签筛选」三种用法,另有一套按 mysqld_exporter 指标名写的。

给监控账号 PROCESS、REPLICATION CLIENT 和 SELECT 权限即可,不要用 root。

模板里有什么​

  • 7 张仪表盘,共 227 个面板
  • 20 条告警规则,每条附处置步骤
  • 31 条指标说明
  • Categraf 采集配置:input.mysql

怎么接入​

  1. 安装 Categraf,把下面的配置放到 conf/input.mysql/mysql.toml,按实际地址和凭据改好后重启 Categraf。启动日志里出现 input: local.mysql started 就说明插件已加载。

    # # collect interval
    # interval = 15

    # [[queries]]
    # measurement = "users"
    # metric_fields = [ "total" ]
    # label_fields = [ "service" ]
    # timeout = "3s"
    # request = '''
    # select 'n9e' as service, count(*) as total from n9e_v5.users
    # '''

    [[instances]]
    # address = "127.0.0.1:3306"
    # username = "root"
    # password = "1234"

    # # set tls=custom to enable tls
    # parameters = "tls=false"

    # extra_status_metrics = true
    # extra_innodb_metrics = false
    # gather_processlist_processes_by_state = false
    # gather_processlist_processes_by_user = false
    # gather_schema_size = true
    # gather_table_size = false
    # gather_system_table_size = false
    # gather_slave_status = true

    # # timeout
    # timeout_seconds = 3

    # # interval = global.interval * interval_times
    # interval_times = 1

    # important! use global unique string to specify instance
    # labels = { instance="n9e-10.2.3.4:3306" }

    ## Optional TLS Config
    # use_tls = false
    # tls_min_version = "1.2"
    # tls_ca = "/etc/categraf/ca.pem"
    # tls_cert = "/etc/categraf/cert.pem"
    # tls_key = "/etc/categraf/key.pem"
    ## Use TLS but skip chain & host verification
    # insecure_skip_verify = true

    #[[instances.queries]]
    # measurement = "lock_wait"
    # metric_fields = [ "total" ]
    # timeout = "3s"
    # request = '''
    #SELECT count(*) as total FROM information_schema.innodb_trx WHERE trx_state='LOCK WAIT'
    #'''

    # [[instances.queries]]
    # measurement = "users"
    # metric_fields = [ "total" ]
    # label_fields = [ "service" ]
    # # field_to_append = ""
    # timeout = "3s"
    # request = '''
    # select 'n9e' as service, count(*) as total from n9e_v5.users
    # '''
  2. 在夜莺「集成中心」里找到 MySQL,把仪表盘和告警规则导入到业务组。

  3. 导入的告警规则默认是停用的。先确认指标已经入库,再按自己环境的阈值逐条启用。

内置仪表盘​

仪表盘面板数
MySQL 仪表盘(使用 address 筛选,用于中心端 Categraf 采集远端多个 mysql 实例的场景)39
MySQL 仪表盘(使用 instance 筛选,需要采集时自行打上 instance 标签)39
MySQL 仪表盘,适用于 Categraf 采集本机 MySQL 的场景39
MySQL Overview by categraf24
MySQL Overview by categraf, group by ident38
MySQL Overview by categraf, group by instance24
MySQL Overview by exporter24

内置告警规则​

共 20 条。每条给出触发条件(PromQL)和告警后的处置步骤,导入后可以直接改阈值。

规则按采集方式分组,用哪种采集器就导哪一组。

Categraf 采集(10)​

MySQL slow queries are piling up - categraf​

MySQL slow queries are piling up over the last 5 minutes

S2 警告 · 持续 2 分钟 · 触发条件:

increase(mysql_global_status_slow_queries[5m]) > 10

处置步骤:

  1. SHOW FULL PROCESSLIST 找当前长时间运行的 SQL,必要时 KILL <id> 先止血;
  2. 用 mysqldumpslow -s t -t 10 <slow_log> 或 pt-query-digest 定位 TOP 慢 SQL;
  3. 对定位到的 SQL 执行 EXPLAIN 看执行计划,补索引或改写;
  4. 若是 long_query_time 设置过低导致的噪音,调整该参数而不是忽略告警。

More than 60% of the connections in Mysql are in a running state - categraf​

S2 警告 · 持续 2 分钟 · 触发条件:

avg by (instance) (mysql_global_status_threads_running) / avg by (instance) (mysql_global_variables_max_connections) * 100 > 60

处置步骤:

  1. SHOW FULL PROCESSLIST 看堆积的线程集中在哪条 SQL、哪张表;
  2. SHOW ENGINE INNODB STATUS 查是否存在锁等待或死锁;
  3. 对元凶 SQL 执行 KILL 止血后补索引或限流;
  4. 排查上游是否有突发流量或慢依赖导致连接迟迟不释放。

Mysql has just restarted. Please be advised - categraf​

MySQL has just been restarted, less than one minute ago

S3 提醒 · 触发条件:

mysql_global_status_uptime < 60

处置步骤:

  1. 查看 error log(SHOW VARIABLES LIKE 'log_error' 指向的文件)确认是崩溃、被 OOM kill 还是人工重启;
  2. 若是 OOM,核对 innodb_buffer_pool_size 与机器物理内存后调小;
  3. 若非计划内重启,检查 systemd 或容器编排是否在反复拉起;
  4. 重启后确认主从复制已自动恢复、应用连接池已重连。

Mysql has opened a large number of file handles. Please be aware - categraf​

More than 80% of MySQL files open

S2 警告 · 持续 2 分钟 · 触发条件:

avg by (instance) (mysql_global_status_open_files) / avg by (instance)(mysql_global_variables_open_files_limit) * 100 > 80

处置步骤:

  1. 用 SHOW GLOBAL STATUS LIKE 'Open_files' 和 SHOW VARIABLES LIKE 'open_files_limit' 确认当前水位;
  2. 调大 my.cnf 中的 open_files_limit,并同步放开系统 ulimit -n 与 systemd 的 LimitNOFILE;
  3. 检查 table_open_cache 是否设置过大导致句柄膨胀;
  4. 排查是否有大量分区表或小表被同时访问。

Mysql instance has crashed - categraf​

S1 紧急 · 触发条件:

mysql_up == 0

处置步骤:

  1. 登录主机用 systemctl status mysqld 或 docker ps 确认进程是否存活;
  2. 进程存活则用 mysql -h<host> -P<port> -u<user> -p 手工连一次,区分是实例夯住还是网络/账号问题;
  3. 进程不在则先看 error log 尾部定位崩溃原因(OOM、磁盘满、数据文件损坏)再拉起,不要盲目重启;
  4. 有主从的立即评估是否需要切主,并确认应用已摘除该节点。

MysqlInnodbLogWaits - categraf​

MySQL innodb log writes stalling

S2 警告 · 触发条件:

rate(mysql_global_status_innodb_log_waits[15m]) > 10

处置步骤:

  1. 调大 innodb_log_buffer_size(通常从默认 16M 翻倍到 64M~256M);
  2. 检查 innodb_log_file_size 是否过小导致频繁 checkpoint;
  3. 用 iostat -x 1 看 redo log 所在磁盘的 util 是否已经打满;
  4. 排查是否有大事务一次性写入过多数据,拆成小批次提交。

MysqlSlaveIoThreadNotRunning - categraf​

MySQL Slave IO thread not running

S1 紧急 · 触发条件:

mysql_slave_status_master_server_id > 0 and ON (instance) mysql_slave_status_slave_io_running == 0

处置步骤:

  1. 在从库执行 SHOW SLAVE STATUS\G 看 Last_IO_Error;
  2. 常见原因是主库连不上、复制账号失效、或所需 binlog 已被 purge——分别处理网络、用 CHANGE MASTER TO 重设账号、或用备份重建从库;
  3. 处理完执行 START SLAVE IO_THREAD 并确认 Slave_IO_Running=Yes;
  4. 恢复前先把读流量从该从库摘走。

MysqlSlaveReplicationLag - categraf​

S1 紧急 · 持续 1 分钟 · 触发条件:

mysql_slave_status_master_server_id > 0 and ON (instance) (mysql_slave_status_seconds_behind_master - mysql_slave_status_sql_delay) > 30

处置步骤:

  1. SHOW SLAVE STATUS\G 看 Seconds_Behind_Master 与 SQL 线程当前正在执行的事件;
  2. 到主库用 SHOW PROCESSLIST 找是否有大事务或批量 DML 正在灌数据;
  3. 从库若是单线程回放,开启并行复制(slave_parallel_workers / slave_parallel_type=LOGICAL_CLOCK);
  4. 延迟持续扩大时先把读流量切回主库或其他从库。

MysqlSlaveSqlThreadNotRunning - categraf​

MySQL Slave SQL thread not running

S1 紧急 · 触发条件:

mysql_slave_status_master_server_id > 0 and ON (instance) mysql_slave_status_slave_sql_running == 0

处置步骤:

  1. SHOW SLAVE STATUS\G 看 Last_SQL_Error 定位卡住的事件;
  2. 若是可安全跳过的冲突(如重复主键),核对数据一致后执行 SET GLOBAL sql_slave_skip_counter=1 再 START SLAVE SQL_THREAD;
  3. 若主从数据已经分叉,用备份重建从库,不要盲目跳过;
  4. 恢复前先把读流量从该从库摘走。

The number of connections in Mysql has exceeded 80% - categraf​

More than 80% of MySQL connections are in use

S2 警告 · 持续 2 分钟 · 触发条件:

avg by (instance) (mysql_global_status_threads_connected) / avg by (instance) (mysql_global_variables_max_connections) * 100 > 80

处置步骤:

  1. SHOW FULL PROCESSLIST 按来源主机统计连接,找出连接数异常的应用;
  2. 区分是业务突增还是应用连接池泄漏(大量长时间 Sleep 的连接堆积);
  3. 应急可调大 max_connections,同时核对内存余量避免 OOM;
  4. 根因侧收敛应用连接池上限、缩短 wait_timeout。

Exporter 采集(10)​

More than 60% of the connections in MySQL are in a running state​

S2 警告 · 持续 2 分钟 · 触发条件:

avg by (instance) (mysql_global_status_threads_running) / avg by (instance) (mysql_global_variables_max_connections) * 100 > 60

处置步骤:

  1. SHOW FULL PROCESSLIST 看堆积的线程集中在哪条 SQL、哪张表;
  2. SHOW ENGINE INNODB STATUS 查是否存在锁等待或死锁;
  3. 对元凶 SQL 执行 KILL 止血后补索引或限流;
  4. 排查上游是否有突发流量或慢依赖导致连接迟迟不释放。

More than 80% of MySQL files open​

More than 80% of MySQL files open

S2 警告 · 持续 2 分钟 · 触发条件:

avg by (instance) (mysql_global_status_innodb_num_open_files) / avg by (instance)(mysql_global_variables_open_files_limit) * 100 > 80

处置步骤:

  1. 用 SHOW GLOBAL STATUS LIKE 'Open_files' 和 SHOW VARIABLES LIKE 'open_files_limit' 确认当前水位;
  2. 调大 my.cnf 中的 open_files_limit,并同步放开系统 ulimit -n 与 systemd 的 LimitNOFILE;
  3. 检查 table_open_cache 是否设置过大导致句柄膨胀;
  4. 排查是否有大量分区表或小表被同时访问。

MySQL connection count has exceeded 80%​

More than 80% of MySQL connections are in use

S2 警告 · 持续 2 分钟 · 触发条件:

avg by (instance) (mysql_global_status_threads_connected) / avg by (instance) (mysql_global_variables_max_connections) * 100 > 80

处置步骤:

  1. SHOW FULL PROCESSLIST 按来源主机统计连接,找出连接数异常的应用;
  2. 区分是业务突增还是应用连接池泄漏(大量长时间 Sleep 的连接堆积);
  3. 应急可调大 max_connections,同时核对内存余量避免 OOM;
  4. 根因侧收敛应用连接池上限、缩短 wait_timeout。

Mysql has just restarted. Please be advised - exporter​

MySQL has just been restarted, less than one minute ago

S3 提醒 · 触发条件:

mysql_global_status_uptime < 60

处置步骤:

  1. 查看 error log(SHOW VARIABLES LIKE 'log_error' 指向的文件)确认是崩溃、被 OOM kill 还是人工重启;
  2. 若是 OOM,核对 innodb_buffer_pool_size 与机器物理内存后调小;
  3. 若非计划内重启,检查 systemd 或容器编排是否在反复拉起;
  4. 重启后确认主从复制已自动恢复、应用连接池已重连。

MySQL slow queries are piling up​

MySQL slow queries are piling up over the last 5 minutes

S2 警告 · 持续 2 分钟 · 触发条件:

increase(mysql_global_status_slow_queries[5m]) > 10

处置步骤:

  1. SHOW FULL PROCESSLIST 找当前长时间运行的 SQL,必要时 KILL <id> 先止血;
  2. 用 mysqldumpslow -s t -t 10 <slow_log> 或 pt-query-digest 定位 TOP 慢 SQL;
  3. 对定位到的 SQL 执行 EXPLAIN 看执行计划,补索引或改写;
  4. 若是 long_query_time 设置过低导致的噪音,调整该参数而不是忽略告警。

MysqlInnodbLogWaits - exporter​

MySQL innodb log writes stalling

S2 警告 · 触发条件:

rate(mysql_global_status_innodb_log_waits[15m]) > 10

处置步骤:

  1. 调大 innodb_log_buffer_size(通常从默认 16M 翻倍到 64M~256M);
  2. 检查 innodb_log_file_size 是否过小导致频繁 checkpoint;
  3. 用 iostat -x 1 看 redo log 所在磁盘的 util 是否已经打满;
  4. 排查是否有大事务一次性写入过多数据,拆成小批次提交。

MysqlSlaveIoThreadNotRunning - exporter​

MySQL Slave IO thread not running

S1 紧急 · 触发条件:

mysql_slave_status_master_server_id > 0 and ON (instance) mysql_slave_status_slave_io_running == 0

处置步骤:

  1. 在从库执行 SHOW SLAVE STATUS\G 看 Last_IO_Error;
  2. 常见原因是主库连不上、复制账号失效、或所需 binlog 已被 purge——分别处理网络、用 CHANGE MASTER TO 重设账号、或用备份重建从库;
  3. 处理完执行 START SLAVE IO_THREAD 并确认 Slave_IO_Running=Yes;
  4. 恢复前先把读流量从该从库摘走。

MysqlSlaveReplicationLag - exporter​

S1 紧急 · 持续 1 分钟 · 触发条件:

mysql_slave_status_master_server_id > 0 and ON (instance) (mysql_slave_status_seconds_behind_master - mysql_slave_status_sql_delay) > 30

处置步骤:

  1. SHOW SLAVE STATUS\G 看 Seconds_Behind_Master 与 SQL 线程当前正在执行的事件;
  2. 到主库用 SHOW PROCESSLIST 找是否有大事务或批量 DML 正在灌数据;
  3. 从库若是单线程回放,开启并行复制(slave_parallel_workers / slave_parallel_type=LOGICAL_CLOCK);
  4. 延迟持续扩大时先把读流量切回主库或其他从库。

MysqlSlaveSqlThreadNotRunning - exporter​

MySQL Slave SQL thread not running

S1 紧急 · 触发条件:

mysql_slave_status_master_server_id > 0 and ON (instance) mysql_slave_status_slave_sql_running == 0

处置步骤:

  1. SHOW SLAVE STATUS\G 看 Last_SQL_Error 定位卡住的事件;
  2. 若是可安全跳过的冲突(如重复主键),核对数据一致后执行 SET GLOBAL sql_slave_skip_counter=1 再 START SLAVE SQL_THREAD;
  3. 若主从数据已经分叉,用备份重建从库,不要盲目跳过;
  4. 恢复前先把读流量从该从库摘走。

The MySQL instance is down​

S1 紧急 · 触发条件:

mysql_up == 0

处置步骤:

  1. 登录主机用 systemctl status mysqld 或 docker ps 确认进程是否存活;
  2. 进程存活则用 mysql -h<host> -P<port> -u<user> -p 手工连一次,区分是实例夯住还是网络/账号问题;
  3. 进程不在则先看 error log 尾部定位崩溃原因(OOM、磁盘满、数据文件损坏)再拉起,不要盲目重启;
  4. 有主从的立即评估是否需要切主,并确认应用已摘除该节点。

指标说明​

共 31 条,和仪表盘、告警规则里用到的指标一一对应。

指标含义单位
mysql_global_status_buffer_pool_bytes_dataGlobal Status InnoDB 缓冲池 data 大小bytes
mysql_global_status_buffer_pool_bytes_dirtyGlobal Status InnoDB 缓冲池 dirty 大小bytes
mysql_global_status_buffer_pool_bytes_freeGlobal Status InnoDB 缓冲池 free 大小bytes
mysql_global_status_buffer_pool_pages_utilizationGlobal Status InnoDB 缓冲池 page 使用率%
mysql_global_status_buffer_pool_bytes_usedGlobal Status InnoDB 缓冲池 used 大小bytes
mysql_global_status_buffer_pool_bytes_totalGlobal Status InnoDB 缓冲池总大小bytes
mysql_global_status_uptimeGlobal Status 启动时长s
mysql_global_status_threads_runningGlobal Status 当前 running 的 threads 数量
mysql_global_status_open_filesGlobal Status 当前打开的文件句柄数
mysql_global_status_threads_connectedGlobal Status 当前连接数
mysql_global_status_max_used_connectionsGlobal Status 最大曾用连接数 — 曾经达到过的最大连接数
irate(mysql_global_status_commands_total[3m])Global Status 每秒 Command 数量
irate(mysql_global_status_queries[3m])Global Status 每秒 query 数量
irate(mysql_global_status_questions[3m])Global Status 每秒 question 数量
irate(mysql_global_status_slow_queries[3m])Global Status 每秒 slow query 数量
sum(irate(mysql_global_status_commands_total{command=~"commit|rollback"}[3m])) without (command)Global Status 每秒事务操作数量
sum(irate(mysql_global_status_commands_total{command=~"insert|update|delete|replace"}[3m])) without (command)Global Status 每秒写操作数量
irate(mysql_global_status_bytes_sent[3m])Global Status 每秒发送流量bytes/s
irate(mysql_global_status_bytes_received[3m])Global Status 每秒接收流量bytes/s
sum(irate(mysql_global_status_commands_total{command="select"}[3m])) without (command)Global Status 每秒读操作数量
increase(mysql_global_status_aborted_clients[3m])Global Status 近 3 分钟 abort 的客户端 — 原始指标 mysql_global_status_aborted_clients 表示由于客户端未正确关闭连接而终止的连接数,Counter 类型,单调递增。
increase(mysql_global_status_aborted_connects[3m])Global Status 近 3 分钟 abort 的连接数 — 原始指标 mysql_global_status_aborted_connects 表示尝试连接到 MySQL 服务器失败的次数,Counter 类型,单调递增。
increase(mysql_global_status_table_locks_waited[3m])Global Status 近 3 分钟 table lock 等待次数
mysql_global_variables_innodb_buffer_pool_sizeGlobal Variables InnoDB 缓冲池配置大小bytes
mysql_global_variables_read_onlyGlobal Variables read_only 开关值 — 0 就是 OFF,1 是 ON
mysql_global_variables_open_files_limitGlobal Variables 允许打开的文件句柄数
mysql_global_variables_max_connectionsGlobal Variables 最大连接数限制 — 允许的最大连接数,默认值是 151,过小了。 通过 SHOW VARIABLES LIKE 'max_connections' 命令查看当前设置; 通过 SET GLOBAL max_connections = 2048 重新设置最大连接数; 通过修改 MySQL 配置文件,在 [mysqld] 下面添加 max_connections = 2048 使其重启依旧生效
mysql_global_variables_query_cache_sizeGlobal Variables 查询缓存大小bytes
mysql_upMySQL 实例是否 UP — 1 表示 UP,说明能正常连到 MySQL 采集数据;0 表示无法连通 MySQL 实例,可能是网络问题、认证问题,或者 MySQL 本身就是挂了
mysql_scrape_use_secondsMySQL 指标抓取耗时s
mysql_version_infoMySQL 版本信息

相关链接​