CAP定理を時間と空間に拡張する「落ちず、速く、信頼できるサービスをどう作るのか?」

Top / テクニカルノート / CAP定理を時間と空間に拡張する「落ちず、速く、信頼できるサービスをどう作るのか?」

落ちず、速く、信頼できるサービスをどう作るのか?

オンプレミスでもクラウド上でも、システムを作る時に次の2つはどちらも「大切だ」と思うことでしょう。

  1. サーバの可用性(落ちないサーバであること)、レスポンス(速いサーバであること)
  2. サーバの一貫性(書いたデータが消えないということ)

しかし分散システムにおいては、実際は「どちらか1つを優先するしかない」というのが、定理上の真理です。

どういうことなのでしょうか?


データの一貫性を過度に重視することが可用性を低下させている

データストアをどのように設計するか?

分散システムを構築するにあたり、「データストアをどのように設計するか」は重要なテーマのひとつです。

残念ながら機械である以上サーバーはいつかは必ず壊れます。複数台のサーバーで構成されているシステムの内で、たった1台のサーバが故障するだけでサービス停止が発生したり(可用性の低下)、データが壊れること(一貫性の低下)によりサービス終了するわけにはいきません。

そこで、データは複数箇所に保存(分散システム)するべきだと考えられます。

しかし、複数のサーバーで共通のデータを持たねばならない場合、次の3つの望まれる性質のうち、2つしか同時に満たすことができません。これを『CAP定理』といいます。

 

CAP
C:Consistency(一貫性)
すべてのサーバーで統一された最新データを持っていること。
A:Availability(可用性)
そのデータの更新に対する高可用性。つまり、常に動いているということ。
P:Partition-tolerance(分断に対する許容)
サーバー同士が分断する状態がありえる、または分断が起きてしまった=許容された状態
※日本では一般に分断耐性と翻訳されることが多くありますが、分断耐性という言葉による混乱が多々見られるので、本ドキュメントでは「tolerance」を「許容」と訳しています。

簡単に説明するため、2つのサーバーに同じデータを保存したい場合を考えます。CAP定理では、『P-A』『P-C』『A-C』の3つのパターンのみが達成可能です。

P-A
サーバーに分断が発生したとき(P=分断が起きてしまった)、可用性(A)を考えて片方のサーバーにだけ書き込みをしてしまうと、2つのサーバーでは同じデータを持つことができません。そこで一貫性(C)が失われます。
P-C
同様にサーバーに分断が発生したとき(P=分断が起きてしまった)、一貫性(C)を考えて2つのサーバーで同じデータにするには、システムを一時停止するしかありません。つまり可用性(A)が失われます。
A-C
分断されていない状態(Pが起きていない)ときのみ、一貫性(C)も可用性(A)も得ることができます。
 

二つのサーバーでCAP定理を考える

例えば、遠隔の拠点(例として2つのデータセンター)にそれぞれサーバーが設置されている分散システムで、データの出し入れなどの協調動作する場合、短時間といえどこれらのサーバー間の通信が分断されることを避けることはできません。したがってシステムの全体設計として、分断(Partition)が起きることを許容(Tolerance)しなければならず、『P』は必須となります。CAP定理に従うと、結果として残りは『A』または『C』のどちらかを選ぶしかありません。

視点を変えて、近距離に設置したの二つのサーバーではどうでしょうか?

『P』を選ぶ必要がない、すなわち分断は必ず起きないと保証されるとき、『A』と『C』は同時に成立するように見えます。データの一貫性が保たれ可用性もある(動作が継続する)。これは理想的なシステムと考えられそうです。

そこで、ミラー化されたストレージサーバー・システムを想像してみましょう。ミラー化されたストレージサーバーでは、一方のストレージサーバーがダウンしてももう一方のストレージサーバーのみで動作を継続するため、一見するとデータ一貫性も可用性も保たれているように見えます。

 

xentec1-2.jpg

