#1. まえがき
私はWordPressを使ってたくさんのサイトを運用しています。
しかし、各サイトの連携をする手段が、データベースサーバーからデータをエクスポート・インポートのバッチ処理だと仕組みが大変です。
そこで、数年前に話題になり、今でもモバゲーなどで基幹システムでも採用しているQ4Mを使えばうまくいくかと考え、インストールの方法と流れにめどができたので、書くことにしました。
#2.考え方
Q4Mは、MySQLにプラグインとして実装するメッセージキューです。
Q4M (Queue for MySQL) は GPL のもとにライセンスされるメッセージキューで、MySQLのプラグイン可能なストレージエンジンとして動作し、堅牢、高速、柔軟なように設計されています。既にプロダクションの品質であり、幾つかのwebサービスで利用されています(Q4Mのユーザを見てください)。
出典:http://mogile.web.fc2.com/q4m/
既存のサーバーにMySQLプラグインとして追加する形ができますが、既存のデータベースへの影響は未知数です。
そこで、メッセージキューのシステムとしてのMySQLを独立した形で運用したほうが、障害発生時の原因の切り分けなどがラクなのでおススメします。
今回は、別MySQLでの作り方で記載します。
簡単には、メッセージキュー用MySQLは別領域でかつ別Port番号で受け付けるタイプです。
今回私のサーバー環境は以下の通りです。
[root@q4m ~]#uname -a
Linux q4m 2.6.32-573.7.1.el6.x86_64 #1 SMP Tue Sep 22 22:00:00 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
#3.各種ソフトのインストール
必要なパッケージを準備し、インストールします。
[root@q4m ~]# yum install -y git gcc gcc-c++ bison perl-Data-Dumper
gitからcloneされて自動でインストールされます。
[root@q4m ~]# cd /usr/local/src
[root@q4m ~]# git clone git://github.com/kazeburo/mysetup.git
[root@q4m ~]# cd mysetup/q4m_mysql56
[root@q4m ~]# sh ./setup.sh
cmake, libaio-devel, ncurses-devel は入っていなければこのスクリプトが自動的に yum から入れてくれます。
しばらく待つとビルドが完了し 「メッセージキュー用MySQL」が起動してくれます。
ここまではQiitaの記事に記載があります。
「CentOS 7 に Q4M をインストールする」
出典:http://qiita.com/akishin/items/bbe90f892e9fff2e105c
なお、setup.shのファイルにはバージョン記載があるので、取得するバージョンの確認が必要です。
[root@q4m ~]# cat /usr/local/src/mysetup/q4m_mysql56/setup.sh
#!/bin/sh
set -e
MYVER=5.6.20
Q4MVER=0.9.14
CDIR=$(cd $(dirname $0) && pwd)
cd /usr/local/src
if [ -f $CDIR/mysql-$MYVER.tar.gz ]; then
cp $CDIR/mysql-$MYVER.tar.gz ./
fi
if [ -d mysql-$MYVER ]; then
rm -rf mysql-$MYVER
fi
if [ ! -f mysql-$MYVER.tar.gz ]; then
wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-$MYVER.tar.gz
fi
tar zxf mysql-$MYVER.tar.gz
if [ -d q4m-$Q4MVER ]; then
rm -rf q4m-$Q4MVER
fi
if [ ! -f q4m-$Q4MVER.tar.gz ]; then
wget http://q4m.kazuhooku.com/dist/q4m-$Q4MVER.tar.gz
fi
tar zxf q4m-$Q4MVER.tar.gz
mv q4m-$Q4MVER mysql-$MYVER/storage/q4m
if [ ! -f mysql-$MYVER/storage/q4m/CMakeLists.txt ]; then
curl -kL https://raw.github.com/q4m/q4m/$Q4MVER/CMakeLists.txt > mysql-$MYVER/storage/q4m/CMakeLists.txt
fi
cd mysql-$MYVER/storage/q4m
cat $CDIR/q4m_test_queuewait_noinnodb.patch | patch -p0
cd /usr/local/src
yum install -y cmake ncurses-devel libaio-devel
cd mysql-$MYVER
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/q4m \
-DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all \
-DWITH_ZLIB=bundled -DWITH_SSL=bundled -DWITH_READLINE=1 -DWITH_PIC=ON -DWITH_FAST_MUTEXES=ON \
-DWITH_DEBUG=OFF \
-DCOMPILATION_COMMENT="Q4M" -DMYSQL_SERVER_SUFFIX="-q4m" \
-DMYSQL_USER=nobody -DMYSQL_UNIX_ADDR="/tmp/mysql_q4m.sock" -DMYSQL_TCP_PORT=13306 \
-DWITH_DEFAULT_FEATURE_SET=xsmall \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITHOUT_DAEMON_EXAMPLE_STORAGE_ENGINE=1 \
-DWITHOUT_FTEXAMPLE_STORAGE_ENGINE=1 \
-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 \
-DWITHOUT_ARCHIVE_STORAGE_ENGINE=1 \
-DWITHOUT_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITHOUT_FEDERATED_STORAGE_ENGINE=1 \
-DWITHOUT_INNOBASE_STORAGE_ENGINE=1 \
-DWITHOUT_PERFSCHEMA_STORAGE_ENGINE=1 \
-DWITHOUT_NDBCLUSTER_STORAGE_ENGINE=1 \
-DWITH_INNODB_MEMCACHED=OFF \
-DWITH_EMBEDDED_SERVER=OFF \
-DWITH_UNIT_TESTS=OFF
make
make install
mkdir -p /usr/local/q4m/etc
cp $CDIR/my.cnf /usr/local/q4m/etc
cp $CDIR/q4m.init /etc/init.d/q4m
chmod 755 /etc/init.d/q4m
chkconfig --add q4m
/usr/local/q4m/scripts/mysql_install_db --skip-name-resolve \
--basedir=/usr/local/q4m --defaults-file=/usr/local/q4m/etc/my.cnf
rm -f /usr/local/q4m/my.cnf
chmod 755 /usr/local/q4m/var
/etc/init.d/q4m start
cat storage/q4m/support-files/install.sql | /usr/local/q4m/bin/mysql -S /tmp/mysql_q4m.sock
echo "show plugins" | /usr/local/q4m/bin/mysql -S /tmp/mysql_q4m.sock
[root@q4m ~]#
#4.MySQLの併存方法
「メッセージキュー用MySQL」と既存のMySQLを併存することは可能です。
「メッセージキュー用MySQL」は初期インストール時にはポート番号13306で稼働しています。
##4.1 「メッセージキュー用MySQL」の初期Configファイル
「メッセージキュー用MySQL」の初期Configファイルは以下の通りです。
[root@q4m ~]# cat /usr/local/q4m/my.cnf
[client]
port = 3306
socket = /tmp/mysql_q4m.sock
#default-character-set = utf8
[mysql]
no-auto-rehash
#safe-updates
prompt = '\u@\h mysql>'
# also can use utf8mb4
default_character_set = utf8
[mysqld]
basedir = /usr/local/q4m
datadir = /usr/local/q4m/var
user = nobody
port = 13306
socket = /tmp/mysql_q4m.sock
skip-external-locking
key_buffer_size = 1M
max_allowed_packet = 64M
table_open_cache = 256
max_connections = 4096
max_connect_errors = 10000
sort_buffer_size = 128K
read_buffer_size = 128K
myisam_sort_buffer_size = 128K
thread_cache_size = 256
query_cache_size = 0
query_cache_type = 0
tmp_table_size = 64M
max_heap_table_size = 64M
skip-name-resolve
# also can use utf8mb4
character-set-server=utf8
default-storage-engine=MyISAM
default-tmp-storage-engine=MyISAM
transaction_isolation = REPEATABLE-READ
explicit_defaults_for_timestamp
sql_mode = "STRICT_ALL_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE"
slow_query_log = 1
long_query_time = 10
log_slow_admin_statements
[mysqldump]
quick
max_allowed_packet = 16M
[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
read_buffer = 1M
write_buffer = 0M
[mysqld_safe]
open-files-limit = 8192
[root@q4m ~/]#
適宜改変してください。
##4.2 「メッセージキュー用MySQL」の起動停止方法
初期インストールの場合には、サービスに登録されているので、以下の通りで起動・停止します。
起動する手順
[root@q4m ~]# service q4m start
Starting MySQL-Q4M: [ OK ]
[root@q4m ~]#
停止する手順
[root@q4m ~]# service q4m stop
Stopping MySQL-Q4M: [ OK ]
[root@q4m ~]#
##4.3 「メッセージキュー用MySQL」のポート番号開け
iptablesなどでポート番号を開けます。(私のサーバー環境はiptablesではなくルーター設定のため割愛します)
##4.4 「メッセージキュー用MySQL」の設定
「メッセージキュー用MySQL」内部に接続用ユーザー、データベース作成を行います。
初期のデータベースでrootユーザーの場合には、パスワードが設定されていません。
[root@q4m ~]# cd /usr/local/q4m/bin/
[root@q4m bin]# ./mysql -u root
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.20-q4m-log Q4M
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
root@localhost mysql>
気を付けなければならないのが、環境変数PATHでコマンドが検索されます。
インストールした「メッセージキュー用MySQL」のディレクトリにPATHが通っていなければ、「mysql」と入力すると /usr/bin/ /usr/sbinなどのディレクトリへ検索しにいきます。
「メッセージキュー用MySQL」のコマンド「./mysql」には./をつけてください。
(1)接続用ユーザーを作成
mysql> CREATE USER 'setuzokuser'@'192.168.5.1' identified by 'abcdefg';
(2)メッセージキュー用データベースを作成
mysql> CREATE DATABASE wpdbmq;
(3)権限の設定
mysql> GRANT ALL PRIVILEGES ON wpdbmq.* TO 'setuzokuser'@'192.168.5.1' IDENTIFIED BY 'abcdefg';
(4)権限の即時反映
mysql> flush privileges;
(5)rootユーザーのパスワード設定
mysql> SET PASSWORD = PASSWORD('ab9w37daskk');
(6)接続オフ
mysql> quit;
#5. 「メッセージキュー用MySQL」を使ってメッセージキュー送受信
メッセージキューとしての送受信のからくりはこちらです。
#5.1 メッセージキューのテーブル作成
やりとりになるメッセージキューのテーブルを作ります。
mysql> CREATE TABLE my_queue (v1 int not null, v2 varchar(255)) ENGINE=queue;
#5.2 メッセージキュー受信のPHPプログラム
メッセージキュー受信用PHPプログラムを作ります。
[root@192.168.5.1 ~]# cat 1.php
<?php
$dsn = 'mysql:dbname=wpdbmq;host=q4m;port=13306';
$user = 'setuzokuser';
$password = 'abcdefg';
try{
$dbh = new PDO($dsn, $user, $password);
while(1){
$sql = 'select queue_wait("my_queue")';
foreach ($dbh->query($sql) as $row) {
$sql = "select * from my_queue";
foreach( $dbh->query($sql) as $result){
$key = $result['v1'];
print $result['v1'] . " " ;
print $result['v2'] . " ";
print "\n" ;
}
// $key が9の場合は終了処理
if($key == 9){
break;
}
}
$sql = "select queue_end()";
$dbh->query($sql);
// $key が9の場合は終了処理
if($key == 9){
break;
}
}
}catch (PDOException $e){
print('Error:'.$e->getMessage());
die();
}
$dbh = null;
[root@192.168.5.1 ~]#
##5.3 メッセージキュー送信
送信はプログラムでなくても、MySQLコマンド上から送信することで対応できます。
root@localhost mysql>INSERT INTO my_queue (v1, v2) VALUES (3, "hello world!123");
Query OK, 1 row affected (0.00 sec)
root@localhost mysql>INSERT INTO my_queue (v1, v2) VALUES (3, "hello world!123");
Query OK, 1 row affected (0.28 sec)
root@localhost mysql>INSERT INTO my_queue (v1, v2) VALUES (9, "hello world!123");
Query OK, 1 row affected (0.28 sec)
##5.4 メッセージ受信のPHPプログラムの動き
キーで9が来たらプログラムが終了します。
[root@192.168.5.1 ~]# php 1.php
3 hello world!123
3 hello world!123
9 hello world!123
[root@192.168.5.1 ~]#
##5.5 応用例
・メッセージキュー受信のPHPプログラムをCRONで定期的に起動させ、メッセージを受信したら何かをするようなことができます。
・反応性が必要とまではいかないものの、重いプログラム系にはメッセージキューのからくりには使えます。
mysql> SELECT queue_wait('my_queue');
・queue_wait関数が有限時間のタイムアウトでwaitしてくれるので、ずっとブロック(処理待ち)ならないのが助かります。
#6. まとめ
今回の例では、データベースをメッセージキュー専用MySQLとしてプロセスをデーモンとして起動させておくことがポイントになります。
受け付けるポート番号(初期値:13306)を既存のMySQLと分けることで併存ができ、またメッセージキュー専用MySQLにすることで、データベースの容量は比較的コンパクトなサイズでの運用も可能です。
可能なら今流行りのDocker化して「メッセージキューサーバー」みたいな運用するとさらにいいかもしれません。
また、キャッシュサーバーとしてmemcachedなども連携すると、色々な広がりが見えてきそうです。
敷居の高そうなQ4Mも簡単に導入できるので、サーバーのWordPress連携などに使えそうです。