[技術ブログVol.14] RDSのMySQLログをファイルでアーカイブする

前回は、AWSのRDSサービスでのリードレプリカ機能についてご紹介しましたが、今回も同じくRDSサービス(ここではAmazon RDS for MySQLのみが対象)のログ機能に関するソリューションをご紹介します。

さてこのログ機能、Parameter Groupsにて設定することでスロークエリログやジェネラルログを取得することが可能となるのですが、少々癖のある仕様となっており、主に以下のような点が挙げられます。

  • WEBブラウザ上でいちいち見なければいけない
  • 一時間ごとにローテートされる
  • 1時間でローテートされ、24時間しか保持されないため、数日前のログが見たい時に詰む
  • 1時間でファイルが切れるので、調査しづらい

こういった不便により、「もうEC2上でMySQL動かしちゃえばいいや」と判断した方がいらっしゃるのではないでしょうか。
ログ至上主義、CUI至上主義の私にとってはこれがいささか不便であったため、今回ご紹介するスクリプトによって以下の環境を実現しました。

  • 別サーバ(連携させているEC2サーバ等)にファイルとしてログを保存する
    • 調査時にサーバ内だけで完結でき、テキスト編集もらくらく
  • 複数日分をアーカイブする
  • 日次処理で自動取得させる
  • 一日分を一ファイルで

この環境を実現してからはプライベートも絶好調で、宝くじが当たる夢も見ることができました。
私が暇つぶしで作成したものなので、皆様もご自由に自己責任でご利用下さい。

概要

本スクリプトは、RDSのコマンド操作を実現するAmazon RDS Command Line Toolkit(以下RDS CLI)を必要とします。そのため、今回ここではまずRDS CLIの導入方法からご説明します。

前提として、今回の実施環境はEC2(CentOS6)とRDSを連携させており、RDSのパラメータグループにて各ログをファイル出力する設定を行っています。

RDS CLIでできることは?

基本的には、WEBコンソールでできることと変わりません。
例えば...

  • Option Groups等の追加
  • DB操作(インスタンスやリードレプリカ追加/削除、起動/停止、リストア、パラメータグループ編集、Snapshot操作等)
  • DB情報の表示(インスタンス、ログ、パラメータグループ、Snapshot等)
  • ログのダウンロード

これらがWEBでポチポチせずに、コマンドにて実行できます。

とりわけ、今回ご紹介するログ関連の操作では、以下の操作が行えます。(主要なもののみ)

  • 取得するログの変更
    • rds-modify-db-parameter-group
  • 取得しているログリストの表示
    • rds-describe-db-log-files
  • ログ内容の表示
    • rds-download-db-logfile
  • ログのリアルタイム表示
    • rds-watch-db-logfile

まずは、JDKのインストール

RDS CLIは、Javaの実行環境を必要とします。
YUMで入るOpenJDKで良いので、簡単です。

[root@aws ~]# yum search jdk
-----------------------------------------------------------
================================== N/S Matched: jdk ==================================
java-1.6.0-openjdk.x86_64 : OpenJDK Runtime Environment
java-1.6.0-openjdk-demo.x86_64 : OpenJDK Demos
java-1.6.0-openjdk-devel.x86_64 : OpenJDK Development Environment
java-1.6.0-openjdk-javadoc.x86_64 : OpenJDK API Documentation
java-1.6.0-openjdk-src.x86_64 : OpenJDK Source Bundle
java-1.7.0-openjdk.x86_64 : OpenJDK Runtime Environment
java-1.7.0-openjdk-demo.x86_64 : OpenJDK Demos
java-1.7.0-openjdk-devel.x86_64 : OpenJDK Development Environment
java-1.7.0-openjdk-javadoc.noarch : OpenJDK API Documentation
java-1.7.0-openjdk-src.x86_64 : OpenJDK Source Bundle
ldapjdk-javadoc.x86_64 : Javadoc for ldapjdk
icedtea-web.x86_64 : Additional Java components for OpenJDK - Java browser plug-in and
: Web Start implementation
ldapjdk.x86_64 : The Mozilla LDAP Java SDK

Name and summary matches only, use "search all" for everything.
-----------------------------------------------------------

java-1.7.0-openjdk-devel.x86_64をインストールします。

[root@aws ~]# yum install java-1.7.0-openjdk-devel.x86_64

RDS CLIのインストール

まずは、プログラムをダウンロードします。

[root@aws ~]# wget http://s3.amazonaws.com/rds-downloads/RDSCli.zip
[root@aws ~]# unzip RDSCli.zip

# Rootのみ実行できるよう調整
[root@aws ~]# mkdir /root/TOOLS
[root@aws ~]# mv RDSCli-1.15.001/ /root/TOOLS/

Security Credentialの情報を設定します。

