Skip to content

MySQL 监控

1. 概述

MySQL 监控是数据库运维的重要组成部分,通过监控数据库连接、SQL 执行、慢查询等指标,可以及时发现和解决数据库性能问题,保证系统稳定运行。在梵医云系统中,使用 Druid 连接池进行 MySQL 监控。Druid 是阿里巴巴开源的数据库连接池,提供了强大的监控功能。本文档介绍如何配置和使用 MySQL 监控。

2. 监控体系架构

2.1 监控组件

梵医云系统 MySQL 监控包含以下组件:

  • Druid 连接池:数据库连接池和监控组件
  • Druid StatViewServlet:监控页面 Servlet
  • Druid WebStatFilter:Web 应用监控过滤器
  • Prometheus Exporter:指标导出到 Prometheus(可选)

2.2 监控架构

┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│  Application │ ───> │  Druid Pool │ ───> │  MySQL DB   │
│             │      │   Monitor   │      │             │
└─────────────┘      └─────────────┘      └─────────────┘


                    ┌─────────────┐
                    │  Druid Web  │
                    │   Monitor   │
                    └─────────────┘

3. Druid 配置

3.1 添加依赖

pom.xml 中添加 Druid 依赖:

xml
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.23</version>
</dependency>

3.2 配置 Druid

编辑 application.yaml

