MySQLのバイナリログを自動的に圧縮して退避する
問題
MySQLのバイナリログがそこそこの容量になるので、圧縮して退避したい。
ただ、ログ調査などのために一定期間は消さずに残したい。
できますか。
答え
バイナリログは、/var/lib/mysql などのMySQLのデータディレクトリの中に、以下のような感じで保存されている。
/MySQLデータディレクトリ/mysql-bin.000123 /MySQLデータディレクトリ/mysql-bin.000124 /MySQLデータディレクトリ/mysql-bin.000125 ... ... /MySQLデータディレクトリ/mysql-bin.000151 /MySQLデータディレクトリ/mysql-bin.000152 /MySQLデータディレクトリ/mysql-bin.index
連番の一番大きいファイルが現在書き込み中のファイルで、これはそのままにしておく。
連番の小さい方のファイルはローテーションしたファイルで、これを圧縮したい。
連番の一番大きいファイルだけは圧縮しないでそのままにしておいて、
連番の小さい方のファイルは圧縮したい。
gzipコマンドで圧縮すると、元のファイルはなくなってしまうのだが、
それではMySQLサーバー側の管理上、不整合が起きる。
元のファイルは残したまま別のディレクトリに圧縮ファイルを作り、
古いログの削除は PURGE BINARY LOGS でおこないたい。
一度に複数の処理を行おうとするとコマンドが複雑になるので、
なるべく単純な仕事に分けて考えると、
以下の3つができればよいはず。
・連番最大以外のログファイルについて、圧縮ファイルが未作成のとき、圧縮ファイルを作成
・圧縮ファイルが作成されているログファイルの削除
・一定期間経過した圧縮ファイルの削除
コマンドにするとこうなった。
・圧縮
/bin/find /MySQLデータディレクトリ -name 'mysql-bin.[0-9]*' | sort | sed '$d' | xargs -I {} sh -c 'i={} ; [ ! -f /退避先/${i##*/}.gz ] && gzip -c {} > /退避先/${i##*/}.gz && /bin/touch -r {} /退避先/${i##*/}.gz'
・圧縮後の削除
/bin/find /MySQLデータディレクトリ -name 'mysql-bin.[0-9]*' | sort | xargs -I {} sh -c 'i={} ; [ ! -f /退避先/${i##*/}.gz ] && mysql -e "PURGE MASTER LOGS TO '\''${i##*/}'\'';" && exit 255'
・古い圧縮ファイルの削除
/usr/sbin/tmpwatch -m 720 /退避先
先頭に 0 0 * * * など付けて、cronに設定するとよい。
重複起動は避けたいが、cronで実行するので考慮していない。
メモ
・sed ‘$d’ は、最後の行を削除してくれる。
・xargs は、呼び出したコマンドがステータス255で終了するとxargsの処理を即座に終了してくれるのを利用して、まだ圧縮ファイルが作られていない最初のバイナリログの名前で1回だけ PURGE して終了するようにしている。圧縮処理中にバイナリログのローテーションが進んでも大丈夫。
・touch で圧縮ファイルのタイムスタンプを元のバイナリログと同じにしておいた方が、いつのログなのかわかるし、tmpwatchで削除するときにも使える。
コメント