[root@aws ~]# vi /root/TOOLS/RDSCli-1.15.001/credential-file-path.template
------------------------------------------------------------
# Enter the AWS Keys without the < or >
# These can be found at http://aws.amazon.com under Account->Security Credentials
AWSAccessKeyId="アクセスキーを入力"
AWSSecretKey="シークレットキーを入力"
------------------------------------------------------------

環境変数を設定します。

[root@aws ~]# export AWS_RDS_HOME="/root/TOOLS/RDSCli-1.15.001"
[root@aws ~]# export PATH=$PATH:${AWS_RDS_HOME}/bin
[root@aws ~]# export AWS_CREDENTIAL_FILE="${AWS_RDS_HOME}/credential-file-path.template"
[root@aws ~]# export EC2_REGION="ap-northeast-1"

JDK側の環境変数設定も必要です。

# JAVAの動作領域を特定
[root@aws ~]# readlink $(readlink $(which java))
------------------------------------------------------------
/usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
------------------------------------------------------------

[root@aws ~]# export JAVA_HOME="/usr/lib/jvm/jre-1.7.0-openjdk.x86_64"

これでインストールは完了です。
実際に動くかどうか、テストしてみましょう。

[root@aws ~]# rds-version
--------------------------------------------
Relational Database Service CLI version 1.15.001 (API 2013-09-09)
--------------------------------------------

正しく動く事が確認できたので、rootの.bash_profileに設定しておきましょう。

[root@aws ~]# vi /root/.bash_profile
-------------------------------------------------------
##For AWS CLI

#For RDS CLI
export AWS_RDS_HOME="/root/TOOLS/RDSCli-1.15.001/"
export PATH=$PATH:${AWS_RDS_HOME}/bin
export EC2_REGION="ap-northeast-1"
export AWS_CREDENTIAL_FILE=${AWS_RDS_HOME}/credential-file-path.template
export JAVA_HOME="/usr/lib/jvm/jre-1.7.0-openjdk.x86_64"
-------------------------------------------------------

MySQLログを一括ダウンロードするシェルスクリプト

さて、RDS CLIの導入が完了しましたので、早速RDSのMySQLログをEC2のサーバに一括ダウンロードするスクリプトをご紹介したいと思います。
ですが、まずはデバッグを兼ねたテストスクリプトを実行してみましょう。

[root@aws ~]# vi /root/script/rds-getlog.sh
-------------------------------------------------------
#!/bin/sh

# この後でスペースを含む引数を指定するため、IFSを改行のみに指定
PRE_IFS=$IFS
IFS=$'n'


# 一時ファイルの作成
rds-describe-db-log-files --db-instance-identifier mydb > /root/script/tmp.logfiles


# ルーチン

## ログ取得ルーチン
get_log()
{
for GETINFO in $* ; do
GETNAME=echo $GETINFO |awk '{print $2}'
echo "###########$GETNAME###########"

### ログ取得
rds-download-db-logfile --db-instance-identifier mydb --log-file-name $GETNAME > /root/script/$GETNAME

### タイムスタンプ付け
LOGDATE=echo $GETINFO |awk '{print $3,$4,$5,$6,$7,$8}'
touch -d "$LOGDATE" /root/script/$GETNAME
done
}


# 各ログ指定フィールド
SLOW=cat /root/script/tmp.logfiles |grep slowquery
ERROR=cat /root/script/tmp.logfiles |grep error
GENERAL=cat /root/script/tmp.logfiles |grep general

get_log $SLOW
get_log $ERROR
get_log $GENERAL


# IFSの初期化
IFS=$PRE_IFS


# 一時ファイルの削除
rm -f /root/script/tmp.logfiles


