ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2010-04-20

まるで魔法のようなストレージエンジン??VP for MySQLによる驚愕のテーブル操作テクニック。

先日、SPIDERストレージエンジンについて2度に渡り本ブログで紹介した(その1:Not Only NoSQL!! 驚異的なまでにWRITE性能をスケールさせるSPIDERストレージエンジンその2:快適スケールアウト生活への第一歩。SPIDERストレージエンジンを使ってみよう!)が、SPIDERの作者である斯波氏は、実はもう一つ驚くべきストレージエンジンを開発している。その名も、VPストレージエンジンだ。ちょっと地味な名前だが、VPとは、Vertical Partitioning(垂直パーティショニング)の略で、複数のテーブルの上にVPストレージエンジンを被せて、垂直パーティショニング(カラムごとにデータを格納する領域を分ける)を実現するというものだ。他のテーブルの上に被せるアーキテクチャをとっているという点では、VPとSPIDERの発想は同じである。以下は、VPストレージエンジンの動作イメージだ。
このVPストレージエンジン、実は垂直パーティショニングに使えるだけでなく、とても応用が利く。これまで、「MySQLの運用ではこういう点で困っています」といった悩みを、一挙に解決するかも知れない凄いヤツなのだ。というわけで、本日はVPストレージエンジンについて、基本的な使い方からその応用方法までを説明しようと思う。


VPのインストール

VPのインストール方法は、SPIDERのインストール方法とほぼ同じだ。partitionconditionpushdownformysqlを適用する必要があるので、ソースコードをコンパイルするのがオススメである。ソースコードはLaunchpadから入手しよう。ドキュメントもこのページにあるので、手順の詳細はそちらを見て頂きたい。

Vertical Partitioning for MySQL

ソースコードを入手したら、展開して、パッチをあてて、VPストレージエンジンをstorageディレクトリにコピーして、configure&&makeする。以下、03_install_vp_storage_engine.txtからの抜粋である。
MySQLのソースの展開。
# tar zvfx ./mysql-5.1.39.tar.gz

Vertical Partitioningストレージエンジンのソースの展開と移動。
# tar zvfx ./partition_cond_push-0.1-for-5.1.36.tgz (http://launchpad.net/partitionconditionpushdownformysql からダウンロード)
# tar zvfx ./vp-0.8-for-5.1.39.tar.gz
# mv ./vp ./mysql-5.1.39/storage

パッチの適用、コンパイル準備、コンパイル、インストール。
# cd ./mysql-5.1.39
# patch -p2 < ../mysql-5.1.36.partition_cond_push.diff
# patch -p2 < ../mysql-5.1.39.vp.diff
# autoconf
# automake
# ./configure --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data --libexecdir=/usr/local/mysql/bin --enable-thread-safe-client --enable-local-infile --with-pic --with-fast-mutexes --with-client-ldflags=-static --with-mysqld-ldflags=-static --with-zlib-dir=bundled --with-big-tables --with-ssl --with-readline --with-embedded-server --with-partition --without-innodb --without-ndbcluster --without-archive-storage-engine --without-blackhole-storage-engine --with-csv-storage-engine --without-example-storage-engine --without-federated-storage-engine --with-extra-charsets=complex
(オプションは適当に変更すること)
# make
# make install

インストール後、起動までの操作はmysqlリファレンスマニュアルを参照。
http://dev.mysql.com/doc/refman/5.1/ja/post-installation.html

プラグインをインストールする。
mysql> install plugin vp soname 'ha_vp.so';
mysql> create function vp_copy_tables returns int soname 'ha_vp.so';
SPIDERのときも言及したが、--with-embedded-server--without-embedded-serverにしておくといいだろう。(どうせ使わないのにビルドに時間が掛かってしまうからだ。)

VPはSPIDERと違って、リモートサーバーへの接続などを管理する必要が無い(つまりステートレスである)ため、管理用のテーブルを作成する必要はない。そのため、INSTALL PLUGINでプラグインとしてインストールし、CREATE FUNCTIONでUDFを登録しさえすれば、直ぐに使い始めることが出来る。今回は、my.cnfはデフォルトのまま利用するが、SPIDERと違ってVPはオプションがとても少ない。ぜひ皆さんの手でオプションのチューニングをして頂きたい。

テーブルを作成する

冒頭のイメージのように、VPストレージエンジンは他のストレージエンジンで作成したテーブルの上に被せるようにして利用する。VPテーブルが実際にデータを格納するテーブルには、共通の主キー(PRIMARY KEY)を設ける。すると、同一のPKを持つ行が、ひとつの行として扱われるわけである。それでは実際にVPを使ってテーブルを作成してみよう。今回も、モチーフとしてMySQL公式のサンプルデータベースであるemployeesデータベースを利用する。以下は、employeesテーブルをVPを使って2つにパーティショニングする例である。
mysql> CREATE TABLE employees_vp1 (
    ->   emp_no int(11) NOT NULL,
    ->   birth_date date NOT NULL,
    ->   hire_date date NOT NULL,
    ->   PRIMARY KEY (emp_no)
    -> ) ENGINE InnoDB DEFAULT CHARSET utf8;
Query OK, 0 rows affected (0.06 sec)

mysql> CREATE TABLE employees_vp2 (
    ->   emp_no int(11) NOT NULL,
    ->   first_name varchar(14) NOT NULL,
    ->   last_name varchar(16) NOT NULL,
    ->   gender enum('M','F') NOT NULL,
    ->   PRIMARY KEY (emp_no)
    -> ) ENGINE InnoDB DEFAULT CHARSET utf8;
Query OK, 0 rows affected (0.10 sec)

mysql> CREATE TABLE employees (
    ->   emp_no int(11) NOT NULL,
    ->   birth_date date NOT NULL,
    ->   first_name varchar(14) NOT NULL,
    ->   last_name varchar(16) NOT NULL,
    ->   gender enum('M','F') NOT NULL,
    ->   hire_date date NOT NULL,
    ->   PRIMARY KEY (emp_no)
    -> ) ENGINE VP DEFAULT CHARSET utf8
    -> COMMENT 'table_name_list "employees_vp1 employees_vp2"';
Query OK, 0 rows affected (0.41 sec)
このように、VPストレージエンジンでテーブルを作成する手順は、至ってシンプルであると言える。配下のテーブルをCOMMENT文で定義するのは、SPIDERと同じ発想である。このテーブル定義の実体は、次のようなものであると考えられる。VPテーブルには実際にはデータは格納されておらず、配下の2つのInnoDBテーブルにデータが格納されているのである。
VPは、その配下のテーブルをロックしない。そのため、VP利用中に配下のテーブルを直接書き換えたり、DROPしたりしないように注意しよう。

カラムごとに格納する領域を別けると何が嬉しのか?

そもそもであるが、カラムごとに格納する領域を分けるという、垂直パーティショニングは何が嬉しいのだろうか?以前、InnoDBにおけるCOUNT()のチューニングについて解説したが、スキャン系の処理では、ディスクから読み取るデータ量が少なければ少ないほどクエリが効率的になる。垂直パーティショニングは、特にDWH(データウェアハウス)やBI(ビジネスインテリジェンス)系の処理において、威力を発揮する仕掛けなのである。

InnoDBにおけるCOUNT()のチューニングでは、Covering Indexを利用してスキャンを高速化する手法について述べた。Covering Indexを作成すると、その分インデックスツリーが大きくなってしまうという問題がある。その点、VPを利用してスキャンで参照するカラムだけを別けておけば、Covering Indexを利用しなくてもCOUNT()の高速化が期待できる。そのため、ディスクの消費量という観点からすると、VPを利用した方が効率が良いのである。

同様に、テーブルをスキャンする必要がある処理では、カラムを別けておくだけで(不要なカラムへアクセスする必要がなくなるため)高速化が期待できる。

実際にデータを格納する領域(実体は他のストレージエンジンを使ったテーブル)を別けることによるメリットは、クエリの効率化だけではない。実は、次のように様々なメリットが存在するのである。

InnoDBのカラムサイズの制限解除

ご存じの通り、InnoDBには1行あたりおよそ8KBまでというサイズ制限がある。BLOB/TEXT/大きなサイズのVARCHARなどのデータは、別の領域に格納されるため8KB以上のBLOBデータを作成することは可能である。ただし、BLOBは先頭の768バイトが通常の行データと同じ領域に格納されるため、BLOBなどの大きなカラムをひとつのテーブルにたくさん作成することは出来ないという制限がある。768バイトをフルで使うと、11カラム目には8KBの制限を超えてしまうからである。つまり、InnoDBでは実質的に、ひとつのテーブルにBLOBカラムは10個までしか作成することが出来ないのである。

実は、この制限はVPストレージエンジンを使えばいとも簡単に解決できる。8KB以上のデータを1行に格納する必要がある場合には、VPストレージエンジンで領域を分けてしまえばいいのだ。VPストレージエンジンを利用すれば、「InnoDBの1行あたり8KBまで」という制限は、実質的に無かったことに出来るのである!!

パーティショニングのユニークキー制限解除