具体的に想像するため、ストレージサーバー『1号機』と『2号機』があり、同じデータを書き込むリクエストがあったと仮定します。

システムは『1号機』と『2号機』の両方に書き込み要求をし、その書き込みが完了したという「完了報告」(一般にAcknowledge/アクノリッジといいます)をもらってから、ようやく次のデータの読み書きに移ることができます。

こうしなければ一貫性(C)を保つことができません。

 
xen

ここでもし、『1号機』はすぐに書き込みを完了したが、『2号機』の書き込みが遅れた場合はどうなるでしょうか? 

この場合、『1号機』だけが最新の状態になり、『2号機』はどうなっているのかわかりません。つまりこの瞬間においては分断が発生(P)しているのです。

 

『A』『C』のどちらかを選ばなければならない

あなたがプログラマーだったとしたら、一方のストレージ応答が遅れた場合の処理をどう書きますか? おそらく、できることは次のどちらかか、両方の組み合わせしかないでしょう。

  • 『応答を待ち続ける』
    • この場合は、データの一貫性(C)を保つことを重視していることになります。ただし、『2号機』の書き込み完了を待つ間(Δt)、そのシステムは停止することになるため可用性(A)を失います。
  • 『応答を待たずに進む』
    • この場合は、『1号機』だけで動作を継続することから可用性(A)を重視していることになります。ただし、『1号機』と『2号機』のデータ整合性が崩れるため、一貫性(C)を失います。

つまり、近距離の二つのサーバーであったとしても、プログラマーは分断が発生する前提で『A』『C』のどちらかを選ばなくてはなりません。

※この文書でのΔtは、ある時間t1から、ある時間t2までの間の、一定の時間Δt=t2-t1を意味しています。ここでは、とある一定の時間だと考えれば良いでしょう。

一貫性を保つことで可用性の低下(レスポンス性の低下)が発生する

実際のストレージシステムにおいては、この遅延時間『Δt』はしばしば発生しています。たとえ同じハードウェア・同じソフトウェアのストレージシステムを用いたとしても必ず発生します。上の例では、『2号機』の書き込み遅延が終了するまでの時間(Δt)が分断が発生(P)している時間になります。

これはCAP定理自体を、マクロな時間軸の設計視点から、一定の短い時間(Δt)を考慮したミクロな時間軸の設計視点へ概念を拡張しなくてはならないことを意味しています。ほぼすべての分散システムにおいて、Δtのようなごく短時間の間に、分断『P』が発生したり消滅したりしているのです。したがって、分散システム上で処理を記述するプログラマーは、必ずどこかで『A』と『C』のどちらかを選ぶ必要があります。

現実的なミラーストレージをミクロ的な視点から見ると、書き込み遅延により分断が発生(P)した場合、基本的にはタイムアウトが発生するまでは書き込み完了を待ち続けます。すなわち待つ(停止する)ことでΔtの間の可用性(A)を捨て、一貫性(C)を保つのです。この「Δtの間待つ」という行為が多数発生しているシステムは、マクロ的な視点からは「全体的に遅いシステム」に見えることになります。

なお、タイムアウトが発生してしまった場合は、そのタイムアウトが発生した片系のシステムを切り離します。それにより一貫性(C)が捨てられ、可用性(A)が選択されて動作を継続します。

さて、多くの3-Tier型クラウドシステムでは、ハイパーバイザー層で共有ストレージ(SANストレージ)を利用し、この層で一貫性(C)を担保しようとします。ストレージは、複数のハイパーバイザーから届く様々なリクエストを、一貫性を保ちつつ処理するため、大小様々な遅延を発生させています。

これにより一貫性は保たれますが、マクロの視点からは上述のとおり「全体的に遅いシステム」に見えます。一貫性を重視しすぎることで、可用性の低下(レスポンス性の低下)が発生してしまうのです。

つまり「データ書き込みに安全性があるストレージは遅い」ことになります。

コラム

