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は更新/参照するべきデータノードをテーブルパーティション設定によって判断します。
│[123.123.123.123] ┌──┴──┐ │ Spider │ └──┬──┘ │ │ ┌──────┴───────┐ │[111.111.111.111] │[222.222.222.222] ┌─┴─┐ ┌─┴─┐ │ DB1 │ │ DB2 │ └───┘ └───┘
Spider、DB1、DB2の各データベースは共通して、以下のデータベースを持つことにします。
また、3つのノードで別々のDBやユーザー、パスワードのものを接続することも可能です。
- データベース名:cloudpack
- DBのユーザー名:cloudpack_user
- DBのパスワード:cloudpack_pass
データノードの設定
データノードは普段使用している通常のMySQLでかまいません。特別なインストールも必要なしです。
前々回と同様、Linuxバイナリを使用してインストールします。
MySQLのインストールと起動
mysqlのダウンロードページから適切なバイナリを選んでダウンロードします。
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のインストール
Spiderのダウンロードページからビルド済みバイナリをダウンロードして展開します。
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 < install_spider.sql
ユーザーの作成
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 "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"' );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の動作として、
となっており、今回の場合1の簡易モードが有効になり、Spider側で自動採番しているためです。デフォルトは0
- 0:通常モード。(リモートサーバにロック付き問い合わせで取得した最新付番を利用して、付番を行う。) 遅い。テーブルパーティショニングを利用しており、auto incrementカラムが indexの第一カラムである場合は、簡易モードで動作する。
- 1:簡易モード。(Spiderテーブル内のカウントで付番を行う。) 速いが、更新は1テーブルからのみに限定しないと値の重複が発生する。
- 2:割愛
- 3:割愛
この様に、複数の分散されたDBをまったく1つのDBとほぼ同じように扱えるため、読込みだけでなく書込みにも負荷分散でき、非常に有用なプロダクトだといえます。
疲れた、、、、今回はここまで。