Help us understand the problem. What is going on with this article?

CentOS6にQ4Mを入れて、Q4Mを使って他サーバPHPプログラムとの連携

More than 3 years have passed since last update.

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」を使ってメッセージキュー送受信

メッセージキューとしての送受信のからくりはこちらです。

チュートリアル
http://mogile.web.fc2.com/q4m/tutorial.html

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連携などに使えそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした