MySQLをファイルシステムとして使う
Fedora、openSUSE、UbuntuにはMySQLfsのバイナリー・パッケージは含まれていない。したがって、MySQLfsを使うにはソースからビルドする必要がある。また、あらかじめmysql-develとfuse-develをインストールしておかなければならない(FUSEにより、一般のプログラムがLinuxカーネルを介してファイルシステムを開示できるようになる。つまり、任意のアプリケーションからFUSEファイルシステムが直接使えるようになる)。develパッケージに不足がある場合、configureでエラーが発生するが、これが若干の混乱を引き起こすことがあるので注意されたい。たとえば、私がFedora 8 64ビット・マシンで試行したときはmysqlclient_rのリンクに失敗した。これはFUSE開発パッケージがなかったのが原因だ。つまり、このエラーによりリンカーのフラグに-L
が生成されたために、mysqlclientテスト・プログラムのリンクに失敗したのだ。また、ビルドではデフォルトで-Wall -Werror
が含まれているため、警告メッセージが発生した時点でビルドは直ちに中止される。これを回避するため、-Werror
を外してコンパイルし、必要な開発パッケージがすべてインストールされていることを確認しておく。MySQLfsがビルドできたら、make install
コマンドでMySQLfsを/usr/local/binにインストールする。
MySQLfsを使用できるようMySQLデータベースを設定する手順を以下に示す。ここで、make install
では、schema.sqlファイルがファイルシステムのどこにもインストールされないことに注意。あとでほかのMySQLfsデータベースを設定する場合はこのスキーマをどこかにコピーしておかなければならない。
# mysql -p mysql> CREATE DATABASE mysqlfs; mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON mysqlfs.* TO mysqlfs@"%" IDENTIFIED BY 'foobar'; mysql> FLUSH PRIVILEGES; mysql> Bye # mysql -uroot -p mysqlfs < /tmp/mysqlfs-0.4.0-rc1/schema.sql
データベース・スキーマは、tree、inodes、data_blocksという3つのテーブルから成る。treeはinodeの子から親への対応だ。テーブルの一部を下に例示する。
以下の例は、guten/alice13a.txtというファイルをインポートしたときのものだ。treeテーブルはファイルシステム中のファイルやディレクトリーの階層を表現しており、この場合ファイルalice13a.txtはディレクトリーgutenの中にあり、ディレクトリーgutenはMySQLfsファイルシステムのルートの下にあることを示している。inodesテーブルにはstat(2)で得られるすべての情報が、data_blocksテーブルにはファイルの内容がバイト列として格納されている。
mysql> select * from tree; +-------+--------+----------------------+ | inode | parent | name | +-------+--------+----------------------+ | 1 | NULL | / | | 2 | 1 | guten | | 3 | 2 | alice13a.txt | ... mysql> select * from inodes; +-------+-------+---------+-------+-----+-----+------------+------------+------------+----------+ | inode | inuse | deleted | mode | uid | gid | atime | mtime | ctime | size | +-------+-------+---------+-------+-----+-----+------------+------------+------------+----------+ | 1 | 0 | 0 | 16877 | 0 | 0 | 1201155861 | 1201155861 | 1201155861 | 0 | | 2 | 0 | 0 | 16888 | 500 | 500 | 1200108244 | 1200108244 | 1201156234 | 0 | | 3 | 0 | 0 | 33184 | 500 | 500 | 1200108239 | 1200108239 | 1201156234 | 153477 | ... mysql> describe data_blocks; +-------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------------+------+-----+---------+-------+ | inode | bigint(20) | NO | PRI | | | | seq | int(10) unsigned | NO | PRI | | | | data | blob | YES | | NULL | | +-------+------------------+------+-----+---------+-------+
FUSEでは非正規な動作を行うファイルシステムでもマウントできるため、カスタムFUSEファイルシステムのマウントは、通常、fuseグループに明示的に追加されたユーザーに制限される。次に示す手順は、FUSEファイルシステムをマウントしようとして拒否され、対処しているところだ。この場合、自身をfuseグループに追加してからログインしなければならない。MySQLfsファイルシステムとデータベースは当初は空だが、dfコマンドを実行すると、カーネルがこのファイルシステムのマウントを認識していることがわかる。最後にfusermountコマンドで、ユーザーが作成したFUSEファイルシステムをアンマウントしている。
$ mkdir ~/mysqlfs $ mysqlfs -ohost=localhost -odatabase=mysqlfs ~/mysqlfs * Opening logfile 'mysqlfs.log': OK fuse: failed to open /dev/fuse: Permission denied $ su -l root# usermod -a -G fuse ben root# exit $ exit ... $ id uid=500(ben) gid=500(ben) groups=492(fuse), ... $ mysqlfs -ohost=localhost -odatabase=mysqlfs ~/mysqlfs * Opening logfile 'mysqlfs.log': OK $ ls -ld mysqlfs drwxr-xr-x 1 root root 0 2008-01-24 16:24 mysqlfs $ df -h mysqlfs . Filesystem Size Used Avail Use% Mounted on mysqlfs 0 0 0 - /home/ben/mysqlfs /dev/sdc3 16G 4.4G 11G 31% /home $ ls -l mysqlfs total 0 $ fusermount -u mysqlfs
以上でMySQLをファイルシステムとしてマウントする環境が整った。次に、ファイルをMySQLデータベースにコピーし、ファイルシステムを操作してみよう。下に示した例では、まず、Project Gutenbergのテキスト・ファイルをMySQLfsにコピーし、読み出してMD5チェックサムが一致することを確認。次いで、44MBもあるLinuxソースのtarballをMySQLfsにコピーしてパフォーマンスを調べている。
ディスク・キャッシュが空の状態のとき、/tmpにあるtarballを同じ/tmp上でバックアップするには約2秒かかっている。MySQLfsにコピーした場合は約20秒だ。直後に同じテストを行うと、tarballがディスク・キャッシュに残っているため、/tmp上でのバックアップは約0.3秒に短縮したが、MySQLfsへのコピーは20秒で変わらない。これは、MySQLfsにとって書き込みのパフォーマンスが大きな障害になりうることを示している。一方、読み出しのテスト結果を見ると、MySQLでも一部のデータをキャッシュしているようだ。テストを繰り返すと処理時間が短くなる。このことから、読み出しの多いファイルシステムであれば、MySQLfsは検討に値すると思われる。MySQLのキャッシュ機能を活用できるからだ。
~]$ cp -av /.../guten ./mysqlfs/ `/.../guten' -> `./mysqlfs/guten' `/.../guten/alice13a.txt' -> `./mysqlfs/guten/alice13a.txt' `/.../guten/boysw10.txt' -> `./mysqlfs/guten/boysw10.txt' `/.../guten/dmoro11.txt' -> `./mysqlfs/guten/dmoro11.txt' ~]$ cd ~/mysqlfs/guten guten]$ ls -l -rw-r----- 1 ben ben 153477 2008-01-12 13:23 alice13a.txt -rw-rw---- 1 ben ben 48923 2008-01-12 13:23 boysw10.txt -rw-rw---- 1 ben ben 259214 2008-01-12 13:23 dmoro11.txt guten]$ md5sum * 135e06ad31b169065bccbf03ec7236f2 alice13a.txt 7dd30f1b37e32cdb5d21fe992bbf248d boysw10.txt 87c05f11193c0e05b3d0dec0808a0450 dmoro11.txt guten]$ md5sum /.../guten/* 135e06ad31b169065bccbf03ec7236f2 /.../guten/alice13a.txt 7dd30f1b37e32cdb5d21fe992bbf248d /.../guten/boysw10.txt 87c05f11193c0e05b3d0dec0808a0450 /.../guten/dmoro11.txt guten]$ cd .. mysqlfs]$ time cp /tmp/linux-2.6.23.tar.bz2 . real 0m16.278s user 0m0.006s sys 0m0.531s mysqlfs]$ time cat linux-2.6.23.tar.bz2 >/dev/null real 0m0.502s user 0m0.004s sys 0m0.035s mysqlfs]$ time dd if=linux-2.6.23.tar.bz2 of=/tmp/junk bs=1024 count=1024 1048576 bytes (1.0 MB) copied, 0.0200973 s, 52.2 MB/s real 0m0.058s user 0m0.003s sys 0m0.013s mysqlfs]$ time dd if=linux-2.6.23.tar.bz2 of=/tmp/junk bs=1024 count=1024 skip=9000 1048576 bytes (1.0 MB) copied, 0.0214207 s, 49.0 MB/s real 0m0.031s user 0m0.001s sys 0m0.011s
FUSEファイルシステムにはきわめて不利だが、Bonnie++ファイルシステム・ベンチマーク・スイートを実行してみた。仮想マシン上で実行したため、仮想化による線形的な遅延が発生するだろうが、MySQLデータベースも/tmpも同じ仮想ディスク・デバイス上にあるためパフォーマンスの比較は可能だ。
結果を下に示す。これからわかるように、Bonnie++(バージョン1.03a-7)の実行では、MySQLfsの処理速度は/tmp/bonnie(ext3)の10分の1程度。このパフォーマンスでは、maildirを直接MySQLfsに格納しようとは誰も思うまい。ただし、Bonnie++はネイティブ・カーネル・ファイルシステム向けに設計されておりFUSE向けではないから、この数字はおよその傾向を表すものと見るべきである。
$ /usr/sbin/bonnie++ -d /tmp/bonnie Version 1.03 ------Sequential Output------ --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP v8tsrv 2G 18155 31 16726 5 13338 6 26207 46 74527 24 9840 144 ------Sequential Create------ --------Random Create-------- -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 24878 94 +++++ +++ +++++ +++ 29018 99 +++++ +++ +++++ +++ $ /usr/sbin/bonnie++ -d ~/mysqlfs/bonnie Version 1.03 ------Sequential Output------ --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP v8tsrv 2G 2615 5 1207 1 1323 1 2143 2 2363 0 138.1 0 ------Sequential Create------ --------Random Create-------- -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 186 2 505 1 296 2 209 2 441 1 282 2
Ben Martin 10年以上にわたってファイルシステムを研究。博士課程を修了し、現在、libferris、ファイルシステム、検索ソリューションを中心にコンサルティングをしている。