ミラーストレージのような分散システムでは、片系ストレージでタイムアウトが発生することにより、その切り離しが発生します。このとき、一貫性(C)が失われ、代わりに可用性(A)を選択することになります。タイムアウトにより『P-C』のシステムが『P-A』のシステムへと入れ替わるのです。

これをマクロ視点から見た場合、仮にタイムアウトまでの時間を無視できるのであれば、ミラー化された冗長ストレージシステムは一貫性(C)ではなく、可用性(A)を重視したシステムといえます。

実際には、片系が切り離されデグレードとなった状態で、一端、分散システムから単一系になります。再度、リカバリー(リビルド、リシルバーなど)処理が完了すると、元の冗長された分散システムへと戻ります。

このようにCAP定理は、Δtの長さによって、短い時間の単位で考えるミクロな視点と、全体を見たマクロな視点のどちらでも考えなくてはなりません。


レスポンスの速いサーバ(可用性の高いサーバ)はどう作るのか?

ここまでで、ある一定の時間Δt内に応答を返す必要があるならば、ある段階で「一貫性(C)を捨て、可用性(A)を重視する」しかないことがわかります。「ハイレスポンス」とはいうのは、「ある一定の十分に短い時間Δt内に、システムが応答すること」とも定義できます。これまでの例からわかるとおり、時間軸にCAP定理を拡張するならば、可用性とハイレスポンスとは事実上同義です。したがってハイレスポンスのサーバを作る為には、データ一貫性をある程度捨てなくてはならないことを意味します。

今まで上げたとおり「データ一貫性(C)はどの程度必要か?」を考える必要があります。

そこで今度は時間軸ではなく、空間(エリア)をイメージします。

一般に、書き込んだデータを失う(一貫性を失う)ことは、大問題です。しかし、サービスを役割ごとに分割することで、「あるサーバーにはデータ一貫性が必要」だが「あるサーバーは数時間に一度の更新しか発生しない」など、様々な種類に分けることができます。これが「空間(=エリア)でわけていく」ということです。

例えば、データ更新がない・または少ないウェブサーバーやアプリケーションサーバーであれば、あらかじめ同じデータを持つサーバーを複数用意することで、1台のサーバーがダウンしてもサービスを継続することができ、可用性が担保されています。

また一方、この状態は同じデータが何らかの枠組みで全てのサーバに保存済みであるなら、一貫性が保たれています。

つまり、一貫性も可用性も確保出来ています。なぜ2つとも満たされているのでしょう?それは、この時間のみこれらのサーバの間は数理的に(データ的に)分断されていない為なのです。

同じシステムにおいても、ある時間、ある空間においてだけ、C-A-Pの選択状況が異なることを意味しているのです。

 

xentec3.jpg

一般的なウェブサービスでは、コンテンツの更新頻度と参照頻度を比べた場合、参照頻度がずっと高いはずです。データ更新用サーバーと参照用サーバーを分け、更新用サーバーで更新されたコンテンツを参照用サーバーにコピーするような仕組みを用意することができるのであれば、更新用サーバーは一貫性を重視し、参照用サーバーは可用性を重視することで一貫性と可用性のベストバランスを実現できるでしょう。

※その場合、更新用サーバーから参照用サーバーへとコピーする時間を考慮する必要があります。コピーする時間(Δt)は、更新用サーバーと参照用サーバーのコンテンツに差異がある状態のため、人によってアクセスするサーバがことなり、異なるデータをみる、つまり一貫性が失われることを許容しなければなりません。これが許容できないならば、同期が終わるまでサーバを一時的に停止するしかありません(可用性が失われる)。

 

このように、サービスを構成するサーバー空間を決め、「一貫性が必要なもの」と「可用性を重視・高レスポンス性が必要なもの」にそれぞれ分離することで、エンドユーザーが感じる快適さを大きく向上することができます。言い方を換えると、エンドユーザーからのアクセスが、一貫性が必要なサーバーにアクセスしなければ、サーバーのレスポンスは向上し、快適なサービスができあがるのです。


