最も単純なレベルでは、スケーラビリティは何かをより大きな規模で行う(source)、と言うことです。より多くのユーザリクエストに応答したり、より多くの作業を実行したり、より多くのデータを処理したり、といったことになるでしょう。ソフトウェアの設計というのは複雑です。しかし、そのソフトウェアがより多くの作業が出来るように作成することにも、一連の問題が存在します。この記事では、スケーラブルなソフトウェアシステムを構築するためのいくつかの原理とガイドラインをお伝えします。
1. 処理時間を減らせ
アプリケーションが行う作業の量を増やす一つの方法は、個々の作業単位が完了するまでにかかる時間を減らすことです。たとえば、一つのユーザリクエストを処理するのに必要な時間を減らすことは、同じ時間内でより多くのユーザリクエストを処理することが出来るということを意味します。以下に示すのは、この原理が適切な個所と、実現を可能にするいくつかの戦略の例です。
- コロケーション : データとコードを回線設備の整った施設に設置することで(コロケーション)、作業に必要とされるデータのフェッチに関連するオーバヘッドを減らしましょう。
- キャッシング : データとコードをコロケーションすることが出来ないのなら、データを何度もフェッチするためのオーバヘッドを減らすためにキャッシュしましょう。
- プーリング : 高価なリソースをキャッシュすることで、それを使用するのに関したオーバヘッドを減らしましょう。
- 並列化 : 問題を分解し、個々のステップを並列化することで、ひとつの作業単位を完了するのにかかる時間を減らしましょう。
- パーティショニング : コードをパーティショニングし、関連するパーティションをコロケーションすることで、関連する処理をできるだけ近くに寄せて集中化を行いましょう。
- リモーティング : 例えば、インターフェースをより疎粒度にすることで、リモートサービスへのアクセスにかかる時間を減らしましょう。それはまた、リモート対ローカルは切り替え可能なものではなく、明らかに設計上の決定であるということを忘れず、分散コンピューティングにおける第一の法則 - あなたのオブジェクトを分散させない - ということをよく考えるという点でも価値があります。
私たちはソフトウェア開発者として、必要とされていないところにも抽象化やレイヤを作り出してしまう傾向があります。そう、これらのコンセプトはソフトウェアコンポーネントを分離させるための偉大なツールです。しかし、特に各レイヤにおけるデータ表現を変換しなければならない場合、それらは複雑さとパフォーマンスへの影響を増加させる傾向があります。したがって、処理時間を最小化するための他の方法は、抽象的になりすぎず、レイヤを多くしすぎないよう努力することです。加えて、私たちが普段から慣れ親しんでしまっているランタイムサービスのコストを把握するのも重要な事です。なぜなら、それらが特定のサービスレベルに達していない場合、結局これらがアプリケーションのボトルネックになってしまう可能性があります。
2. パーティション
ここまでで、特定の作業単位に関した処理時間を減らすことをご理解いただけたかと思います。しかし、単一プロセスのデプロイでは限界に達してしまった時、最終的にはあなたはシステムをスケールアウトさせる必要が生じることでしょう。典型的なWebアプリケーションでは、ユーザリクエストを処理するための Webサーバを追加して、それらの間で負荷分散させるだけ、というくらいにスケールアウトが容易な場合もあります。しかしあなたは、アーキテクチャの一部が問題個所になってしまうと言う事を発見するでしょう。なぜなら同時にすべての部分が忙しくなるのですから。最も良い例が、すべてのWebサーバの後ろに控えている単一のデータベースサーバです。それがボトルネックになり始めたとき、あなたはアプローチを変える必要があります。これを行う一つの方法としては、パーティショニング戦略を採用することです。分かりやすく言うと、これは単一の部分からなるアーキテクチャを、より管理しやすい小さな塊に分解することです。パーティショニングで一つの要素をより小さな塊に分けることにより、それらをスケールアウトすることができます。このテクニックはアーキテクチャをスケールさせようと努力しているeBayのような大きなサイトで実際に用いられています。パーティショニングは良い解決策ですが、一貫性に関してはトレードオフが生じる(source)ということをあなたは発見することでしょう。
システムをどのように分割するかは、状況によります。真にステートレスなコンポーネントは、単純にスケールアウトし、それら - 理想的には、コンポーネントの活性化しているインスタンス全て - の間で負荷分散させることが可能です。一方、もし管理が必要なステートが存在するのであれば、各インスタンスが作業やデータの異なるサブセットを管理する場合でも、それらのステートフルなコンポーネントのインスタンスを複数持つことができるような、作業負荷の分割戦略を見つける必要があります。
3. スケーラビリティは並列性の問題である
スケーラビリティは、本質的に並列性の問題です。結局、それはより多くの作業を同時に行うことについての問題なのです。Enterprise JavaBeans(EJB)の初期バージョンのような技術は、単純化したプログラミングモデルを提供することを試み、シングルスレッドのコンポーネントを書くよう勧めていました。不幸なことに、通常こうしたコンポーネントはほかのコンポーネントに依存しますが、これが並行処理の問題を引き起こしました。もし並行性がきちんと考えてなければ、あなたのシステムはすぐにデータがおかしくなってしまいます。一方、並行性をあまりに避けようとすることは、事実上シリアルな処理しか行えないシステムとなってしまい、スケール可能な度合いを制限する事になります。並列プログラミングを行うのは難しい事ではありませんが、スケーラブルなシステムを構築するときの助けになる、いくつかの単純な原則が存在します。
- ロックを保持しなければならない場合(例えばローカルオブジェクトやデータベースオブジェクト等)、ロックの保持は出来る限り短い時間にするように努力してください。
- 共有リソースへの競合を最小限にし、実行時のクリティカルパスではいかなる競合も発生しないようにする事を心がけてください(例:作業を非同期で行うようスケジューリングするなど)
- どのリソースが安全に共有できるのか、どこがスケーラビリティ上のボトルネックとなりうるのかを良く理解するために、並列性に関するあらゆる設計は前もって行っておく必要があります。
4. 要件を知っておく
素晴らしいソフトウェアシステムを構築するためには、あなたのゴールは何なのか、あなたが目指しているものは何なのかを知る必要があります。機能要求はしばしば良く知られていますが、非機能要求(やシステムの品質)は通常欠落しています(source)。もしあなたが高度にスケーラブルなソフトウェアを作る必要が本当にあるなら、あなたはクリティカルなコンポーネント/ワークフローを作るのに先立って、以下のような物事を理解する必要があります。
- 対象となる平均/ピーク時のパフォーマンス(例えばレスポンスタイムやレイテンシなど)。
- 対象となる平均/ピーク時の負荷(例えば同時実行ユーザやメッセージの量など)。
- パフォーマンスとスケーラビリティの許容できる限界値
パフォーマンスがクリティカルな要件でないとしても、出来るだけ早くこうした情報を知っておく必要があります。なぜならスケーラビリティを扱うためのアプローチは、パフォーマンス要件に影響されるからです。
5. 継続的にテストせよ
一度要件を理解してしまえば、ソリューションの設計や構築を始める事が出来ます。私たちが考えだす設計や、私たちが書くコードは本質的に静的であり、実際に実行されるまでは、それがどのように動作するのかをはっきりと語る事は出来ません。この理由により、パフォーマンスとスケーラビリティに関する全ての決定は証拠に基づくべきであり、その証拠はプロジェクトが開始されてから継続的に収集され、レビューされたものである必要があります。言い換えると; システムを通じて計測可能なゴールを設定し、実際のパフォーマンスを検証・計測し、プロジェクトの全段階でパフォーマンスを考慮するようにしてください。
最も良くあるミスの一つは、システムのパフォーマンスとスケーラビリティに対する視点が、私たち自身の経験や耳学問で曇らされてしまう事です。システムの非機能要求を満たすことは、プロジェクトにおけるその他の決定を見直す必要が生じる一つの原因になります。例えば非機能要求のせいで、標準的でないものや、「主流や流行とは言えない何か」の使用を選択するはめになるかも知れません。非機能要求により、アーキテクチャの選択から宗教的・政治的な要素を排除し、証拠に裏打ちされた事実だけがアーキテクチャを決定づける事になるでしょう。
6. 前もってアーキテクチャを構築せよ
スケーラブルなシステムを構築するための最も重要な原則は恐らく、もしあなたのシステムにスケーラブルな特性を持たせたいのであれば、前もって設計しておく必要があると言う事です。多くの人々(私を含む)が陥ってきた落とし穴の一つは、特にJ2EEの初期においてですが、あなたはアプリケーションを構築したら、自動的にスケールアップ/スケールアウトさせる事が出来るだろう、と言うものでした。スケールアウトするよう設計されたアプリケーションは、ほとんどの場合スケールアップします。しかし、スケールアップするよう設計されたアプリケーションは、ほとんどの場合スケールアウトしないのです。多くのアプリケーションは、よりパワフルなハードウェア上で動かす事でスケールアップできます。しかし、スケールアウトはより複雑な問題です。例えば、アプリケーションのインスタンス間でどうやってデータの一貫性を保てば良いのでしょう?そして、シングルトンやシンクロナイズドなコードブロックを、プロセスを横断して動かすにはどうしたら良いのでしょう?
もちろんこうした物事を、フォーターフォールスタイルで前もって巨大な設計をする(source)のと同様に考える必要はありません。繰り返しでアジャイルなプロセスは、問題を解決するために必要十分 な事(source)を行えるフレームワークを提供してくれるので、私たちの助けになります。とにかく実践的でいてください。スケーラブルなアプリケーションを設計する段階で、いかにきちんと考えていようとも、自分自身を信じず、可能な限りコードを書いてテストするようにするのが常にベストです。
7. より大きな状況を見る
最後に、より大きな状況を見る事を忘れないでください - 木を見る前に森を見てください。細かいコードレベルでコンポーネントをチューニングするのに我を忘れるのはとても簡単ですが、本当に最適化を必要としているのはシステム全体なのです。ローカルなパフォーマンスを犠牲にしても、エンド・ツー・エンドのパフォーマンスとスケーラビリティにフォーカスしてください。ボトルネックを特定するのにプロファイリングツールを使う必要があるのなら、そうしてください。しかし、あなたがエンド・ツー・エンドのパフォーマンスからの視点を持つまでは、これを始めないでください。パフォーマンスは、システム全体のレイテンシの集合と逆比例の関係にあります。そのため、負荷と関連してレイテンシを増加させる、あらゆるオペレーションがパフォーマンスに対する問題となり得ます。そうはいってもやはり、パフォーマンスやスケーラビリティの目標を満たすために格闘しているなら、正しいアーキテクチャを選択したのだろうか、と疑問を抱く事には価値があります。もう一度いいます。より大きな状況を見据えて、誰かがアーキテクトの役割(source)を果たすよう努力してください。
まとめ
この記事は、スケーラブルなアプリケーションを構築するための原則やガイドラインを数多く記しており、ソフトウェア開発プロセスの異なる側面を広くカバーしています。スケーラブルなシステムを構築しようとしている全ての人に贈る最高のアドバイスは、システムを明確に捉え、設計する必要があると言う事です。スケーラビリティは魔法ではありませんし、タダで手に入るものでもありません。最後に注意しておく事として、高速なハードウェアがあなたのみを守る事が出来るかもしれない、と言うのは真ですが、それを当てにしないでください!
この記事について
この記事で紹介した原則の多くは、2005年末にイギリスのロンドンで開かれた、アーキテクト向けのプライベートなサミットでの、スケーラビリティに関する議論におけるいくつかの覚え書きを元にしています。そのサミットはAlexis Richardson, Floyd Marinescu, Rod Johnson, John Davies, Steve Ross-Talbotらによって組織されました。"JP Rangaswami on open source in the enterprise & the future of information"(source)と題されたビデオもそのサミットからのものです。
著者について
Simonは、Detica社(サイト・英語)のグローバル金融市場グループで働いている実践的なソフトウェアアーキテクトです。Simonは、デスクトップクライアントやWebアプリケーションから、高度にスケーラブルな分散システムやサービス指向アーキテクチャ(SOA)まで、幅広いプロジェクトに従事しています。彼が最も得意とする技術や Javaであり、実践的な技術の権威としてアドバイスを求められたり、ソリューションに磨きをかけるようお呼びがかかったりします; 選ばれたアーキテクチャを定義し、改善し、保証する事は、目的にフィットさせ、非機能要求を満たす事です。SimonはJava EE Webテクノロジーに関するたくさんの本を書いたり共著したりしており、いくつものカンファレンスで講演し、Coding the Architecture(source)と言うWebサイト - ソフトウェアアーキテクチャに関する実践的な視点を提供している - を立ち上げてもいます。
原文はこちらです:http://www.infoq.com/articles/scalability-principles
(このArticleは2008年5月21日に原文が掲載されました)