ふたたびSpiderの話題です。
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)
このように、リージョンが分かれていても、アクセス速度を気にすること無くシャーディングができました。
以上です。