MySQLの水平パーティショニングには、ひとつ大きな制限がある。それは、「パーティショニングの評価式に登場するカラムは、全てのPKまたはUNIQUE KEYに所属していなければならない」というものである。どういう事かというと、次のようなパーティションは定義出来ないということである。
mysql> CREATE TABLE t (
    ->   col1 INT NOT NULL,
    ->   col2 DATE NOT NULL,
    ->   col3 INT NOT NULL,
    ->   col4 INT NOT NULL,
    ->   col5 VARCHAR(100) NOT NULL,
              :
            (中略)
              :
    ->   UNIQUE KEY uk1 (col1, col2),
    ->   UNIQUE KEY uk2 (col3)
    -> ) PARTITION BY HASH(col3) PARTITIONS 4;
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
col3は、uk2には含まれているが、uk1には含まれていない。一応、次のようにcol3をuk1へ追加すれば、パーティショニングを行う事が出来るのだが、それではuk1のユニーク性が阻害されてしまい、uk1はUNIQUE KEYとして意味を為さなくなってしまうだろう。
mysql> CREATE TABLE t (
    ->   col1 INT NOT NULL,
    ->   col2 DATE NOT NULL,
    ->   col3 INT NOT NULL,
    ->   col4 INT NOT NULL,
    ->   col5 VARCHAR(100) NOT NULL,
              :
            (中略)
              :
    ->   UNIQUE KEY uk1 (col1, col2, col3),
    ->   UNIQUE KEY uk2 (col3)
    -> ) PARTITION BY HASH(col3) PARTITIONS 4;
Query OK, 0 rows affected (0.09 sec)
このように、一意制約が欲しい場合には、パーティショニングをどうしようかと頭を悩ませてしまうわけである。もちろん、テーブル定義を再考して正規化してしまうというのも手であろう。(ひとつのテーブルに複数のUNIQUE KEYが登場するのは、正規化が必要であるという兆候のひとつである。)だが、VPストレージエンジンを利用すれば、次のようにテーブルを定義することで、回避することが可能になるのだ!
CREATE TABLE vp1 (
  col1 INT NOT NULL,
  col2 DATE NOT NULL,
  col3 INT NOT NULL,
  col4 INT NOT NULL,
  col5 VARCHAR(100) NOT NULL,
          :
        (中略)
          :
  PRIMARY KEY (col3)
) ENGINE InnoDB PARTITION BY HASH(col3) PARTITIONS 4;

CREATE TABLE vp2 (
  col1 INT NOT NULL,
  col2 DATE NOT NULL,
  col3 INT NOT NULL,
  UNIQUE KEY (col1, col2),
  PRIMARY KEY (col3)
) ENGINE InnoDB;

CREATE TABLE t (
  col1 INT NOT NULL,
  col2 DATE NOT NULL,
  col3 INT NOT NULL,
  col4 INT NOT NULL,
  col5 VARCHAR(100) NOT NULL,
          :
        (中略)
          :
  UNIQUE KEY (col1, col2),
  PRIMARY KEY (col3)
) ENGINE VP
COMMENT 'table_name_list "vp1 vp2", pk_correspond_mode "1"';
この例では、実質的な本体となるvp1テーブルが(col3)によってHASHパーティショニングされ、vp2テーブルにおいて(col1, col2)のユニーク性が保証されるというわけである。なんと、見事にMySQLのパーティショニングの制限を実質的に回避することができた!!

オンラインスキーマ変更

先ほどのパーティショニングの制限を回避する例を注意深く見られた方は、col1とcol2がvp1テーブルとvp2の両方のテーブルに存在することに気付かれたことだろう。ここでひとつ疑問が沸いてくる。「PKでないカラムが重複していても大丈夫なの?!」と。

大丈夫なのである!

先ほどのパーティショニングの例では、重複しているカラムはcol1とcol2の2つだけであったが、実は全てのカラムが重複していても良い。さらに突き詰めると、VPストレージエンジンの配下のテーブルは、まったく同じ定義であっても問題はない。そのように同じ定義のテーブルをVPストレージエンジンでラッピングしても意味が無いじゃないか?!と思われるかも知れない。が、この点こそがVPの有用性をさらに飛躍的に向上させるタネとなり、あたかもマジックであるかのように様々な応用を可能にするのである!!

その応用例の代表的なものが、オンラインスキーマ変更である。ご存じの通り、MySQLはALTER TABLEを実行すると、その間テーブルはロックされ、参照だけが可能な状態になる。ALTER TABLE中の更新はブロックされ、スキーマ変更完了後に改めて処理されるのである。大きなテーブルともなるとALTER TABLEコマンドの実行時間は無視出来ないほど掛かってしまうため、処理の中でどうしても参照が必要なサービスでは、スキーマ変更は実質的にサービス停止となってしまう。このことは、多くのMySQL DBAを悩ます問題であった。しかし、VPストレージエンジンを利用すればオンラインスキーマ変更が可能になる!!その様子を示したのが次の図である。


