今回はEC2上での、MySQLとSpiderについての記事になります。
MySQLでの負荷分散となるとレプリケーションが主でしたが、参照系の負荷は分散できても更新処理は分散することが難しく、それがボトルネックになっていましたが、このSpiderを利用すると、更新も参照も負荷分散することができます。
Spider斯波健徳さんが開発したMySQLのストレージエンジンで、MySQLでのシャーディングという、データを分散して保存することで負荷を分散する処理を行うことができます。
尚、Spiderには以下の機能と特徴があります。

  • 異なるMySQLインスタンスのテーブルを同一インスタンスのテーブルのように扱うことが可能になります。
  • XAトランザクションを含むトランザクションをサポートしているため、更新系DBのクラスタリングに
    利用することが可能です。
  • テーブルパーティショニングをサポートしているため、パーティショニングのルールを利用して、
    同一テーブルのデータを複数サーバに分散配置することが可能です。
  • Spiderストレージエンジンのテーブルを作成すると、MySQL内部ではファイルへのシンボリックリンクの
    ように、リモートサーバのテーブルへのテーブルリンクを生成します。
  • テーブルリンクは、具体的にはローカルMySQLサーバからリモートMySQLサーバへのコネクションを
    確立することで実現されます。
  • リンク先のテーブルのストレージエンジンに制限はありません。

○Spiderの構成
Spiderはストレージエンジンなのでテーブル単位で分散することができます。
また、Spiderテーブルはデータそのものは保持しておらず、データ自体は接続先の分散用テーブルに保持され、Spider自体はデータノードへの分散、集約のためのゲートウェイとして機能します。

分散と集約には、パーティションの機能を利用しています。
本来パーティションは、そのテーブル内のデータ領域を内部で分けておくことによって、検索などの効率を上げるためのシステムですが、Spiderはこの設定を擬似的に利用することで、その領域を他のDBインスタンスにまで拡大して分散、集約するように作られています。
言い換えれば他のDBを全て1つのDBの1パーティションとして扱えるストレージエンジンです。

今回はサンプルとしてmemberテーブルに対する書き込みを分散するという目的で、以下のようなEC2インスタンスの構成で試してみます。
[ ]内は仮のIPになります。
ここでは、123.123.123.123をSpiderノード、残りのDB1,DB2をデータノードと呼ぶことにします。
Spiderは更新/参照するべきデータノードをテーブルパーティション設定によって判断します。

Spider、DB1、DB2の各データベースは共通して、以下のデータベースを持つことにします。
また、3つのノードで別々のDBやユーザー、パスワードのものを接続することも可能です。

  • データベース名:cloudpack
  • DBのユーザー名:cloudpack_user
  • DBのパスワード:cloudpack_pass

○データノードの設定

データノードは普段使用している通常のMySQLで構わず、特別なインストールも必要ありません。EC2でMySQL(簡単インストール編)と同様、Linuxバイナリを使用してインストールします。

・MySQLのインストールと起動Directory Listing: /archives/mysql-5.5から適切なバイナリを選んでダウンロードします。

su -
cd /usr/local/src

wget http://downloads.mysql.com/archives/mysql-5.5/mysql-5.5.14-linux2.6-i686.tar.gz

tar xzvf mysql-5.5.14-linux2.6-i686.tar.gz
mv mysql-5.5.14-linux2.6-i686 /usr/local/mysql-5.5.14
ln -s /usr/local/mysql-5.5.14 /usr/local/mysql

groupadd mysql
useradd -r -g mysql mysql

cd /usr/local/mysql
chown -R mysql:mysql .
yum list installed | grep libaio
./scripts/mysql_install_db --user=mysql
chown -R root .
chown -R mysql data
cp support-files/my-medium.cnf /etc/my.cnf
cp support-files/mysql.server /etc/init.d/mysqld
mkdir -p /var/log/mysql
chown -R mysql:mysql /var/log/mysql

/etc/init.d/mysqld start
chkconfig mysqld on

・ユーザーの作成

mysql -u root

mysql> GRANT ALL PRIVILEGES ON *.* TO 'cloudpack_user'@localhost IDENTIFIED BY 'cloudpack_pass';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'cloudpack_user'@'%' IDENTIFIED BY 'cloudpack_pass';
mysql> flush privileges;

・データベースの作成

mysql> create database cloudpack;

・テーブルの作成

