WEBアプリを世界展開する場合、要件の1つとして、世界各国のユーザーは全てのデータを参照する必要があるが、データの登録は各国、地域の担当者が各自のデータを登録したい、というケースが多いと思います。
たとえば、商品のサイトで、EUと日本にそれぞれ管理者がいるとします。
その場合のユースケースとしては、
- EUの管理者はEUの商品を登録する
- 日本の管理者は日本の商品を登録する
- ユーザーは全ての商品を閲覧できる
となります。
このとき、DBがどのリージョンにあるかによって、ユーザーや管理者の間で、レスポンススポードに差がでます。
DBを日本に置くとEUのユーザーや管理者には遅いシステムとなってしまい、EUに置くとその逆になります。
そのため、各リージョンに全てのリージョンで登録した商品データを用意し、ユーザーのロケーションに関わらず、DBアクセスをユーザーと同じリージョン内で済ませる必要があります。管理者がアクセスするDBも管理者のいるリージョン内で済ませる必要があります。
これをSpiderとレプリケーションで実現してみます。
上図をみると想像できるかも知れませんが、方法としてはEUとJPそれぞれのリージョンに属する商品マスタに対して書き込み、EUではJPの、JPはEUのスレーブをもち、それぞれをSpiderでシャーディングします。
DBの図で表すと、下記のようになります。
それでは実際に試してみます。
データノード
CREATE TABLE item ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(256) DEFAULT NULL, shop_id int(11) DEFAULT NULL, region_id int(11) NOT NULL DEFAULT '0', PRIMARY KEY (id, region_id) ) ENGINE=SPIDER DEFAULT CHARSET=utf8 ;
Spiderノード
spider_ja
CREATE TABLE item ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(256) DEFAULT NULL, shop_id int(11) DEFAULT NULL, region_id int(11) NOT NULL DEFAULT '0', PRIMARY KEY (id, region_id) ) ENGINE=SPIDER DEFAULT CHARSET=utf8 CONNECTION=' table "item", user "remote_user", password "remote_pass" ' PARTITION BY LIST (region_id) ( PARTITION ja_ja VALUES IN (1) COMMENT = 'host "111.111.0.1", port "3306"', PARTITION ja_eu VALUES IN (2) COMMENT = 'host "111.111.0.2", port "3306"' ) ;
spider_eu
CREATE TABLE item ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(256) DEFAULT NULL, shop_id int(11) DEFAULT NULL, region_id int(11) NOT NULL DEFAULT '0', PRIMARY KEY (id, region_id) ) ENGINE=SPIDER DEFAULT CHARSET=utf8 CONNECTION=' table "item", user "remote_user", password "remote_pass" ' PARTITION BY LIST (region_id) ( PARTITION eu_ja VALUES IN (1) COMMENT = 'host "222.222.0.1", port "3306"', PARTITION eu_eu VALUES IN (2) COMMENT = 'host "222.222.0.2", port "3306"' ) ;
レプリケーション
ja-eu
$ mysql -u root mysql> CHANGE MASTER TO MASTER_HOST='222.222.0.2', MASTER_USER='remote_user', MASTER_PASSWORD='remote_user', MASTER_PORT=3306;
eu-ja
$ mysql -u root mysql> CHANGE MASTER TO MASTER_HOST='111.111.0.1', MASTER_USER='remote_user', MASTER_PASSWORD='remote_user', MASTER_PORT=3306;
※各ノード間のアクセス権限やサーバーIDの登録、セキュリティグループの設定などは以前の記事に書いたので割愛します
ポイントはregion_id(1:ja, 2:eu)のLISTパーティションにするため、プライマリキーをidとregion_idの複合キーにするところです。INSERT時には、登録したリージョンの region_idをセットします。
※登録したリージョンではないregion_idをセットするとパーティションに含まれず、シャーディング対象にならないので、注意が必要です。
spider-ja
mysql> INSERT INTO item (name, shop_id, region_id) VALUES('おいしい水', 1, 1), ('おしゃれなバッグ', 2, 1); Query OK, 2 rows affected (0.02 sec) Records: 2 Duplicates: 0 Warnings: 0
spider-eu
mysql> insert into item(name,shop_id,region_id) values('Cool Watch', 3, 2),('Cute Ring', 4, 2); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0
すると、
それぞれのspiderノードですべてのitemがselectできます。
mysql> select * from item; +----+--------------------------+---------+-----------+ | id | name | shop_id | region_id | +----+--------------------------+---------+-----------+ | 1 | おいしい水 | 1 | 1 | | 2 | おしゃれなバッグ | 2 | 1 | | 1 | Cool Watch | 3 | 2 | | 2 | Cute Ring | 4 | 2 | +----+--------------------------+---------+-----------+ 4 rows in set (0.01 sec)
このように、リージョンが分かれていても、アクセス速度を気にすること無くシャーディングができました。
以上です。