[画像のクリックで拡大表示]

 東京都大田区で開催されているPerl技術者向けカンファレンス「YAPC::Asia 2006 Tokyo」で2006年3月29日,日本最大のソーシャル・ネットワーキング・サイト(SNS)である「mixi」を運営するミクシィのBatara Kesuma(バタラ・ケスマ)取締役最高技術責任者(CTO)が,増え続ける膨大なトラフィックにどのように対処してきたのかについて講演した。カギとなるのは「データベース分割」である。

 mixiのシステムはもともとBatara氏が1人で作り上げたものだ。2003年当時,米国でFriendsterなどのSNSがはやっており,同氏が会社(現在のミクシィ,当時はイー・マーキュリー)にSNSを作りたいと提案したところ認められたという。同氏が開発を始めたのは2003年12月。3カ月でコーディングし,2004年2月にサービスを開始した。

 mixiがサービスを開始すると,すごい勢いでユーザーが増えていった。2カ月後にはユーザー1万人,1日60万ページ・ビューを達成した。「思ったよりペースが速かった」(Batara氏)という。ユーザーは最初の1年間で21万人,次の1年間で200万人以上にふくれあがった。現在は300万人以上になり,1日に約1万5000人のペースで新しいユーザーが増えている。しかも,70%がアクティブ・ユーザー(72時間以内にアクセスするユーザー)であり,ユーザーは1週間に平均3時間20分をmixiに費やしている。日記のレコードは1億件以上あり,1日に50万件以上の新しい日記レコードが増え続けている。これは,秒間約6レコードのペースだ。これに加え,コメントの数は日記レコード数のおよそ4倍におよぶ。

 こうした膨大なアクセスを処理するには,スケーラビリティが大きな問題になる。mixiのシステムはオープンソースのソフトウエアが支えている。Linux 2.6,Apache 2.0,MySQL 4.0/4.1/5.0,そしてPerl 5.8。いわゆるLAMPである。このうち,Webサーバーはサーバーを増やすことで水平にスケールできるのであまり問題にならないという。「問題は,MySQLがスケールしないこと」(Batara氏)である。

 MySQLのスケーラビリティを確保する手段としてまず考えられるのが,レプリケーションである。データの書き込みを行うデータベースと読み出しを行うデータベースを分け,書き込みを行うデータベースから読み出しを行うデータベースにデータを複製する。ただ,レプリケーションは,データの書き込みが多いケースではあまり効果がない。そしてmixiはまさにそのケースに当てはまるという。mixiの日記サービスでは読み出しが85%に対し書き込みが15%,メッセージ・サービスでは読み出しが75%に対し書き込みが25%と,検索系サービスなどに比べると書き込みの割合が高い。

 そこで登場するのが,データベースを分割することによる負荷の分散である。mixiでは,2段階のレベルでデータベース分割を行った。

 まずレベル1では,テーブルの種類によってデータベースを分けた。どのテーブルがどのデータベースにあるかを示すパーティション・マップを用意する。利点は古いデータベースから新しいデータベースへの移行が容易なことだ。欠点はJOINができないこと。MySQL 5にはこの問題を解決するための「FEDERATED table」という機能があるが,当時はまだMySQL 5は正式リリースされていなかった。そこで,SELECTを2回投げる,あるいはテーブルが小さければ複製する,といった方法で対応したという。

 レベル1のデータベース分割後もmixiのトラフィックは増え続けた。その結果,再びデータベースの負荷が大きくなり,再度分けなければならなくなった。これがレベル2である。今度は,ユーザーIDを利用したパーティショニング・キーを用意し,このキーでデータを格納するデータベースを分けた。つまり,ユーザーによってどのデータベースにデータを置くかを変えるのである。

 レベル2には2種類の方法があるという。「マネージャ・ベース」と「アルゴリズム・ベース」である。マネージャ・ベースは,パーティション・マップを格納するデータベースを追加する方法だ。利点は管理が楽であること。欠点は,パーティション・マッピングの際に余計なクエリが一つ発生してしまうこと。一方,アルゴリズム・ベースは,アプリケーションの中だけでパーティション・マップを処理する方法である。利点は,データベースにパーティション・マップの情報を取りにいく必要がないこと。欠点は,管理が難しいことと新しいデータベースを追加する際にトリッキーな方法が必要になることだ。mixiでは,これら二つの方法をテーブルの種類によって使い分けているという。

 ただ,こうしたデータベース分割により新しい問題点も発生した。一つのWebページにいくつもの違うデータベースの情報を表示しようとすると,多くのコネクションが発生してしまうのだ。この問題に対処するため,mixiではメモリー・キャッシュを利用している。具体的には,メモリー・キャッシュを実現するためのmemcachedを,Perlプログラムを動かすためのApacheモジュールであるmod_perlと同じサーバーにインストールしている(2GBのメモリーを積んだ39台のサーバー)。Batara氏によると「mod_perlはCPUを食うが,memcachedはCPUを食わないので,いいコンビ」だという。

 Batara氏は,レベル1とレベル2のデータベース分割をいつ行ったかも明らかにした。2004年10月に日記のテーブルをレベル1分割,2005年3月に日記のテーブルをレベル2分割,2005年4月にコミュニティのテーブルをレベル1分割,2005年10月にコミュニティのテーブルをレベル2分割という順番で行ったという。

 データベース分割の手法については,さらなる改良も検討している。現在は,非常に多くの日記を書いている個人がいてもデータベースを分けられない。そこでタイム・スタンプでデータベースを分散することを考えている。これはマネージャ・ベースのレベル3に相当するという。アルゴリズム・ベースも,よりよいアルゴリズムを探しているという。

 講演後は,聴衆の関心の高さを反映して,多くの質問が寄せられた。例えば「どんなタイミングでキャッシュ・サーバーのデータを変えているのか」という質問に対しては,「データによってエクスパイアの時間はまちまち。よく変更されるものは短く,あまり変更されないものは長くなっている」という回答だった。また「現在の開発チームの規模」を尋ねる質問の回答は「(ミクシィの求人情報サイトである)Find Job!やデザイナなどすべて合わせて20名弱」だった。「なぜPerlを選択したか」というPerlのカンファレンスにふさわしい質問も出た。「(先に開発した)Find Job!でPerlを使っていたので引き続き使った。また,mod_perlのサイトに(米国の玩具ショッピング・サイトである)eToysの資料があり,スケーラビリティのあるシステムを作れると思った。Pythonも考えたが,(Perlの)CPANに比べてライブラリが少なかった」というのがBatara氏の回答である。