![]() ![]() |
![]() |
|
![]() |
||
![]() |
もしかしたら使うかもしれないので調べてみた。
横軸にはサービス運用開始からの時間経過を設定し、縦軸には「DBの応答時間」、「DBへの問い合わせ数」、「DBサイズ」の各数量をとります。サービスが順調に利用されていっているものとし、「DBサイズ」や「DBへの問い合わせ数」は時間経過とともに線形に増えていきますが、「DBの応答時間」はある時を境に指数的に増えていくことが想定できます。要するにDBのレスポンスは急激に悪化することがあります。原因としては以下が考えられます。
スケールアップ・スケールアウトという枠組みで解決法が考えられますが、今回の主題から言うと次のようになります。
DB shardingは単一のサーバでの処理能力が著しく落ちない程度にデータの大きさを調節する(データベースサイズをスケールする)ことでDBの性能を最大限に引き出せるようにする手法です。MySQLのSpiderエンジンは手軽にDBを分散処理できるようにしてくれています。
これに対してレプリケーションはDBへの参照問い合わせをスケールしてくれていると言えるでしょう。
上記の図はサーバ4台の構成で、黄色のサーバはアプリケーションサーバでDBサーバも兼ねています。が、DBのデータの実体は各オレンジ色のDBサーバに分散されて黄色のサーバはデータは保持していません。
下記のようなCREATE文を発行することで通常は一つのMYDファイルに保存されるところをp0.MYD, p1.MYD, p2.MYD, p3.MYDのように4つのファイルに分割してデータを保存することができるようになります。ちなみにこのSQL文だけだと単に同一のサーバにファイル分割しただけとなります。同一のサーバでも異なるHDに分割できるようにすればデータの読み込み速度も上がるのかなと思ったりしますが、単純にファイル分割しただけで何がどう変わるとかまでは調べておりません。。
CREATE TABLE t_range ( name text, hight int, birthday date ) ENGINE=MYISAM PARTITION BY RANGE(hight) ( PARTITION p0 VALUES LESS THAN (150), PARTITION p1 VALUES LESS THAN (170), PARTITION p2 VALUES LESS THAN (180), PARTITION p3 VALUES LESS THAN MAXVALUE )
CREATE TABLE t_list ( name text, hight int, birthday date ) ENGINE=MYISAM PARTITION BY LIST(MONTH(birthday)) ( PARTITION p0 VALUES IN (1, 2, 3), PARTITION p1 VALUES IN (4, 5, 6), PARTITION p2 VALUES IN (7, 8, 9), PARTITION p3 VALUES IN (10, 11, 12) );
CREATE TABLE t_hash ( name text, hight int, birthday date ) ENGINE=MYISAM PARTITION BY HASH(MONTH(birthday)) PARTITIONS 4;
CREATE TABLE t_key ( id int, name text, hight int, birthday date ) ENGINE=MYISAM PARTITION BY KEY(id) PARTITIONS 4;
mysqlのドキュメントページからダウンロード(http://dev.mysql.com/doc/index-other.html)できるemployeeデータベースを使ってサンプルを作成する。
CREATE TABLE salaries ( emp_no int(11) NOT NULL, salary int(11) NOT NULL, from_date date NOT NULL, to_date date NOT NULL, PRIMARY KEY (emp_no,from_date), KEY emp_no (emp_no) ) ENGINE=SPIDER DEFAULT CHARSET=utf8 PARTITION BY HASH(emp_no) ( PARTITION p1 COMMENT 'user "msandbox", password "msandbox", host "127.0.0.1", port "13916", table "salaries",', PARTITION p2 COMMENT 'user "msandbox", password "msandbox", host "127.0.0.1", port "13917", table "salaries",', PARTITION p3 COMMENT 'user "msandbox", password "msandbox", host "127.0.0.1", port "13918", table "salaries",' );
CREATE TABLE salaries ( emp_no int(11) NOT NULL, salary int(11) NOT NULL, from_date date NOT NULL, to_date date NOT NULL, PRIMARY KEY (emp_no,from_date), KEY emp_no (emp_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
$ ./n1 spider_test -e 'select count(*) from salaries'; +----------+ | count(*) | +----------+ | 2844047 | +----------+
$ ./use_all -e 'use spider_test; select count(*) from salaries'; # server: 1: count(*) 2844047 # server: 2: count(*) 947747 # server: 3: count(*) 947505 # server: 4: count(*) 948795
insert into salaries select * from salaries_datasource
まずは単一のサーバにロードされたsalariesテーブル mysql > desc salaries; +-----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+-------+ | emp_no | int(11) | NO | PRI | NULL | | | salary | int(11) | NO | | NULL | | | from_date | date | NO | PRI | NULL | | | to_date | date | NO | | NULL | | +-----------+---------+------+-----+---------+-------+ 4 rows in set (0.00 sec) mysql > select AVG(salary) from salaries; +-------------+ | AVG(salary) | +-------------+ | 63810.7448 | +-------------+ 1 row in set (1.17 sec) mysql > select count(*) from salaries; +----------+ | count(*) | +----------+ | 2844047 | +----------+ 1 row in set (0.74 sec) mysql > select count(*) from salaries where emp_no in (10011, 10012, 10013); +----------+ | count(*) | +----------+ | 34 | +----------+ mysql > delete from salaries where emp_no in (10011, 10012, 10013); Query OK, 34 rows affected (0.01 sec) mysql > select AVG(salary) from salaries; +-------------+ | AVG(salary) | +-------------+ | 63810.9068 | +-------------+ mysql > select count(*) from salaries; +----------+ | count(*) | +----------+ | 2844013 | +----------+ 1 row in set (0.87 sec)
次いでspiderテーブル node1 > select AVG(salary) from salaries; +-------------+ | AVG(salary) | +-------------+ | 63810.7448 | +-------------+ 1 row in set (3.33 sec) node1 > select count(*) from salaries where emp_no in (10011, 10012, 10013); +----------+ | count(*) | +----------+ | 34 | +----------+ node1 > delete from salaries where emp_no in (10011, 10012, 10013); Query OK, 34 rows affected (0.02 sec) node1 > select AVG(salary) from salaries; +-------------+ | AVG(salary) | +-------------+ | 63810.9068 | +-------------+ 1 row in set (3.31 sec)
とまあ以上のような感じで検証しました。参考にさせてもらったのは主にhttp://nippondanji.blogspot.com/2010/04/spider.htmlでした。
あと、レプリケーションして使いたいとか、そういうケースも調べてみたのでまた別エントリで書きたいと思います。
自宅サーバ派の自分としては結構使い道があるなと思ったりもしています。