5月に開催されたBacon Conferenceで,bitlyのアプリケーション開発リーダのSean O’Connor氏は,毎月600億クリックを処理する分散システムの開発を通じてbitlyの開発者たちが学んだ,最も価値ある教訓について説明した。
分散システムとは何か?
分散システムを定義する3大特性は,氏によれば,Wikipediaで簡単に見付けることができる。
- コンポーネントノードの真の並行性。これによってノード間の同調に関連するコストと複雑性が発生する。
- 共通クロックの不在。このため,異なるノードで発生したイベントを時間順に並べることは不可能になる。
- 障害の独立性。これはノード障害がシステム内の他のノードに影響を与えない,という能力として理解されるべきだ。
従って分散システムの構築では,これらの特性を扱うことを目標にする必要がある。 ただし氏の意見として,システムの分散的特性に起因する複雑性を,実際には分散化されていないように見せかけるために,抽象化によって隠ぺいすることを一義的な目的としたアプローチは時代遅れだ。このようなアプローチでは失敗は避けられない,分散システムの特性が抽象化から漏出するのは時間の問題だからだ,と氏は言う。そうではなく,システムの分散的な特質をモデル化して,それが外部に漏れても処置可能な抽象化が必要なのだ。
ビルディングブロックとしてのサービス
Bitlyのアーキテクチャはサービスの概念を中心に定義されている。 サービスとは,明確に定義された機能を,APIを通じて提供することに特化した抽象化である。分散システムにおけるサービスとは,コードに対する関数のような存在だ,と氏はいう。実装の詳細をすべて知らなくても,より高度なレベルで考えることを可能にする。この発想は,物事を考える方法をシフトさせることになる。
システムを小規模なサービスの集合体でモデル化することのメリットとして,氏は次のようなものを挙げる。
- コード行数でのサイズを減少することにより,サービスが理解の容易なものになる。
- 障害の独立化。すなわち,サービスがダウンした場合でも特定の機能の提供能力を失うだけで,システム全体としては稼働を維持することができる。
- システムのどの部分に問題が発生しているかを容易に特定できる。
非同期メッセージング
システムのスケール性を保証する上で重要なのが,非同期メッセージの利用だ。他のノードから返送される応答を待つ必要がなくなると同時に,ノード間にメッセージキューが存在することでノードの独立性も向上する。
これを行うメリットのひとつは,ノードに障害が発生して一時的にすべての着信メッセージを処理できなくなったような場合でも,可能な限りメッセージをキューに保持することができる点だ。ノードの障害が他のノードに直接影響しないことも利点のひとつだ。
しかしながら非同期メッセージングには独特の複雑性があるため,特定の処理については同期的な処理の方が自然である場合も少なくない。この例として氏は,bitlyのURL短縮が完全な同期処理として実装されていることに言及した。この処理では可能な限り短時間で行うという要件と同時に,一貫性,すなわち異なるユーザに同じ短縮URLを返送しないことも必要だ。その一方で,分析処理に関しては,完全な非同期処理の対象とするのに適するような,まったく別の要件がある。そのためbitlyでは,リンクでのユーザ行動に関連する測定データの収集と処理を行う場合には単にキューに流すのみとして,最終的に所要時間をあまり意識せずに処理する方法を採用している。本来は同期的な処理を非同期にモデル化することは,非常に複雑なものになる可能性がある,と氏は指摘する。オペレーションの本質を事前に理解しておくことが必要だ。
最後に氏はノードのインタラクションについて触れて,メッセージをひとつのノードから別のノードに流れるコマンドであるとする考え方に対して,イベントとしてモデリングすることで得られるメリットについて言及した。イベントとは,どこかで発生したある事象を表現するものであって,送信するノードが受信ノードについて何かを知る必要はない。一方で,もしメッセージがコマンドならば,送信するノードは受信ノードが実行可能なコマンドについて理解している必要がある。このような理由から,メッセージをイベントと解釈することは,ノードの独立性に大きく貢献し,複数のコンシューマ(受信側)や新たなコンシューマの動的な追加および削除を無理なくサポート可能にすると同時に,プロデューサ(送信側)ノードがコンシューマについての情報を持つ必要もなくなる。
メッセージをイベントと考えることで,メッセージに対するアノテートがプロデューサ側でのフィルタリングより優れているという,新たな認識が導き出される。この例として氏が挙げるのは,プライベートリンクとパブリックリンクの処理だ。プライベートリンクは必要のないノードに到達しないように,プロデューサ側でフィルタリングすることができる。だだしこのためには,どの下流ノードが情報を必要としているのか,プロデューサ側で仮定を立てることが必要だ。bitlyではその代わりに,プライベートリンクにそのようなアノテーションを付けている。その上で,下流のノードがそれを適切に扱うとの前提に立って,関連するメッセージを自由に送出している。
サービスの統合動作性
bitlyでは次のようなサービスを開発することで,サービスの統合動作を保証している。
-
指定されたサービスがビジーあるいはオーバーロード状態であることを,バックプレッシャを通じて要求元ノードに通知することで,以降の要求を制限できるようにする。これによってシステムの正常性の維持と,連鎖的なエラーの防止が可能になる。この例として氏が挙げたのは,サービスキャッシュのウォームアップだ。キャッシュのウォームアップ中に連続して要求が到着すると,データ損失の危険性が生じる。
-
サービスの正常性に応じたロードバランス要求。bitlyでは,ロードバランスとサービス障害の監視に自社のhostpoolライブラリを使用して,サービスの正常性を優先させている。
監視
このトピックの導入として氏は,"分散システムでは,あなたがその存在を認知さえしていないコンピュータの障害が,あなたのコンピュータを使用不能にすることがあり得る"とした,Laslie Lamport氏の言を引用している。400台以上のサーバが稼働するbiltyにおいて,サーバ監視は基本的な作業である。何かが期待通りに動作していないことを知るための,それが唯一の方法だからだ。
氏は監視に関するいくつかのレシピを提供する。
- サーバ状態のチェックにNagiosを使用すること。
- 整合性チェックを実行して,サービスが適切なデータを返していることを確認すること。
- 中央の位置にログインすること。さまざまなノードからすべてのログを集めることで,何が起きているかを解析,診断することが可能になる。
- 関連情報を適切な人々から,適切なタイミングで取得すること。bitlyでは,自社のnsqメッセージングプラットフォームをWeb UIとともに使用することで,デプロイ中に何が起こっているかを容易に確認することが可能になっている。
bitlyは,ソーシャルネットワークやSMS, Eメールなどを対象としたURL短縮サービスである。URLの短縮に加えて同社では,参照リンクに関する情報分析も行っていて,これが同社のビジネスモデルの中心となっている。