2chに学ぶCGMとDBMSとの相性(データのローカリティはとても重要)

もう一ヶ月以上前の記事だけど,ニコニコ動画が1000万コメントを達成したというニュースがあった.

「24日で1千万コメント突破! 「ニコニコ動画」が好調」

ドワンゴグループの1社で、メールポータルなどの事業を企画運営しているニワンゴは8日、同社がサービスを提供している「ニコニコ動画」(ベータバージョン)に投稿されたコメント数が、
オープンから24日で1,000万件を突破したことを発表した。また、1日のページビュー数が2,000万を突破していることもあわせて発表した。

http://www.rbbtoday.com/news/20070208/38344.html

ニコニコ動画のすごいところは動画キャプション部は
システム的に掲示板とほとんど同じで,おそらくその場に
リアルでいる人の数はせいぜい数十人とかなのに,さも数100人
とかがその場にいるような臨場感を与えているところだと思う.


モバゲーやMixi2chなどの盛り上がりを見ていると,人間には
やっぱり共通の話題で盛り上がりたいという根本的な欲求が
あるんだろうなぁとか思う.


そんな話はサテオキ,かねてよりCGM系のシステムとRDBMSって相性よくないなぁと思っていたので,
今回はそれについて.


例えば10万個のスレッドが同時進行していて随時書き込みが発生してるような
2chライクな掲示板を考える.このようなシステムはデータ的にこんな特性をもつ.


1. 新たなスレッドが定期的に立つ
2. 1000に達成しないスレに関してはユーザからのアクセスが定期的に発生しつづける,
3. 1000までいったスレッドに関しては一定期間のアクセスののち,ほとんどアクセスされなくなる.


さてここで具体的なディスク上のデータレイアウトについて考えてみたい.
ここでは仮にメッセージテーブルのデータ構造を下記のように定義する.

create table messages(
  id serial,
  thread_id integer,
  title varchar(256),
  body  text
);

PostgreSQLのようにinsertやupdateに対してディスクの上書きではなく,
追記を行っているような実装になっているDBにランダムにレスがつくとすると,
レコードのディスク上のデータレイアウトは下記のようになる.
これをみると同一スレ内の書き込みが連続した領域にないことが理解できると思う.




図1 各スレッドへの書き込みが連続してない様子



ここであるスレッドのデータを全部見る操作をするとどうなるだろう?
PostgreSQLの場合ストレージの読み込み単位がデフォルト8KByteに
なっている.これはある1レコードを読み込んだ場合,そのレコードのある
ディスクの位置から8Kを必ず読むということを意味する.

その結果意味のないReadが発生することになり,DB内のキャッシュがかき
消される結果になってあまりうまくない.PostgreSQLが8Kを読むのは
テーブルスキャンなどの時に先読みなどを行いたい為だが,今回の様な
ケースではそれが裏目に出ているということになる.



図2 1つのスレッドの情報を集めるのに無駄なReadがかかっている様子


その一方2chのデータストレージ(?)の実装は1スレ1datファイルという実に男らしい
設計になっている.これは一見原始的に見えるかもしれないけれど,データが
ディスク上に常に連続しているため,データのローカリティの確保という点では
とても優れている.


RDBMSでこれをやろうと思うと,1スレの全データを1カラムに格納するという手がある.

create table message_boards(
  id serial,
  title varchar(256),
  body  text
);

これなら1スレッドのデータはディスクの連続した領域に格納されるので,
上記のような無駄なメモリ使用は発生しない.


「お前はDBの正規化というものを知ってるのか?」という意見があるかもしれないが,
状況によっては「そんなにDBの正規化が大事か?」というケースもあると思うので,
DBのキャッシュがかき消されて1000倍以上遅いディスクアクセスになるデメリットと
正規化を維持することのメリットをきちんと天秤にかけてデータ設計は行っていきたい.
DBはただのストレージにすぎないのだから.



なお「それmemcachedでキャッシュ取ればできるよ」はたぶんその通りです.
ただmemcachedの各言語のBindingではWrite Through(Cacheを変更したら
ちゃんとオリジナルも変更する)ような形にはなってないようなので,
その作りこみはそれなりに大変かもしれない.

(おしまい)