yaml
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.1.10:3306/fanyi_cloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: your_password
    druid:
      # 连接池初始化大小
      initial-size: 5
      # 连接池最小空闲连接数
      min-idle: 10
      # 连接池最大活跃连接数
      max-active: 20
      # 获取连接等待超时时间(毫秒)
      max-wait: 60000
      # 配置间隔多久进行一次检测,检测需要关闭的空闲连接(毫秒)
      time-between-eviction-runs-millis: 60000
      # 配置一个连接在池中最小生存的时间(毫秒)
      min-evictable-idle-time-millis: 300000
      # 配置一个连接在池中最大生存的时间(毫秒)
      max-evictable-idle-time-millis: 900000
      # 配置检测连接是否有效的 SQL
      validation-query: SELECT 1
      # 申请连接时执行 validationQuery 检测连接是否有效
      test-while-idle: true
      # 申请连接时执行 validationQuery 检测连接是否有效
      test-on-borrow: false
      # 归还连接时执行 validationQuery 检测连接是否有效
      test-on-return: false
      # 是否缓存 preparedStatement
      pool-prepared-statements: true
      # 配置监控统计拦截的 filters
      filters: stat,wall,slf4j
      # 通过 connectProperties 属性来打开 mergeSql 功能;慢 SQL 记录
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      # StatViewServlet 配置
      stat-view-servlet:
        # 是否启用 StatViewServlet(监控页面)
        enabled: true
        # 访问路径
        url-pattern: /druid/*
        # 登录用户名
        login-username: admin
        # 登录密码
        login-password: admin
        # 允许访问的 IP 地址(空表示允许所有)
        allow: ""
        # 拒绝访问的 IP 地址
        deny: ""
        # 是否禁用重置按钮
        reset-enable: true
      # WebStatFilter 配置
      web-stat-filter:
        # 是否启用 WebStatFilter
        enabled: true
        # 拦截路径
        url-pattern: /*
        # 排除路径
        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
        # session 统计最大数量
        session-stat-max-count: 1000
        # 是否启用 session 统计
        session-stat-enable: true
        # principalSessionName 配置
        principal-session-name: username
        # profileEnable 配置
        profile-enable: true
      # 配置 StatFilter
      filter:
        stat:
          # 是否启用 StatFilter
          enabled: true
          # 慢 SQL 记录(毫秒)
          log-slow-sql: true
          slow-sql-millis: 5000
          # 合并 SQL
          merge-sql: true
        wall:
          # 是否启用 WallFilter(防火墙)
          enabled: true
          # 配置允许的 SQL 语句
          config:
            multi-statement-allow: true
        slf4j:
          # 是否启用 Slf4jFilter
          enabled: true
          # 是否开启日志
          statement-log-enabled: true
          # 是否开启结果集日志
          result-set-log-enabled: true
          # 是否开启连接日志
          connection-log-enabled: true

3.3 配置安全访问

编辑 SecurityConfiguration.java,允许访问 Druid 监控页面:

java
@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/druid/**").permitAll()
                .anyRequest().authenticated()
            );
        return http.build();
    }
}

4. 访问监控页面

4.1 访问 Druid 监控页面

启动应用后,在浏览器中访问:

http://your-server-ip:48080/druid

输入用户名和密码(默认:admin/admin)登录。

4.2 监控页面功能

Druid 监控页面包含以下功能:

  • 数据源:查看数据源信息、连接池状态
  • SQL 监控:查看 SQL 执行情况、慢查询
  • SQL 防火墙:查看 SQL 防火墙拦截情况
  • Web 应用:查看 Web 应用请求统计
  • URI 监控:查看 URI 访问统计
  • Session 监控:查看 Session 统计信息
  • Spring 监控:查看 Spring Bean 方法调用统计

5. 监控指标说明

5.1 数据源监控

  • 连接池信息

    • initial-size:初始连接数
    • min-idle:最小空闲连接数
    • max-active:最大活跃连接数
    • current-active:当前活跃连接数
    • current-idle:当前空闲连接数
    • max-wait:获取连接最大等待时间
  • 连接使用情况

    • activeCount:活跃连接数
    • activePeak:活跃连接峰值
    • activePeakTime:活跃连接峰值时间
    • poolingCount:池中连接数
    • poolingPeak:池中连接峰值
    • poolingPeakTime:池中连接峰值时间
  • 连接等待情况

    • waitThreadCount:等待线程数
    • notEmptyWaitCount:等待连接次数
    • notEmptyWaitNanos:等待连接总时间
    • notEmptyWaitPeak:等待连接峰值
    • notEmptyWaitPeakTime:等待连接峰值时间

5.2 SQL 监控

  • SQL 执行统计

    • executeCount:执行次数
    • executeMillisTotal:执行总时间
    • executeMillisMax:执行最大时间
    • executeMillisMin:执行最小时间
    • executeMillisAvg:执行平均时间
    • executeErrorCount:执行错误次数
    • executeErrorLast:最后执行错误时间
  • SQL 事务统计

    • commitCount:提交次数
    • rollbackCount:回滚次数
    • fetchRowCount:获取行数
    • updateCount:更新行数
  • SQL 慢查询

    • slowSqlMillis:慢 SQL 阈值(毫秒)
    • slowSqlCount:慢 SQL 次数
    • slowSqlMillisMax:慢 SQL 最大执行时间

5.3 Web 应用监控

  • 请求统计

    • RequestCount:请求总数
    • RequestTimeMillisTotal:请求总时间
    • RequestTimeMillisMax:请求最大时间
    • RequestTimeMillisMin:请求最小时间
    • RequestTimeMillisAvg:请求平均时间
  • JDBC 统计

    • JdbcExecuteCount:JDBC 执行次数
    • JdbcExecuteTimeMillis:JDBC 执行时间
    • JdbcCommitCount:JDBC 提交次数
    • JdbcRollbackCount:JDBC 回滚次数
  • 并发统计

    • ConcurrentMax:最大并发数
    • RunningCount:当前运行数
    • JdbcRunningCount:当前 JDBC 运行数

6. Prometheus 集成

6.1 安装 MySQL Exporter

MySQL Exporter 用于将 MySQL 指标导出到 Prometheus。

bash
# 拉取镜像
docker pull prom/mysqld-exporter

# 运行容器
docker run -d \
  --name mysqld-exporter \
  -p 9104:9104 \
  -e DATA_SOURCE_NAME="root:password@(192.168.1.10:3306)/" \
  --restart=always \
  prom/mysqld-exporter

6.2 配置 Prometheus 采集 MySQL 指标

编辑 prometheus.yml

yaml
scrape_configs:
  - job_name: 'mysql'
    static_configs:
      - targets: ['192.168.1.10:9104']
        labels:
          instance: 'mysql-1'
          env: 'dev'

6.3 MySQL 监控指标

  • 连接指标

    • mysql_global_status_threads_connected:当前连接数
    • mysql_global_status_max_used_connections:最大连接数
    • mysql_global_status_threads_running:运行中的线程数
  • 查询指标

    • mysql_global_status_questions:查询总数
    • mysql_global_status_queries:查询速率
    • mysql_global_status_slow_queries:慢查询数
  • 缓冲池指标

    • mysql_global_status_innodb_buffer_pool_reads:缓冲池读取次数
    • mysql_global_status_innodb_buffer_pool_read_requests:缓冲池读取请求
    • mysql_global_status_innodb_buffer_pool_size:缓冲池大小
  • 复制指标

    • mysql_slave_status_seconds_behind_master:从库延迟时间

7. Grafana 仪表板

7.1 导入 MySQL 仪表板

  1. 登录 Grafana
  2. 进入"Dashboards" -> "Import"
  3. 输入仪表板 ID:7362(MySQL Overview)
  4. 点击"Load"
  5. 选择 Prometheus 数据源
  6. 点击"Import"

7.2 自定义 MySQL 仪表板

创建自定义仪表板,监控以下指标:

  • 连接监控

    • 当前连接数
    • 最大连接数
    • 连接使用率
  • 查询监控

    • 查询速率
    • 慢查询数
    • 查询响应时间
  • 缓冲池监控

    • 缓冲池大小
    • 缓冲池命中率
    • 缓冲池读取速率
  • 复制监控

    • 从库延迟
    • 复制状态

8. 告警配置

8.1 配置 MySQL 告警规则

创建 /data/prometheus/rules/mysql.yml

yaml
groups:
  - name: mysql_alerts
    interval: 30s
    rules:
      # MySQL 宕机告警
      - alert: MySQLDown
        expr: mysql_up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "MySQL 实例 {{ $labels.instance }} 宕机"
          description: "MySQL 实例 {{ $labels.instance }} 已经宕机超过 1 分钟"

      # 高连接数告警
      - alert: MySQLHighConnections
        expr: (mysql_global_status_threads_connected / mysql_global_variables_max_connections) * 100 > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "MySQL 实例 {{ $labels.instance }} 连接数过高"
          description: "MySQL 实例 {{ $labels.instance }} 连接数超过 80%,当前值为 {{ $value }}%"

      # 慢查询告警
      - alert: MySQLSlowQueries
        expr: rate(mysql_global_status_slow_queries[5m]) > 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "MySQL 实例 {{ $labels.instance }} 慢查询过多"
          description: "MySQL 实例 {{ $labels.instance }} 慢查询速率超过 10 次/分钟,当前值为 {{ $value }}"

      # 缓冲池命中率告警
      - alert: MySQLLowBufferPoolHitRate
        expr: (1 - (rate(mysql_global_status_innodb_buffer_pool_reads[5m]) / rate(mysql_global_status_innodb_buffer_pool_read_requests[5m]))) * 100 < 95
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "MySQL 实例 {{ $labels.instance }} 缓冲池命中率过低"
          description: "MySQL 实例 {{ $labels.instance }} 缓冲池命中率低于 95%,当前值为 {{ $value }}%"

      # 从库延迟告警
      - alert: MySQLReplicationLag
        expr: mysql_slave_status_seconds_behind_master > 60
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "MySQL 从库 {{ $labels.instance }} 延迟过高"
          description: "MySQL 从库 {{ $labels.instance }} 延迟超过 60 秒,当前值为 {{ $value }} 秒"

9. 慢查询分析

9.1 开启慢查询日志

编辑 MySQL 配置文件 my.cnf

ini
[mysqld]
# 开启慢查询日志
slow_query_log = 1
# 慢查询日志文件路径
slow_query_log_file = /var/log/mysql/slow-query.log
# 慢查询阈值(秒)
long_query_time = 2
# 记录未使用索引的查询
log_queries_not_using_indexes = 1
# 记录管理语句
log_slow_admin_statements = 1

9.2 分析慢查询

使用 mysqldumpslow 工具分析慢查询:

bash
# 查看最慢的 10 条 SQL
mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log

# 查看访问次数最多的 10 条 SQL
mysqldumpslow -s c -t 10 /var/log/mysql/slow-query.log

# 查看返回记录数最多的 10 条 SQL
mysqldumpslow -s r -t 10 /var/log/mysql/slow-query.log

9.3 优化慢查询

根据慢查询日志,分析并优化 SQL 语句:

  1. 添加合适的索引
  2. 优化 SQL 语句
  3. 优化表结构
  4. 使用缓存

10. 性能优化

10.1 连接池优化

yaml
spring:
  datasource:
    druid:
      # 根据实际情况调整连接池大小
      initial-size: 10
      min-idle: 20
      max-active: 50
      # 调整获取连接等待时间
      max-wait: 10000
      # 调整连接检测间隔
      time-between-eviction-runs-millis: 60000
      # 调整连接最小生存时间
      min-evictable-idle-time-millis: 300000

10.2 SQL 优化

  • 使用索引
  • 避免 SELECT *
  • 避免 OR 条件
  • 使用 LIMIT 分页
  • 使用 JOIN 替代子查询
  • 使用 EXPLAIN 分析 SQL

10.3 MySQL 优化

ini
[mysqld]
# 调整缓冲池大小(建议设置为物理内存的 70-80%)
innodb_buffer_pool_size = 4G

# 调整缓冲池实例数
innodb_buffer_pool_instances = 4

# 调整日志文件大小
innodb_log_file_size = 512M

# 调整日志缓冲区大小
innodb_log_buffer_size = 16M

# 调整最大连接数
max_connections = 500

# 调整查询缓存
query_cache_size = 0
query_cache_type = 0

11. 常见问题

11.1 Druid 监控页面无法访问

问题:无法访问 Druid 监控页面

解决方案

  1. 检查 stat-view-servlet.enabled 是否为 true
  2. 检查安全配置是否允许访问 /druid/**
  3. 检查防火墙是否开放端口
  4. 检查用户名密码是否正确

11.2 连接池耗尽

问题:连接池耗尽,无法获取连接

解决方案

  1. 增加 max-active 连接数
  2. 检查是否有连接泄漏
  3. 优化 SQL 执行时间
  4. 检查是否有长事务

11.3 慢查询过多

问题:慢查询数量过多

解决方案

  1. 开启慢查询日志
  2. 分析慢查询日志
  3. 优化 SQL 语句
  4. 添加合适的索引
  5. 优化表结构

11.4 MySQL Exporter 无法采集指标

问题:MySQL Exporter 无法采集指标

解决方案

  1. 检查 MySQL 是否运行
  2. 检查连接配置是否正确
  3. 检查用户权限是否足够
  4. 检查网络连接是否正常

12. 注意事项

  1. 连接池配置:根据实际情况调整连接池大小
  2. 慢查询监控:定期分析慢查询日志
  3. 索引优化:合理使用索引提高查询性能
  4. 告警配置:配置合理的告警规则
  5. 日志管理:定期清理日志文件
  6. 安全配置:限制监控页面访问
  7. 备份策略:定期备份数据库
  8. 性能监控:持续监控数据库性能

13. 相关文档