時間と空間の両方で狭域化する!

可用性、つまり落ちないこと、レスポンスが良いシステムを作ることは、サーバエンジニアの極みです。どのようにすればそのようなシステムを作れるのでしょうか?

その鍵は「狭域化」にあります。時間、空間(エリア)を分割し、小さくしていくのです。時間Δtをなるべく小さくし空間を分割して広域から狭域へと狭めていく。

一貫性の必要な部分を時空で狭域化するというのは、システムが随所に持つ「ロック期間」をなるべく小さくすることを意味します。これを小さくするほど、マクロな視点では高レスポンスなのにデータが安全なシステムが生まれていくのです。

多くのシステムでは、可用性より一貫性が必要なサーバーは全体の中の一部、たとえばデータストア系(ストレージ、レポジトリ、RDB、KVSなどなど)です。一貫性が必要な時間的尺度Δtも異なります。にもかかわらず、システム全てに影響するインフラの中のさらにインフラ層であるSAN層に一貫性を担保させる場合、もっとも広域にCAP定理の空間範疇を決めたことになるのです。これではシステムが全体的に遅く非効率になってしまいます。

だからこそオンプレミスシステムと異なり、クラウドではエフェメラルディスクを用いて高速にやり取りを行い、データストアを別に用意する設計になることが多くなるのです。

自分が利用しているクラウドサービスにおいて、データ一貫性がどのような設計思想で考えられているのか?は重要な指標です。データ一貫性を重視するストレージシステムへの書き込みは、そうでないストレージに比べると遅く、また容量単価も高価になりがちだからです。

 

参考≫ テクニカルノート/超高速なInterconnected Storageを効果的に利用しつつデータを守る方法

 

例えば、当社のストレージサービスでは、次の様な性質を持ちます。

 

当社サービス名優先要件種別設計思想
Interconnected Storage(ICS)独立型
速度特化型
インターコネクト
インターコネクト型で、エフェメラルディスク並の高速性能を持ちつつ永続化されたストレージ。シリコンレベルでの冗長性を持つ
Enterprise Storage(ES)一貫性速度特化型
ネットワーク
Block Storage(ESB)とFile System(ESF)のどちらも切り出すことができる、速度特化型のStorage。ストレージ層はダブルパリティの冗長性をもつ。
Backup Storage(BS)一貫性容量特化型
ネットワーク
Block Storage(BSB)とFile System(BSF)のどちらも切り出すことができる、容量特化型のStorage。ストレージ層はダブルパリティの冗長性をもつ。

参考≫テクニカルノート/永続化されたストレージ (Persistent Storage)とは (ICS/EB/BSは何が違うのか?)
参考≫デザインパターン/High Response Private Cloud用Storageデザインパターンガイド

一般に、ストレージサービスは「データが消えてしまってはいけない」ため一貫性側を重要視します。InfiniCloudのストレージサービスは、全てのサービス内で、それぞれ異なる形、層で一貫性をもっています。もちろんそれぞれにおいて特性は異なります。優先条件に「一貫性」と記述されているのは、そのストレージサービス「視点」において一貫性があるということです。しかしシステム全体を考えるなら、そのストレージサービスを利用する側の視点に立ち、ストレージサービス自体のインシデントの対処方法を考えなくてはなりません。これは、全てのクラウドサービス、オンプレミスシステムにおいて必要な、共通の視点となります。

CAP定理上、一貫性と可用性は同時に成り立たないため、可用性が必要になる場合は注意が必要です。利用するストレージサービスが一貫性に主軸を持っている場合、これまで説明したとおり「反応速度が悪く」なるため、ハイレスポンスではないシステムができあがります。ハイレスポンスではない=Δtのタイムでは可用性は失われています。

ESは速度を重視したストレージサービスですから、求めるニーズに対してESの速度が十分であれば、異なるESを束ね、ニーズを満たす可用性が実現できます。

