InfoQ

News

Twitter、進化するアーキテクチャ

作者 Abel Avram , 翻訳者 南 伸二 投稿日 2009年7月5日 午後3時0分

コミュニティ
Architecture
トピック
パフォーマンス&スケーラビリティ
タグ
C,
JVM,
Ruby on Rails,
Caching,
Scala

原文(投稿日:2009/6/26)へのリンク

Twitterサービスチームの主任エンジニアであり、主に最適化とスケーラビリティを担当しているEvan Weaver氏が、QCon London 2009においてTwitterのアーキテクチャ、とりわけ過去一年にわたって行ってきたウェブサイトの最適化について語った。

Twitterで使われているツールの多くはオープンソースである。そのスタックは、フロントサイドにRails、中間のビジネス層にC、Scala、Java、データストアとしてMySQLを利用してつくられている。すべてがRAM上に保持されており、データベースは単なるバックアップである。Railsのフロントエンドはレンダリング、複合キャッシュ、DBクエリ、同期的挿入を扱う。このフロントエンドは、MySQLクライアント、Memcachedクライアント、JSONクライアントなどの、多くはCで書かれたいくつかのクライアントサービスを主につなぐ役目も果たしている。

ミドルウェアとしては、Memcached、ページキャッシュとしてのVarnish、Scalaで書かれたMQであるKestrelを利用している。さらに同じくScalaで書かれた、多数のつぶやき(tweets)をトラッキングしようと考えているクライアントが使うCometサーバを利用するための作業が進行中である。

Twitterは“メッセージングプラットフォームではなくコンテンツマネジメントプラットフォーム”として始まっており、そのため、まとめて読むことを基礎にした初期モデルから、すべてのユーザが最新のつぶやきで常に更新される必要がある現在のメッセージングモデルに変更するために、多くの最適化が必要とされた。変更は、キャッシュ、MQ、Memcachedクライアントという3つの領域で行われた。

キャッシュ

各つぶやきは平均126ユーザにトラッキングされている。そのため、明らかにキャッシングが必要である。当初の設定では、APIだけがユーザからつぶやきが届くたびに無効化されるページキャッシュを持ち、残りのアプリケーションはキャッシュレスであった。

image

アーキテクチャの最初の変更は、64ビット整数で直列化されたtweet IDの配列を含むライトスルーキャッシュであるベクターキャッシュ(Vector Cache)をつくることだった。このキャッシュは99%のヒット率を持っている。

2番目の変更は、ユーザとつぶやきのデータベースレコードを含む別のライトスルーキャッシュである列キャッシュ(Row Cache)を加えることだった。このキャッシュは95%のヒット率を持ち、Cache Moneyと呼ばれるNick Kallen氏のRailsプラグインを利用している。Nick氏はTwitterのシステムアーキテクトである。

3番目の変更は、つぶやきの直列化バージョンを含むリードスルーキャッシュである断片キャッシュ(Fragment Cache)を導入することであった。ここで、つぶやきの直列化バージョンとは、APIクライアントを通してアクセスされ、JSON、XML、あるいはAtomでパッケージングされているものである。このキャッシュも同じく95%のヒット率を持つ。断片キャッシュは「直接ベクターを消費し、もし直列化された断片がその時点でキャッシュされていたら、誰かが見ようとして要求したつぶやきの実際の列データをロードしない。そうやって、データベースアクセスを避けて、多くの時間を節約する」とEvan氏は述べた。

さらにもう1つの変更は、ページキャッシュとは分離されたキャッシュプールをつくることだった。Evan氏によれば、ページキャッシュプールは直接的な無効化ではなく、世代型キー手法(generational key scheme)を用いている。その理由は、クライアントは

HTTPのif-modified-sinceを送ることができ、リクエストの中で好きなときにタイムスタンプを押すことができます。また、私たちはその列をスライスして、クライアントが見たいつぶやきだけをクライアントに提供する必要があります。しかし、クライアントが利用した可能性のあるキーをすべてトラッキングしたくはないのです。この世代型手法には大きな問題がありました。なぜなら、すべての無効なキーを削除することができなかったからです。つぶやきの数にしたがってユーザが受け取る各ページが追加されるたびに、キャッシュ内の有効なデータを押し出してしまいます。その結果、私たちのキャッシュは5時間の実効時間しか持つことができませんでした。これらのページキャッシュのすべてがずっと流れ続けているからです。

ページキャッシュがプールに移動されることで、キャッシュミスは50%削減された。

以下の図が現在Twitterによって使われているキャッシュ手法の図である。

image

Twitterのトラフィックの80%がAPI経由であるため、そこには2つのレベルのキャッシュが追加されている。それぞれのキャッシュは、その前の層から来るリクエストの最大95%を提供する。全体のキャッシュの変更は、計20から30の最適化によって達成され、それによってもたらされたものは

10倍のキャパシティの改善でした。もっとできたかもしれませんが、私たちはその時点で別のボトルネックにぶち当たったのです…。私たちの戦略は、まずリードスルーキャッシュを追加し、それが正しいものを無効化することを確かめ、その後で、ライトスルーキャッシュに移し、新しいtweet IDが届くたびごとにキャッシュを壊すのではなく、修復してオンラインにすることです。