# ログマージ
TARGET_SLOW=ls -1tr /root/script/slowquery/*
TARGET_ERROR=ls -1tr /root/script/error/*
TARGET_GENERAL=ls -1tr /root/script/general/*
SLOWQUERY="/var/log/mysql/slowquery.log"
ERRORRUNNING="/var/log/mysql/error-running.log"
GENERAL="/var/log/mysql/general.log"

cat $TARGET_SLOW > $SLOWQUERY
cat $TARGET_ERROR > $ERRORRUNNING
cat $TARGET_GENERAL > $GENERAL
-------------------------------------------------------

このスクリプトを適当なディレクトリに設置し、実行権限をつけて実行してください。
テストスクリプトではechoで現在取得中のログファイル名を表示するようにしているので、以下の様にログファイル名がどんどん表示され、全てが表示されていることをまず確認します。

[root@aws ~]# chmod +x /root/script/rds-getlog.sh
[root@aws ~]# /root/script/rds-getlog.sh
-------------------------------------------------------
###########slowquery/mysql-slowquery.log###########
###########slowquery/mysql-slowquery.log.0###########
###########slowquery/mysql-slowquery.log.1###########
###########slowquery/mysql-slowquery.log.10###########
###########slowquery/mysql-slowquery.log.11###########
###########slowquery/mysql-slowquery.log.12###########
###########slowquery/mysql-slowquery.log.13###########
...
-------------------------------------------------------

その後、/var/log/mysql/配下に作成されたログファイルを確認し、正しく時系列に沿ったログが取れていることを確認します。
問題がなければ、cronに設置する用のスクリプトに変更しましょう。

[root@aws ~]# vi /root/script/rds-getlog.sh
-------------------------------------------------------
#!/bin/sh

# この後でスペースを含む引数を指定するため、IFSを改行のみに指定
PRE_IFS=$IFS
IFS=$'n'


# cron実行用にパスを読ませる
source /root/.bash_profile


# 一時ファイルの作成
rds-describe-db-log-files --db-instance-identifier mydb > /root/script/tmp.logfiles


# ルーチン

## ログ取得ルーチン
get_log()
{
for GETINFO in $* ; do
GETNAME=echo $GETINFO |awk '{print $2}'

### ログ取得
rds-download-db-logfile --db-instance-identifier mydb --log-file-name $GETNAME > /root/script/$GETNAME

### タイムスタンプ付け
LOGDATE=echo $GETINFO |awk '{print $3,$4,$5,$6,$7,$8}'
touch -d "$LOGDATE" /root/script/$GETNAME
done
}


# 各ログ指定フィールド
SLOW=cat /root/script/tmp.logfiles |grep slowquery
ERROR=cat /root/script/tmp.logfiles |grep error
GENERAL=cat /root/script/tmp.logfiles |grep general

get_log $SLOW
get_log $ERROR
get_log $GENERAL


# IFSの初期化
IFS=$PRE_IFS


# 一時ファイル削除
rm -f /root/script/tmp.logfiles


# ログマージ
TARGET_SLOW=ls -1tr /root/script/slowquery/*
TARGET_ERROR=ls -1tr /root/script/error/*
TARGET_GENERAL=ls -1tr /root/script/general/*
DATE="date '+%Y%m%d' --date '1 day ago'"
SLOWQUERY="/var/log/mysql/slowquery.log"
ERROR="/var/log/mysql/error.log"
GENERAL="/var/log/mysql/general.log"

cat $TARGET_SLOW > $SLOWQUERY
cat $TARGET_ERROR > $ERROR
cat $TARGET_GENERAL > $GENERAL

mv ${SLOWQUERY} ${SLOWQUERY}_${DATE}
mv ${ERROR} ${ERROR}_${DATE}
mv ${GENERAL} ${GENERAL}_${DATE}

gzip ${SLOWQUERY}_${DATE}
gzip ${ERROR}_${DATE}
gzip ${GENERAL}_${DATE}


# 古いログの削除
RMTARGET="date '+%Y%m' --date '3 day ago'"
rm -rf ${SLOWQUERY}_${RMTARGET}.gz
rm -rf ${ERROR}_${RMTARGET}.gz
rm -rf ${GENERAL}_${RMTARGET}.gz
-------------------------------------------------------

上記スクリプトをcronに仕込めば、一日一回、一日分のMySQLログをアーカイブする環境が整います。
正常に動作しない場合は、以下の様にcron実行時のエラー出力をファイルに渡すことで、確認することができます。

[root@aws ~]# crontab -e
-------------------------------------------------------
30 0 * * * /root/script/rds-getlog.sh 2>/root/script/error.log
-------------------------------------------------------

スクリプトの仕様について

動きとしては、以下を行っています。

  1. 取得中のログファイルに関する情報を取得し、一時データとして扱う
  2. 一時データから各ログ(スロークエリログやエラーログ)の情報のみを抜き出し、ログ取得ルーチンに渡す
  3. ログ取得ルーチンの引数で指定されたログを、ローテートされたものを含め全てダウンロード
  4. ダウンロードしたログをマージし、圧縮
  5. 古いログを削除

本スクリプトのメンテナンス時等に役立つであろう情報をまとめます。

  • 取得するログを選択したい場合
    • 各ログ指定フィールドを編集することで可能です
    • 例えば、スロークエリログのみを取得したい場合、get_logで渡す引数を$SLOWのみにするといった感じです
    • 変数等は、適宜コメントアウトなりしてください
  • ログの保存数を変えたい
    • 上記のスクリプトでは二日分しか残らない設定となっていますが、RMTARGETを変更することで可能です
    • 例えば"date '+%Y%m' --date '6 month ago'"と設定すると、六か月分を保存することができます

注意事項

ダウンロードしたログの設置ディレクトリと、マージしたログの設置ディレクトリは別にして下さい。
マージする際に、圧縮済みの古いログをcatしようとするため、マージされたログにエラーが混ざります。

技術ブログ中の人
更新予定は、9月中旬頃です。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA