hyperf 框架中按日期分割 MySQL 慢查询日志

在使用 MySQL 数据库时,开启慢查询日志可以帮助我们识别和优化性能较差的查询语句。然而,随着时间的推移,慢查询日志文件会变得非常大,难以管理和分析。为了更好地组织和分析慢查询日志,我们可以将日志文件按日期进行分割。说明一下我的环境是 window for docker

配置 MySQL 慢查询日志

1. 使用 docker-compose.yml 配置慢日志

  mysql:
    container_name: mysql
    environment:
      - "TZ=Asia/Shanghai"
      - MYSQL_ROOT_PASSWORD=12345678
      - "explicit_defaults_for_timestamp=true"
      - "lower_case_table_names=1"
    image: mysql:8.0
    restart: always
    volumes:
      #持久化
      - mysql-data:/var/lib/mysql
      # 将本地的初始化脚本目录挂载到容器中
      - ./docker/mysql/backup.sql:/docker-entrypoint-initdb.d/backup.sql
      # 挂载数据库日志目录 也可以就挂载到 runtime 目录下
      - ./docker/mysql/logs:/var/lib/mysql/logs
    ports:
        - "3306:3306"  # 确保端口映射允许宿主机上的应用连接到 MySQL
    command: "--default-authentication-plugin=mysql_native_password --max_connections=200 --slow_query_log=1 --slow_query_log_file=/var/lib/mysql/logs/slow_query.log --long_query_time=1 --innodb-buffer-pool-size=1G"
    # max_connections 最大连接数
    # slow_query_log 开始慢查询日志
    # slow_query_log_file 慢查询日志路径
    # long_query_time 慢查询阈值"

2.1 使用 dockerFile 配置慢日志

  mysql:
    container_name: mysql
    environment:
      - "TZ=Asia/Shanghai"
      - MYSQL_ROOT_PASSWORD=12345678
      - "explicit_defaults_for_timestamp=true"
      - "lower_case_table_names=1"
    build:
      context: ./docker/mysql
      dockerfile: Dockerfile
    restart: always
    volumes: #持久化
      - mysql-data:/var/lib/mysql
      # 将本地的初始化脚本目录挂载到容器中
      - ./docker/mysql/backup.sql:/docker-entrypoint-initdb.d/backup.sql
      # 挂载数据库日志目录 也可以就挂载到 runtime 目录下
      - ./docker/mysql/logs:/var/mysql/logs
      # 挂载自定义配置文件目录
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
    ports:
        - "3306:3306"  # 确保端口映射允许宿主机上的应用连接到 MySQL
    command: "--default-authentication-plugin=mysql_native_password --max_connections=200 --innodb-buffer-pool-size=1G"
    # max_connections 最大连接数
    # innodb-buffer-pool-size 运行内存

2.2 配置 Dockerfile 文件

FROM mysql:8.0

# 这里修改为你自己的 slow-query-log.cnf 文件路径
COPY ./conf.d/slow-query-log.cnf /etc/mysql/conf.d/
# 修改文件权限 不然MySQL 报错:mysql: [Warning] World-writable config file '/etc/mysql/conf.d/slow-query-log.cnf' is ignored.
# 这个警告表示 MySQL 配置文件 /etc/mysql/conf.d/slow-query-log.cnf 的权限设置不正确,MySQL 出于安全考虑而忽略了该配置文件。
RUN chmod 644 /etc/mysql/conf.d/slow-query-log.cnf
export 3306

2.3 配置 slow-query-log.cnf 文件

[mysqld]
# 启用慢查询日志
slow_query_log = 1

# 慢查询日志文件的路径和名称
slow_query_log_file = /var/lib/mysql/logs/slow_query.log

# 慢查询的阈值,单位为秒
long_query_time = 1

#记录未使用索引的查询
log_queries_not_using_indexes = 1

# 限制未使用索引的查询的记录频率
log_throttle_queries_not_using_indexes = 5

# 记录慢速管理语句
log_slow_admin_statements = 1

# 记录慢速从库语句
log_slow_slave_statements = 1

# 日志输出方式,设置为 FILE 表示输出到文件
log_output = FILE

# 日志文件的保留天数,超过该天数的日志文件将被自动删除
expire_logs_days = 30

现在我们需要重启容器使配置生效

在宿主机上执行以下命令:

  • docker-compose down
  • docker-compose up -d

为了查看配置是否生效 我们进入到 MySQL 容器中

1. 进入容器的命令行:
docker exec -it mysql /bin/bash
连接到 MySQL:
mysql -u root -p
检查慢查询日志相关的变量:
SHOW VARIABLES LIKE  'slow_query%';  SHOW VARIABLES LIKE  'log_output';
  • 确保 slow_query_log 的值为 ONslow_query_log_file 的值为配置文件中指定的路径和名称,log_output 的值为 FILE

手动触发一个慢查询:

  • 在 MySQL 命令行中执行一个超过 long_query_time 设置的查询,例如:
    SELECT SLEEP(2);
  • 检查 /var/lib/mysql/logs 目录下是否生成了按日期命名的慢查询日志文件。

3 创建定时任务

app/Crontab 目录下创建一个新的定时任务类 RotateSlowQueryLog:

use Hyperf\Crontab\Annotation\Crontab;
use Hyperf\DbConnection\Db;

#[Crontab(name: "rotateSlowQueryLog", rule: "0 0 * * *", callback: "execute", memo: "每天凌晨 0 点执行按日期切割 MySQL 慢日志文件")]
class RotateSlowQueryLog
{
    /**
     * 按日期切割 MySQL 慢日志文件
     * @return void
     * @throws \Exception
     */
    public function execute(): void
    {
        $path = BASE_PATH . '/docker/mysql/logs';

        $logFile = "$path/slow_query.log";
        $rotatedLogFile = "$path/slow_query_" . date('Ymd') . '.log';

        if (!file_exists($path)){
            throw new \Exception("No slow query log file found: $logFile");
        }
        //重命名日志文件
        rename($logFile, $rotatedLogFile);

        //切割日志文件时,我们需要确保 MySQL 能够继续写入新的日志文件。为了解决这个问题,我们可以在重命名日志文件后,通知 MySQL 重新打开日志文件。
        Db::statement("SET GLOBAL slow_query_log = 'OFF'");
        Db::statement("SET GLOBAL slow_query_log = 'ON'");
    }
}

配置完成 :+1: :thumbsup:

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!