メッセージキュー

各ユーザには平均して126のフォロワーがいるので、各つぶやきに対するキューには126のメッセージが存在するということになる。そうでなくても、トラフィックがピークに達する時というのがある。それはオバマ大統領の就任式のときなどで、そのときには、毎秒数百のつぶやき、言い換えるとキューの中に数万のメッセージがあるという状態になり、そのトラフィック量はその当時の通常のトラフィックの3倍の量であった。MQはピークを見つけて、それを時間をかけて分散するようにし、その結果として、さらなる多くのハードウェアの追加をしなくてよいようにする。TwitterのMQはシンプルである。Memcachedプロトコルをベースとしており、ジョブの順序づけはなく、サーバ間の共有状態もなく、すべてはRAMに保持され、トランザクション処理である。

MQの最初の実装はRubyで書かれたStarlingを利用していたが、特に世代型ではないRubyのガベージコレクションのためにうまくスケールしなかった。その結果、ガベージコレクタがその作業を終えるまでの間キュー処理全体がある時点で止まってしまうことが理由でMQがクラッシュした。そこで、MQをより成熟したJVMのガベージコレクションを利用するScalaに移植することが決定された。現在のMQはたった1200行のコードからなり、3つのサーバ上で稼動している。

Memcachedクライアント

Memcachedクライアントの最適化は、クラスターのロードの最適化を目的としたものだ。現在のクライアントが使っているものは、libmemcachedであり、Twitterがその最も重要なユーザであり、コードベースへの貢献者となっている。そのlibmemcachedをもとにして、一年以上かけて断片キャッシュの最適化を行うことにより、1秒間に処理するページリクエストが50倍に増加した。

image

リクエストに局所性がないため、リクエストを処理するもっとも高速な方法は、データを必要なときに各サーバで再処理することではなく、データを事前処理しネットワークRAM上にストアすることである。この手法はWeb2.0のサイトの多くで利用されているもので、それらのサイトはほぼ完全にメモリ上で稼動している。次のステップは、Evan氏によれば、「1年間読み取りのスケーリングを行って、その後、書き込みのスケーリングを行う。それから、複数コロケーションの問題に取り組む」とのことだ。

QConでのプレゼンテーションのスライドがEvan氏のサイトで公開されている

ブックマーク
digg+,
reddit+,
del.icio.us+,
dzone+,
slashdot+
Hatena

特集コンテンツ一覧

Agile Japan 2009

2009年4月22日、東京千代田区にある放送会館で「アジャイルジャパン2009」が開催されました。本イベントは「ソフトウェア開発の次世代リーダーをつくる」ことを合い言葉に、200人以上の参加者を集めてスタートしました。

Flex 4の新機能トップ10

今週(2009年6月1日)AdobeはFlex 4の正式な初ベータ版をリリースしました。Flex 4はGumboというコードネームで開発されています。今回のリリースには大きな変更が多数含まれています。このRIAフレームワークの最新バージョンにおいて変更された事柄についての概要を以下のリストで見ていきましょう。

Domain Driven Design(ドメイン駆動設計) Quickly 日本語版

ビジネス領域の深い理解を反映したドメインモデルを設計するための、ヴィジョンとアプローチです。この本は、Eric Evans氏の「Domain Driven Design」の主要点を短く読みやすく要約しました。

JavaプログラマがFlexとBlazeDSを学んだ方がいい13の理由

この記事ではJavaプログラマがなぜFlexとBlazeDSを学ぶべきなのかについて13の理由を述べています。なぜ高度にインタラクティブなWeb サイトからJavaで開発されたバックエンドをもつエンタープライズ・アプリケーションまでを含む、リッチ・インターネット・アプリケーション(RIA)の開発にFlexとBlazeDSの組み合わせが最適な選択肢となるのかについて述べています。

仮想パネル: バックログは重要な成果物とプラクティスか、それとも無駄か?

Mary Poppendieck氏、Ron Jeffries氏、Jeff Patton氏、David West氏、Steve Freeman氏、Jason Yip氏が、バックログに関する彼らの意見とアジャイルチームを成功させるために必要な事を語った。

Perf4Jを使ったパフォーマンス解析とモニタリング

この記事ではAlex Devine氏が、Java開発者がPerf4Jをどのように利用できるかと、タイミングステートメントにコードを追加し、ロギング、結果の解析とモニタリングを行うオープンソースツールセットの説明をします。

複雑な外部DSLを開発する

本稿では、Vaughn Vernon氏が内部DSLと外部DSLの違いを説明し、複雑な外部DSLを開発する際のステップを示します。

J2EEアプリケーションにおけるAOPを使ったフェッチ戦略の実装

この記事では低レベルのサービス・レイヤやリポジトリ・レイヤを肥大化させることなく、フェッチング・ストラテジによってモジュール化された方法でバックエンドにあるシステムからデータを取得する処理を最適化する方法について説明します。