TLDR

  • 問題:log 檔案過大,將剩餘空間占滿,導致服務異常
  • 原因:MySQL 被設定開啟 mysql-gen.log,且未設定定時清理
  • 調查方法:檢查 MySQL 設定與空間占用狀況
  • 解決方案:使用 logrotate 設定定時清理

情境

正式環境的 MySQL Slave 會定期製作分析報告並郵寄給相關人員。

收到通知已有一段時間沒收到報告,登入主機嘗試手動寄出,卻顯示因空間不足,寄送失敗。

資料庫的檔案未有異常,且資料庫位於外接硬碟,剩餘空間非常大。

調查過程

檢查 Linux 空間狀況

首先用 df -h 檢查空間狀況,卻發現剩餘空間非常少。

1
df -h
1
2
3
4
5
6
7
8
# 結果示意
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   50G     0 100% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           3.9G  1.2M  3.9G   1% /run
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/sdb1       100G   60G   35G  64% /data
/dev/sdc1       200G  150G   50G  75% /backup

檢查根目錄下大文件夾

可用以下命令查看根目錄下佔用空間最大的前 20 個文件夾。

我遇到的問題出在 /var/log/mysql/mysql-gen.log

1
du -ahx / | sort -rh | head -n 20
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 結果示意
50G     /
45G     /var/log/mysql/mysql-gen.log
3G      /var/log
1.2G    /home/user/videos
1G      /usr/lib
800M    /usr/share
500M    /var/cache
300M    /tmp
# ...

分析原因

大約6個月前,客戶請我們將 MySQL 的 general_log 開啟,並透過 rsyslog 轉拋。

同事不清楚 general_log 是什麼,也不知道 rsyslog 是即時轉拋,因此沒有設定定時清除。

簡單來說 general_log 是 MySQL 的詳細 log,會記錄所有查詢,因此會產生大量的 log。

短短6個月,就直接將剩餘空間占滿。

解決方案

步驟 1: 使用 logrotate 定期清除日誌文件

/etc/logrotate.d/mysql 中添加以下設定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/var/log/mysql/mysql-gen.log {
    # 每天執行一次日誌輪換
    daily
    # 保留最近 7 份日誌
    rotate 7
    # 忽略不存在的文件
    missingok
    # 如果日誌文件為空,則不進行輪換
    notifempty
    # 壓縮日誌文件
    compress
    delaycompress
    # 創建日誌文件,640 檔案權限,MySQL 使用者擁有
    create 640 MySQL MySQL
    # 在輪換後執行命令
    postrotate
        # 使用 MySQLadmin 命令刷新 MySQL 日誌,確保 MySQL 開始使用新的日誌文件
        /usr/bin/mysqladmin flush-logs
    endscript
}

步驟 2: 強制執行新設定

1
2
3
# -f 強制執行
# -v 顯示詳細資訊
logrotate -fv /etc/logrotate.d/mysql

步驟 3: 清理現有的大檔案日誌

移除 rotate 出的 mysql-gen.log.1 文件,釋放空間。

步驟 4: 驗證結果

再次使用 df -h 查看硬碟使用情況,確認根目錄空間已釋放。

結論

  1. 若 Linux 運作異常,可檢查硬體及記憶體使用狀況。
  2. 使用 logrotate 定時清理日誌,避免日誌過大,占用空間。
  3. 在做任何設定或指令前,必須先了解指令的用途及可能產生的後果。