しかし、独立性が重視されたICSの場合は、相関関係が無く、もっとも高速になる為、異なるICSを束ねれば、もっと高速に可用性は実現できることになります。

つまり、ストレージサービスを利用する側の視点とは、コンピューティングリソース側、当社のサービスではプライベートクラウドサービス側の視点となります。

 

当社サービス名設計思想
High Response Private CloudICSの独立性を生かし、異なるHRPC、ICSを束ねれば可用性の実現は容易となる。
ICS→ESB/BSBに対し、RPOの範囲でのデータ保護は容易。
ESBを利用すれば、HA機能を利用してコンピューティングノード(HRPC)可用性担保は可能(ただし再起動時間の可用性は失われる)。
ESB側は一貫性を重視しているため、ESB側の可用性を担保する場合は、インスタンス内から異なるESで作られたESBに、分散配置する必要がある。
VMware Private CloudICSの独立性を生かし、異なるVMPC、ICSを束ねれば可用性の実現は容易となる。
ESFを利用すれば、HA機能を利用してコンピューティングノード(VMPC)可用性担保は可能(ただし再起動時間の可用性は失われる)。
ESF側は一貫性を重視しているため、ESF側の可用性を担保する場合は、インスタンス内から異なるESで作られたESBに、分散配置する必要がある。
ESFは、ESとBSが持っているストレージレプリケーション機能により、RPOの範囲でデータ保護が可能。
Solaris SPARC Private CloudICSの独立性を生かし、異なるSSPC、ICSを束ねれば可用性の実現は容易となる。
ESBを利用すれば、コンピューティングノード(SSPC)の可用性担保は可能(ただし再起動時間の可用性は失われる)。
ESB側は一貫性を重視しているため、ESB側の可用性を担保する場合は、SSPCから複数のESに分散し、インスタンス内からZFSミラーを行い可用性を担保することが望ましい。ESBは、ESとBSが持っているストレージレプリケーション機能により、RPOの範囲でデータ保護が可能。

一方、なるべく可用性を持ったまま一貫性を持つには、狭域で一貫性を保つことが重要です。独立性のあるストレージサービスであるICSがもつ一貫性はシリコンレベルの一貫性であり、十分なハイレスポンス性をもつためデータストアに関連するサービスだけ一貫性を持つ仕組みにすることに向いています。たとえばHigh Response Private Cloudを利用し、インスタンスの中でミドルウェアレベルで一貫性を保つデータストアサービスを利用すれば、狭域での一貫性を実現しつつ、狭域の可用性も実現できます。

参考として、ミドルウェアで行う分散技術には次の様なものがあります。

  • MySQL
    • グループレプリケーション
  • PostgreSQL
    • レプリケーション
  • Hadoop
  • redis
  • DNS
  • LDAP
  • などなど・・・

これらの分散技術は、それぞれ異なる思想を持って作られているため、それぞれ特徴にあった物を選ぶ必要があります。

一方、インスタンスイメージ(OSのブートイメージ)という単位で一貫性を持ちたい場合は、Solaris SPARC Private Cloudが行っているように、ブートイメージ毎ことなるESから切り出したESBをミラーする手法もあります。この場合、インスタンスの内部の層でミラーを組むことで、一貫性を担保しようとします。


サーバーはいつか必ずダウンする

残念ながら、サーバーはいつかダウンします。そしてダウンしないシステムを構築する銀の弾もありません。

サービスの可用性(≒レスポンス速度)とデータの一貫性は、システムにおいては二律背反で、理想的にはどちらも重視したい事柄です。しかし、現実的には2つが天秤に乗せられている以上、その天秤に全てのシステムを乗せるのではなく、時空を支配し、時間軸でも空間軸でも、なるべく狭域で優先事項を切り替えることで、矛盾する目的は「なんとなく」達成できるようになるでしょう。

システムにおいては、この「なんとなく」が、とても大切なのです。

 

本記事の関連サービス

 

Private CloudPrivate Cloud
StorageStorage
NetworkNetwork