mysql> use cloudpack;
mysql> create table member(
id int(11) auto_increment,
name varchar(256),
primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

・接続の許可
データノードのセキュリティグループに3306を追加、許可IPに接続先サーバーのIPを指定します。


○Spiderノードの設定

前述のとおり、Spiderは更新/参照するべきデータノードをテーブルパーティション設定によって判断します。
今回はKEYパーティションを利用した分散を試してみます。
Spiderを導入するには、素のMySQLのパッチ適用やコンパイルなどが必要ですが、Spiderやパッチ込みのLinuxバイナリが提供されているので、今回はこれを使用します。

・Spiderビルド済みMySQLのインストールSpiderForMySQL.com – DONWNLOAD Latestからビルド済みバイナリをダウンロードして展開します。

su -
cd /usr/local/src

wget http://spiderformysql.com/downloads/spider-2.26/mysql-5.5.14-spider-2.26-vp-0.15-hs-1.0-linux-i686-glibc23.tgz
tar xzvf mysql-5.5.14-spider-2.26-vp-0.15-hs-1.0-linux-i686-glibc23.tgz
mv mysql-5.5.14-spider-2.26-vp-0.15-hs-1.0-linux-i686-glibc23 /usr/local/
ln -s /usr/local/mysql-5.5.14-spider-2.26-vp-0.15-hs-1.0-linux-i686-glibc23 /usr/local/mysql

groupadd mysql
useradd -r -g mysql mysql
cd /usr/local/mysql
chown -R mysql:mysql .
scripts/mysql_install_db --user=mysql
chown -R root .
chown -R mysql data
cp support-files/my-medium.cnf /etc/my.cnf
cp support-files/mysql.server /etc/init.d/mysqld

mkdir -p /var/log/mysql
chown -R mysql:mysql /var/log/mysql

/etc/init.d/mysqld start
chkconfig mysqld on

・初期化スクリプトの実行
MySQLデータベースにSpiderがバックエンドで使用するのに必要なテーブルを作成するためのSQLファイルを同じページからダウンロードして実行します。

cd /usr/local/src
wget http://spiderformysql.com/downloads/spider-2.26/spider-init-2.26-for-5.5.14.tgz

tar xzvf spider-init-2.26-for-5.5.14.tgz 
mysql -u root

・ユーザーの作成

mysql -u root

mysql> GRANT ALL PRIVILEGES ON *.* TO 'cloudpack_user'@localhost IDENTIFIED BY 'cloudpack_pass';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'cloudpack_user'@'%' IDENTIFIED BY 'cloudpack_pass';
mysql> flush privileges;

・データベースの作成

mysql> create database cloudpack;
mysql> use cloudpack;

・テーブルの作成
Spiderストレージエンジンの作成を行います。

mysql> create table member(
id int(11) auto_increment,
name varchar(256),
primary key(id)
) engine = Spider DEFAULT CHARSET=utf8
CONNECTION ' table "item", user "cloudpack_user", password "cloudpack_pass" '
PARTITION BY KEY() (
   PARTITION db1 comment 'host "111.111.111.111", port "3306"',
   PARTITION db2 comment 'host "222.222.222.222", port "3306"'
);

Spiderは、MyISAMやInnoDBと同じくストレージエンジンなので、engine=Spiderと記載し、そして、このCREATE TABLE文でのPARTITION節とCONNECTIONがSpiderの分散設定の要になります。
ここでは、KEYパーティションによりパーティションをデータノードの数だけ、つまり2つに分けてあります。

KEYパーティションは簡単に言うとPRIMARY KEYのHash値を元にデータを格納すべきパーティションを決定する方式ですが、もちろんそれ以外のパーティションタイプを使用することも可能です。
また、Spiderはここで定義したPARTITION分割ルールにしたがって、更新/集約するデータノードを決定します。

そしてそれぞれのデータノードの接続先情報を定義するのが、PARTITION節のCOMMENT文字列と、ストレージエンジンの後のCONNECTION文字列になります。
これらは通常、別の目的で使用されるものですが、Spiderエンジンはこれらをデータノードの接続情報の設定として解釈するように動作します。
どちらもデータノードへの接続情報などを記載することができますが、主な利用の仕方としては、

  • CONNECTION文字列:テーブル全体としての共通の接続設定
  • COMMENT文字列:各データノード用の独自の接続設定

というように分けて設定することが多いようです。
これらの設定文字列には多数の細やかな設定ができるので、詳しくはプロダクト同包のマニュアルを参照ください。

ここでは、CONNECTION文字列に、DB名、DBユーザー名、DBパスワードを、各PARTITIONのCOMMENT文字列には、各データノードのホスト名とポート番号を記載しました。
もし、データノードが3つだった場合はPARTITION句を3つ設定し、それぞれDB名やテーブル名が異なっている場合には、databaseやtableなどの情報もPARTITION節ののCOMMENTの方にそれぞれ記載します。


○動作の確認

それでは、実際にSpiderがどのように動作するのか、確認してみます。
まず、Spiderノードで数件、INSERTしてみます。

mysql> INSERT INTO member (name) VALUES('memorycraft'),('ichiro'),('jiro'),('sub-LOW'),('shiro');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0

mysql> select * from member;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | memorycraft |
|  3 | jiro        |
|  5 | shiro       |
|  2 | ichiro      |
|  4 | sub-LOW     |
+----+-------------+
5 rows in set (0.00 sec)

一見、普通の1つのテーブルに見えます。
idの順がばらばらですが、通常のテーブルではauto incrementのカラムがあれば、その順にSELECTされることが多いです。
しかし、基本的にORDER BY句がないと順序保証はされないので、特別変わった動作ではなく通常のMySQLの仕様の範囲になります。

SpiderテーブルはDROP TABLEしてもデータノードのテーブルは削除されません。
これはSpiderテーブルが接続や分散/集約のハブとして機能しているだけで、データの保持、管理を行っていないことを表します。
DROP TABLEしたあとに再度CREATE TABLEをするだけで、SELECT結果は元通りのデータが返ってきます。

mysql> create table member(
id int(11) auto_increment,
name varchar(256),
primary key(id)
) engine = Spider DEFAULT CHARSET=utf8
CONNECTION ' table "member", user "cloudpack_user", password "cloudpack_pass" '
PARTITION BY KEY() (
   PARTITION db1 comment 'host "111.111.111.111", port "3306"',
   PARTITION db2 comment 'host "222.222.222.222", port "3306"'
);
Query OK, 0 rows affected (0.03 sec)

mysql> 
mysql> select * from member;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | memorycraft |
|  3 | jiro        |
|  5 | shiro       |
|  2 | ichiro      |
|  4 | sub-LOW     |
+----+-------------+
5 rows in set (0.00 sec)

一方、TRUNCATE TABLEはデータの除去クエリなので、データノードのデータは削除されます。

mysql> truncate table member;Query OK, 0 rows affected (0.01 sec)

mysql> select * from member;
Empty set (0.00 sec)

再度INSERTをし直して、各データノードを確認します。

・SpiderテーブルでINSERT

mysql> INSERT INTO member (name) VALUES('memorycraft'),('ichiro'),('jiro'),('sub-LOW'),('shiro');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0

・db1でSELECT

mysql> select * from member;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | memorycraft |
|  3 | jiro        |
|  5 | shiro       |
+----+-------------+
3 rows in set (0.00 sec)

・db2でSELECT

mysql> select * from member;
+----+---------+
| id | name    |
+----+---------+
|  2 | ichiro  |
|  4 | sub-LOW |
+----+---------+
2 rows in set (0.00 sec)

上記のように、きれいに分散されて保存されていることが確認できます。

ここで、データノードのidカラムにそれぞれauto_incrementが設定されているにもかかわらずidが重複しないのは、Spiderのテーブル設定のauto_increment_modeパラメータ(CONNECTION文字列で設定できるパラメータ)の動作に基づきます。
auto_increment_modeの動作としては、

  • 0:通常モード(リモートサーバにロック付き問い合わせで取得した最新付番を利用します。)
    動作は遅く、テーブルパーティショニングを利用しており、auto incrementカラムが indexの
    第一カラムである場合は、簡易モードで動作する。
  • 1:簡易モード(Spiderテーブル内のカウントで付番を行う。)
    動作は速いが、更新は1テーブルからのみに限定しないと値の重複が発生する。
  • 2:割愛
  • 3:割愛

(デフォルトは0になります。)

となっており、今回の場合は1の簡易モードが有効になり、Spider側で自動採番しているためです。
この様に、複数の分散されたDBを1つのDBとほぼ同じように扱えるため、読込みだけでなく書込みにも負荷分散でき、非常に有用なプロダクトだと言えます。

こちらの記事はなかの人(memorycraft)監修のもと掲載しています。
元記事は、こちら