これだけではわかり辛いので、以下に操作の詳細を説明しよう。

STEP 1: 新しい定義のテーブルと、VPテーブルを準備

例えば次のテーブルに対して、新たにINDEX(c)を追加することを考える。
CREATE TABLE mytable (
  a int NOT NULL,
  b varchar(100),
  c DATE NOT NULL,
  PRIMARY KEY (a)
) ENGINE InnoDB;
次に、空のテーブル(新しい定義のもの+ダミー)とVPテーブルを作成する。
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX(c);
CREATE TABLE mytable_dummy LIKE mytable;
CREATE TABLE mytable_vp LIKE mytable;
ALTER TABLE mytable_vp ENGINE VP COMMENT 'table_name_list "mytable_dummy mytable_new", ctm "1", ist "1", zru "1"';
「ctm "1", ist "1", zru "1"」はVPのテーブルオプションである。ここでは説明を割愛する。詳細はドキュメントに含まれる「06_table_parameters.txt」を見て頂きたい。

STEP 2: テーブルの入れ替え

次に、テーブルの名前を変更する。名前の変更だけなので、この操作は一瞬である。

RENAME TABLE mytable TO mytable_dummy,
             mytable_dummy TO mytable_useless,
             mytable_vp TO mytable;
この一回の操作により、VPテーブルを通じてオリジナルのテーブルへアクセスするようになった。ただし、新しい定義のテーブルもVPストレージエンジンによりアクセスされるようになっているが、こちらは今の段階では空である。このように、空のテーブルが存在してもエラーが起きないように、上記のような追加オプションが指定されている。

STEP 3: データのコピー

次に、新しい定義のテーブルへデータのコピーを行う必要があるのだが、ここでは本エントリの冒頭でUDFをインストールしたのを覚えていらっしゃるだろうか?そう、そのUDFはデータをコピーするためものなのである。さすが斯波氏、用意周到である。
SELECT vp_copy_tables('mytable', 'mytable_dummy', 'mytable_new');
vp_copy_tables()の引数はそれぞれ「VPテーブル名」「コピー元テーブル名」「コピー先テーブル名」である。

STEP 4: 再びテーブルを入れ替え

コピーが完了したら、もう一度テーブルをRENAMEして操作は完了である。また、不要になったテーブルはDROPしておくと良いだろう。
RENAME TABLE mytable TO mytable_vp,
             mytable_new TO mytable;
DROP TABLE mytable_useless, mytable_dummy;

SPIDERにおけるResharding

VPストレージエンジンの可能性を、さらに無限にまで感じさせてくれるのは、SPIDERストレージエンジンと併用出来るということである。VPテーブルの配下にSPIDERテーブルを配置したり、SPIDERテーブルの配下にVPテーブルを配置したり、さらに数珠つなぎにしたり・・・と自由自在である!!

この特性を応用すると、SPIDERのようなSharding利用時の一番の問題であるRe-Sharding、つまりデータの再分散という課題を克服することが出来るのである。もちろんオンラインで。Re-Shardingまで解決できれば、SPIDERにはもはや死角なしではないか!!

以下、Re-Shardingの作業の様子を図を用いて説明しよう。まず、以下は初期状態である。


次に、リモートのノードにおいて、VP+SPIDERを使う。ここがミソなのであるが、node1上ではこれまでと同じように、データの参照・更新が出来る。先ほどと同様、vp_copy_tables()を用いてデータをコピーする。


最後に、node1でSPIDER側のの定義を変更すれば、作業は完了である。SPIDERノードが複数あれば、それぞれのノードで定義を変更しよう。


まとめ

いかがだろうか?!VPストレージエンジンの凄さを実感して頂けただろうか?VPストレージエンジンを使えば、MySQL単体では解決出来なかった様々な問題、具体的には次のものがいともあっさりと解決出来てしまうのである。
  • InnoDBの行サイズ制限(8KB)
  • パーティショニング利用時のユニークキー利用制限
  • オンラインスキーマ変更

また、VPストレージエンジンはSPIDERにとっても、欠かすことの出来ないパーツであると言える。先日、DeNA Technology Seminar #1に参加したときzigorou氏「いったんShardしたデータベースを、もう一度単一のデータベースに集約するにはどうすればいいか?」という旨の相談を受けたのだが、その答えはここにある!!VPとSPIDERを活用すれば、そのようなスキーマ変更は自由自在なのだ。しかも全てオンラインで!!

というわけで、是非皆さんもVPストレージエンジンを活用して、幸せなMySQL DBA生活を送って頂きたい。

0 コメント:

コメントを投稿