EC2でMySQL(運用編 VP+Spiderで無停止負荷分散)などを紹介してきましたが、再び、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)

このように、リージョンが分かれている場合でも、アクセス速度を気にすること無くシャーディングができました。

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