2 DURABILITY AT SCALE(大規模における耐久性)
データベースとは一度書き込んだら読み込みができなければならないのですが、全てのシステムはそうはなっていない。
ここでは、クォーラムのモデルの背後にある理論的根拠を示す。
- なぜストレージを分けるのかという理由(WHY)
- この2つ(データベースとストレージ?)を組み合わせが、耐久性、可用性、パフォーマンスのゆらぎの低減の獲得だけでなく、ストレージインスタン群を大規模に管理する際の運用上の課題も解決するという手法(HOW)
2.1 レプリケーションとそれに関連する障害
インスタンスの寿命とストレージの寿命はあまり相関しない。
インスタンスは落ちるしものだし、ユーザーはインスタンスをシャットダウンし負荷に応じてインスタンスサイズを変更したりする。
これらの理由から、コンピュート層とストレージ層を分離することは有効である。
ただし、切り離すとそれはそれでストレージ層のストレージノードやディスクも故障する可能性がある。
なので、ストレージ層の障害に対する回復力を持つために、何らかの形で複製する必要がある。(つまりバックアップ)
大規模なクラウド環境では、ノード、ディスク、ネットワークパスの障害という低レベルのバックグラウンドノイズが継続的に起きている。
これらの障害は、異なる継続時間と異なる影響範囲を持っている。
(例えば、ノードへのネットワークの可用性の一時的な欠如、再起動時の一時的なダウンタイム、ディスク、ノード、ラック、リーフ、スパインネットワークスイッチの永続的な障害、さらにはデータセンターの障害などが考えられます。)
複製されたシステムの障害に対する耐性を得るための1つのアプローチは、下記論文で述べられているようなクオラムベースの投票のプロトコルを利用することである。
http://www.andrew.cmu.edu/course/15-440/assets/READINGS/gifford79.pdf
(データ指向アプリケーション 5.4.1.2 読み書きのためのクオラムでも同じ論文が参照されている)
複製されたデータのアイテムのV個のコピーのそれぞれに投票権が割り当てられている場合、読み取り操作または書き込み操作は、それぞれVrの読み取りまたはVwの書き込みを取得しなければならない。
一貫性を持たせるためには、投票数は2つのルールに従わなければならない。
- 各読み取りは、最新の書き込みの認識をしなければならない。(Vr + Vw > Vとして定式化される)
- この規則は、読み取り対象のノードの集合が書き込み対象のノードの集合と交叉すること(かぶりがあること)を保証し、読み取りには少なくとも1つは最新バージョン(書き込み対象のノード)が含まれていることを保証している。
- データ指向アプリケーション 5.4.1.2 読み書きのためのクオラムも参照
- 各書き込みは、Vw > V/2として定式化された、競合する書き込みを避けるために過半数以上の書き込み対象が最新の書き込みを認識(最新の状態になっている)していなければならない
- 同じデータ項目に対して書き込み操作が並列に発生しないことを保証する。
1ノードダウンに対する耐性を持つための一般的なアプローチは、データを3ノード(V = 3)に複製し、2つの書き込みノード(2/3 過半数以上)(Vw = 2)と2つの読み取りノード(2/3 過半数以上)(Vr = 2)とすること。
しかし、上記の2/3クオラム(V=3, Vw = Vr = 2)では不十分で、Auroraは、V=6, Vw = 4, Vr = 3のクオラムモデルとしている。
Why?
その理由を理解するために、AWSのAZ(Availability Zone)の概念を理解する必要がある。
AZはリージョンのサブセットで、リージョン内の他のAZには低遅延リンクで接続されているが、電力、ネットワーク、ソフトウェアのデプロイなどのほとんどの障害に対して隔離されている。
AWSのAZ(アベイラビリティーゾーン)とは?AZ障害が起きたときどうすればよいのか | CyberAgent Developers Blog
余談ですが、AZの表記について
AWSアカウントに因らずアベイラビリティゾーンを識別できるAZ IDを利用しよう #reinvent | DevelopersIO
データのレプリカをAZに分散させることで、大規模で典型的な障害の様相においては1つのデータレプリカにのみ影響があることが確実である。(これ言い切っているけどまあ、AZを跨いで障害なんて確率的にないよねってことが言い切れるからかな)
これは、3つのレプリカをそれぞれ別のAZに配置するだけで、小規模な個々の障害にだけでなく大規模な障害にも耐性があることを示している。
しかし、大規模なストレージインスタンス群における障害のバックグラウンドノイズというのは、任意の時点で、ディスクまたはノードの一部のサブセットに障害が発生し、修復している最中の可能性があることを示している。
これらの障害は、それぞれAZをまたいだノードで広がる可能性がある。
しかし、火災、屋根の故障、洪水などの一つのAZの障害は、他のAZで同時に障害が発生するとレプリカのクオラムを崩すことになる。
この時点で、2/3 読み取りクオラムモデルでは、2つのコピーが失われ、3つ目のコピーが最新であるかどうかを判断することができない。
これらの2つのことは下記のように言える。
- 各AZのレプリカ内の個別の障害にはそれぞれに関連はなし
- AZの障害はそのAZ内のすべてのディスクとノードと関連している
クオラムは、AZの故障だけでなく、同時に発生するバックグラウンドノイズの故障にも耐性を持つ必要がある。
Auroraでの設計
Auroraでは下記2点に対しての耐性を持つような設計にしている。
- (a)ある一つのAZ全体とさらに1つのノード(AZ+1)がダウンしてもデータ欠損が発生しない
- (b)ある一つのAZ全体がダウンしてもデータ書き込み能力に影響を与えない
Auroraは各データアイテムについて、AZ内で2つのコピーとを持ち、さらに3つのAZで行うため合計6つのコピーを持つようにしている。
Auroraでは、6つのコピーを使って、投票数 6 (V = 6)、書き込みクオラム4/6(Vw = 4)、読み取りクオラム3/6(Vr = 3)のクオラムモデルを使う。
このモデルでは下記が満たせる。
- (a) 1つのAZと1つのノード(つまり3つのノードの故障)ダウンではデータ読み取りは損なわれない
- (b) 任意の2つのノード(一つのAZ障害はこれに含まれる)ダウンでは書き込みは損なわれない
読み取りクオラムを保証できると、レプリカのコピーを追加して書き込みクオラムを再構築することができる。
分割されたストレージ
ここではAZ+1(つまり3つのノードの故障)が十分な耐久性を提供するかどうかという問題を詳細にみていく。
このモデルで十分な耐久性を提供するためには、平均復旧時間内に、関連のない障害が二回(二重障害)発生する確率が十分に低いことを保証する必要がある。
これには平均復旧時間(Mean Time to Repair - MTTR)と平均故障時間(Mean Time to Failure - MTTF)を使う。
平均復旧時間は故障したものを修理して回復するまでの時間
平均故障時間は故障なしで使⽤できる時間の平均値
二重障害の確率が高いとクオラムが担保できなくなる。
ある期間を超えると、MTTFにおけるそれぞれの障害の確率を下げることは難しい。
代わりに、Auroraでは二重障害に対して脆弱な期間(window)を縮小するためにMTTRを削減することに注力している。
これを実現するために、データベースボリュームを小さな固定サイズのセグメント(現在のサイズは10GB)に分割した。
これらのセグメントを6個複製してProtection Groupt(PG)に配置します。
PGは論理的なブロックで、3つのAZにまたがる6つの10GBのセグメントで構成され、各AZに2つのセグメントがある。
参照 : Introducing the Aurora Storage Engine | AWS Database Blog
一つのストレージボリュームはPGが連結されたセット。
実際の実装は、SSDがアタッチされたEC2を仮想ホストとしプロビジョニングされた大規模なストレージノード群です。
ストレージボリュームを構成するPGは、ストレージボリュームの増加に応じて割り当てられる。
当時は、複製なしを基準とするとで最大64TBまでのストレージボリュームをサポートしている。
(6つのコピーがあると実質おおよそ10TBってことかな)
今は128TBまで拡張されています。 aws.amazon.com
現在、10GBのセグメントはバックグラウンドノイズの障害と修復を行う単位。
Auroraを運用する上で、これらの障害を監視し自動的に修復している。
この10GBのセグメントは、10Gbpsのネットワークリンク上で10秒以内で修復することができる。
EC2でネットワーク帯域10Gbpsはでる。
クオラムが失われるのは、10秒のウィンドウ内に2つの障害が発生することに加えて、2つの障害が起きているAZ以外のAZで1つ障害が発生する必要があります。
(3ノード故障のことをいっているのかなと思っています)
AWSの中で今まで見てきた障害率と今管理しているデータベースの数からすると、上記の状況が引き起こされる可能性は十分に低いと考えられる。
運用におけるフォールトに対する耐性のメリット
長時間の障害にも耐えられるシステムを構築すると、それは短時間の障害にも耐えるということになる。
AZの長時間の障害に耐えられるストレージシステムは、電力に関するイベント(定期停電とか?)やロールバックが必要なソフトウェア障害などの短時間のAZの障害にも対応できる。
クオラムのメンバーの可用性の数秒単位の障害に対応できるストレージシステムは、短時間のネットワークの詰まりやノードへの負荷にも対応できる。
で、AWSのシステムを見てみると、AWSのシステムは障害に対して高い耐性を持っているため、セグメントが使用できない原因となるメンテナンス操作に活かせる。
例として3つが挙げられている。
熱管理
温度が上昇しているディスクやノード上のセグメントの1つを不良としてマークでき、インスタンス群の他の冷えているノードに移行することでクオラムを迅速に修復できようになっている。
OSのセキュリティのパッチ適用、ソフトウェア・アップグレード
OSのセキュリティのパッチ適用は、そのストレージノードでパッチを適用している間は短時間ではあるが利用できない。
ストレージインスタンス群へのソフトウェアアップグレードも同様。
こららは、1度に1つのAZに対して実行し、1つのPGの1つメンバーにのみパッチが当たるようにしている。
これにより、Auroraのストレージサービスではアジャイルで迅速なデプロイが可能になっている。
参照
https://pages.awscloud.com/rs/112-TZM-766/images/D2-05.pdf
(fleetってAWSではインスタンス群的な感じで使われてそうなので、そういう感じで論文を読んでいる)
www.slideshare.net