Twitterの設計論
08-06-10
posted by
石橋秀仁
これは後知恵です。Twitterが最初からこう設計されていればよかったのに、といった意図はありません。ネットベンチャーとして初期の最優先課題は「一日も早くサービスを公開する」ことであり、そのためにRuby on Railsを採用し、インフラ設計を後回しにした、という彼らの判断は妥当なものであったと思います。
そのうえで、しかし他人の事例から学ぶために、自分を当事者と同じ状況と仮定し、どういうことが考えられるか考えてみたいと思います。
Twitterの犯したミスは、彼らの釈明を見る限りではシステムのデザインを誤ったことだ(同時にそのことに気づき、軌道修正を行おうとしていることはすばらしいことだ)。Twitter is, fundamentally, a messaging system. Twitter was not architected as a messaging system, however. For expediency's sake, Twitter was built with technologies and practices that are more appropriate to a content management system.つまり、TwitterはメッセージングシステムをCMSをベースに構築してしまったわけだ。
では、どういうアーキテクチャが良いのか、自分なりに考えてみたいと思います。ぜひみなさんも考えてみてください。
細かい話をするときりがないので、おおざっぱな話になってしまいます。アーキテクチャとはそういうものだと思います。まずおおざっぱな思いつき、構想があって、計算で裏付ける。ナプキン裏の計算−−−フェルミ推定とも言いますが『珠玉のプログラミング―本質を見抜いたアルゴリズムとデータ構造』という本に詳しいです。
さて、Twitterの抱える問題は−−−正確には分かりませんが−−−おそらく「データ件数の増加に伴うRDBMSのパフォーマンス低下」と、多数のユーザが活発に利用することによる「高いトランザクション負荷(QPS: query per second)」を問題にしているような気がします。想像でしかありませんが、この二つを解決するための方法を考えてみたいと思います。
■データ特性の観点
まず、Twitterのデータ(つぶやき)に注目してみました。
Twitterデータ(つぶやき)の特性
・時系列追記データ(並び替えない)
・更新しない(上書き更新という操作がない)
・削除しない(極めて稀にしか削除しない)
・固定長(文字数制限がある)
・トランザクション不要(順番や整合性など気にしなくて良い)
これらの特性を考慮して、どのようなデータ構造を採用するか。
(※くどいようですが、これは後知恵です。Twitterが公開されて、実際にユーザがどう使ったか、それを知っているから、後知恵で私がこう言っているだけです。Twitter公開前の設計時点で、こういうことは分からなかった)
仮に、こういう特性のデータを扱うのだと分かっていたとして、どのようなデータ・ストレージを採用するか。RDBMSは適切ではないような気がします。RDBMSの「データが増えれば増えるほど遅くなる」特性が気になります。とくに索引(インデックス)を使うとその傾向は顕著です。
私なりの思いつきですが、フラットファイルを固定長レコード追記型のデータファイルとして使う方法があります。とても素朴な方法です。C言語の入門書を開けば「バイナリファイルの読み書き」といった項目に載っている例題のような話です。こんなの「第2種情報処理技術者試験」にも出てくるレベルの知識ですが、そうばかにしたもんでもないでしょう。
固定長データ構造のシークタイムはデータ量に関係ない、という利点があります。シークオフセット=レコードサイズ×レコード番号であり、四則演算1回でオフセットを算出できます。また、シーク1回、リード1回のディスクアクセスで済みます。
データ量はどれくらいか。レコードサイズは、
・ユニコードで4バイト×文字数(固定長) ※200文字くらいでしょうか
・投稿者のID(4バイト?)
・時刻(8バイト?)
で1Kバイトには収まりそうですね。1,000件で、たったの1MBですね。例えば、サインアップ時にユーザごとに1MB単位の空のファイルを割当てて、そこに書き込んでいくのはどうでしょう。無駄は多いのですが、画像1枚でも1MBくらいですし、いまどき「ユーザあたり1MB」など誤差のようなデータ量です。(ちなみに1MBを使い切ったらどうするか、というのも面白いトピックですが、細かい話なので省略します。また1MBというサイズの決め方はディスクのI/O、DMAなどから決める方法もあると思います)
ファイルシステムも調整したくなります。ブロックサイズを巨大にしておく。なるべく論理ファイルがストレージ上で物理的に分断されないように。1回のリードで、複数件のデータをまるごと読み込めるように。inodeの木構造を走査するのには時間がかかります。
home画面を表示するロジックはどうなるか。固定長バイナリファイルの連続した10件を読み込むために必要なシークは1回(オフセット=レコード長×レコード番号)、リードも1回(レコード長×10件)で効率的です。
■メッセージング・システムという観点
データの特性という観点のほかに、もうひとつ、システムの使われ方という観点があります。
みなさんはTwitterのhome画面を中心に利用していると思います。この画面が負荷のほとんどを占めるでしょう。書くよりは、見るほうが主体になっている。これは何か。「メーラーの受信箱」です。みなさんが見ているのは受信箱です。時系列で新着メール一覧が表示されている。すべてのメールに件名と本文の区別がなく、中身がそのまま一覧に表示されている。そしてメールの作成と送信は、受信箱と同じ画面からできる。宛先はない。アドレス帳の全員に対して同報配信になる。ただ、アドレス帳というよりメルマガの購読者リスト、パーミションの方向が逆なだけです。
TwitterとはWebメールである。これが「メッセージング・システム」という言葉の意味です。
Twitter is, fundamentally, a messaging system.
そして、受信箱を上述の「固定長レコード追記型」データ構造とすれば、home画面の表示ロジックは、前述のようにシーク1回、リード1回です。
そうなるように、つぶやきをキューイングして、フォローしている全員の「受信箱」に書き込む、といった書き込み処理にしておけばよいでしょう。
(※「みんなのつぶやき」はそれでいいですが、「あなた宛のつぶやき」や「あなたのつぶやき」などもあります。それぞれに別のデータファイルを割り当てる必要がありそうです。あと、新たにフォローを追加したら遡ってデータを修正するのか、とか、問題はいろいろありますが、まあ細かい話はさておき、着想の話をしていますので)
a content management system.
一方、「CMS」とは何か。これは「ブログ」です。当初Twitterは「マイクロ・ブロギング(micro-blogging)」などと呼ばれていました。ブログとは、管理画面から投稿し、それを公開(publish)するシステムです。見るほうではなく、書く方が主体なのです。この発想ならばRDBMSを採用するでしょう。そして、home画面の表示ロジックは、「SELECT * FROM つぶやき WHERE 投稿者=本人 OR reply先=本人 ORDER BY time DESC OFFSET 0 LIMIT 10」といったSQLになるでしょうか。複数回のシークとリードが発生して、要するに大変な処理です。
※参考:Kazuho@Cybozu Labs: フレンド・タイムライン処理の原理と実践
本記事を書き終えてから教えてもらった記事です。くしくも同時に同じような問題について考えた方がいらっしゃるというのは面白い偶然です。私には難しすぎる内容だったので読んでいません。重複する部分があるかもしれません。読み比べると面白いでしょう。私の方が技術的には間違いだらけだろうと思います。
■発想の径路依存性(名付けの大事さ)
もういちど前述の「Twitterデータ(つぶやき)の特徴」をご覧ください。「ブログのシンプル版(マイクロブログ)」と考えたときに、こういう発想になるかどうか。なかなか難しいのではないかと。人間の発想は出発点に縛られるようで、径路依存性(ヒステリシス: Hysteresis)といったりするようです。認知バイアスの一種でしょうか。
当初から「メッセージング・システム」と呼んでいたら、たぶん違う発想になっていたので、ここに書いたようなアーキテクチャを採用したかもしれません。あるいはqmailとかMaildir方式といったメール処理システム(MTA)を使う方法もあります。「TwitterとはWebメール」なのですから。そのときWebサイトはWebメールのUIという位置づけになります。
このように、色々な発想が生まれるべきところが、最初に「CMS」と呼んだばっかりに発想が縛られてしまう。そういったことが、ままあります。気をつけたいものです。
冒頭で紹介した記事から我々が学べるとしたら、既存のカテゴリーに引きずられないこと。自分が作ろうとしているものを「ブログ」と呼ぶことによる自己暗示。独創的なものを作ろうとしている人は、人に説明するとき、既存の似たもので説明する必要があります。ただ、自分で自分の説明に騙されないよう、気をつけたいものです。たとえ仮称でも、安易な名前を付けないことが大事でしょう。有害な名前をつけるくらいなら、Microsoftがやるように地名でも付けておいた方がよいのでしょう。
(※しかし、やはり、これは後知恵です。彼らは当事者として1年間、ひたすら働いた。その結果として得られた洞察が「我々のTwitterは、じつはメッセージング・システムなのではないか」ということなのでしょう。だから、最初から適切な名前を見つける、つまり自分が作っているものの本質を見抜くことは、簡単ではない、と付け加えておきます)
■技術選定は経営判断
ここで述べたアーキテクチャは、固定長で追記型という制約によって高性能を目指しました。その制約があるので非常に特殊な用途に最適化されたものといえます。ブログなどの可変長なデータには向きません。ブログは日進月歩で発展していますから、データベースのスキーマをどんどん変更しないといけないかもしれません。そういう場合、RDBMSならば「ALTER文一発でスキーマ変更」といった柔軟性があります。
ビジネスにおいて柔軟性はとても大事です。技術選定が将来の柔軟な変更を阻むようでは、目先のインフラコストを削減しただけで、大きな経営コストを払っている。ベンチャーは明日が見えない世界です。身軽に方針転換したい。朝令暮改は大いに結構です。そういう身軽さを、たかが事業の一要素に過ぎない技術が縛ってしまうのは本末転倒。技術は事業の道具であり、逆ではありません。(※ちなみに、私自身あまり納得していない理論ではありますが、リアル・オプション理論により「選択肢の価値を金銭評価」することができるといわれています)
ですから、ここに書いた方式がTwitterにとってベストかどうかは、私には分かりません。それはTwitter社の経営判断だからです。外野がとやかくいうことではありません。
※参考:プログラミングとは経営判断の集積である - 分裂勘違い君劇場
ただ、経営的な側面を無視して、「データ件数の増加に伴うRDBMSのパフォーマンス低下」と、多数のユーザが活発に利用することによる「高いトランザクション負荷(QPS: query per second)」だけを問題にしたとき、このような解決策があるのではないか、といった着想です。
■あとがき
もし実現しようと思ったら、排他ロックとか、非同期書き込みとか、いろいろと発展させないと実用にはならないでしょう。突き詰めれば「固定長レコード追記型DBMS」としてTwitterだけでなく汎用的に利用できるミドルウェアになるかもしれません。Twitter以外の用途があれば、ですが。
ここでは、そういう細かい、実装レベルの話は抜きにして、おおざっぱな話をしました。私はエンジニアではありませんから、そういう仕事はエンジニアに譲ります。
私はエンジニアとして出来のいいほうではありませんでした。この記事の内容も「第2種情報処理技術者試験」に毛が生えたような話。世のエンジニア諸兄にとっては技術レベルの低い話かもしれません。
ただ、アーキテクチャとは実現技術の問題ではなく、大局観や戦略や発想の問題だと思います。案外そういうことを苦手にするエンジニアの方が多いようです。根本的に、それは技術の問題ではなく、使われ方や商売のあり方により決まる問題だからだと思います。業務知識といいますか。ですから、技術的にはレベルの低い話かもしれませんが、書かせていただきました。そもそも、Webシステムを作るという時点で、何も考えずにRDBMSを採用する風潮へのアンチテーゼも、少しはあります。固定長バイナリファイルといったローテク知識は誰でも持っているはずですが、それがTwitterと結びつくかどうか、というと、意外と困難があるのではないでしょうか。少しでもヒントになれば幸いです。ご覧いただき、ありがとうございました。
■参考書
珠玉のプログラミング―本質を見抜いたアルゴリズムとデータ構造
■関連記事
秋元@サイボウズラボ・プログラマー・ブログ: fav.or.it創業者による「もしtwitterを作り直すなら」
sklave » Blog Archive » 「フレンド・タイムライン処理の原理と実践」を追試してみた








コメント