Cassandraの分散データベースとしての特徴を語る (第2回)writeの一貫性

★★★ Live配信告知 ★★★

Azureでクラウドネイティブな開発をするための方法について、世界一わかりみ深く説明致します!!複数回シリーズでお届けしている第8回目は、「次世代サーバーレスアーキテクチャDurable Functions」と題しまして、サーバーレスアーキテクチャのさらに次を行くAzureのサービス「Durable Functions」を扱います!!
【2021/11/26(金) 12:00〜13:00】

こんにちは。髙岡です。
弊社では、OSS Cassandraの商用版である米Datastaxのライセンス販売及び導入サポートサービスを提供しております。
この度、サービス体制強化の一環として、Datastax社のCassandra認定資格The Administrator Certificationを取得しました。

今後は、Cassandraの面白い機能や特徴を少しずつ紹介してきたいと思います。
尚、Cassandraは、RDBMSと同じ設計思想で構築してしまうとその特徴を活かすことができません。
そのため、RDBMSと同じ設計思想だと失敗しそうな点に注意して説明していきたいと思います。

今後説明するテーマの候補
* 諸事情により予告なく変更される場合があります。

  • 分散型データベースとしての特徴
  • wirteの一貫性
  •  → 今回説明するテーマ

  • readの一貫性
  • Primary Keyの考え方
  • UPSERTについて
  • クラスタのノードの拡張
  • 複数データセンター構成
  • バックアップ・リカバリ
  • 大量データのロード方法
  • トランザクション
  • アプリケーションドライバからの接続方法
  • 今回は、wirteの一貫性をご紹介いたします。

    同じデータを別のノードに複製しても大丈夫?

    同じデータを複数ノードに複製して配置する場合、以下のような素朴な疑問が思い浮かぶのではないでしょうか。

    1. データが更新された時に複製ノードに障害が発生して書き込みできなかったらどうなるのか?
    2. 複数ノードへ同じデータが複製されることを保証してくれる仕組みは無いと困るが大丈夫か?
    3. 他のノードに複製されたデータが何らかの理由でread時に更新されていなかった場合でも、最新データが返ってくるのか?

    今回は1.と2.の疑問に答えるためにwriteの一貫性について説明します。
    3.は次回のreadの一貫性で説明する予定です。

    writeのシーケンス

    まず最初に、writeのシーケンスをCassandra用語を使わない簡易な言葉で説明してみます。

    ここでの例では、データの複製数は3で設定していると仮定します。
    尚、前回のブログで説明した通り、複製数はKeyspace毎に設定します。

    ①クライアントが指定したノードがwriteリクエスト受信する。
    ②受信したノードが複製先のノードを確認する。
    ③そのノードは、writeリクエストデータを複製先の3つのノードに送信する。
    ④wirteリクエストを受け取ったノードのテーブルのデータがwirteされる。
    ⑤ノードがwirte成功の応答を返すと、クライアントが指定したノードにwirte成功の応答が返る。
    ⑥クライアントが指定したノードが、クライアントにwirte成功の応答を返す。

    このシーケンスを正確に理解するためのCassandra用語を説明します。

    coordinator node
    coordinator nodeは、クライアントからリクエストを受けるノードです。
    coordinator nodeの役割は多岐にわたりますが、ここの説明を理解するという目的に限定して説明しますと、クライアントからwrite等のリクエストを受けて複製先のノード送り、成功または失敗の結果をクライアントに返す役割を担っている、と理解してください。
    尚、CassandraはMaster/Slave型ではないので、どのノードでもcoordinator nodeになることができます。

    Partition
    CassandraはPartition単位で複製先のノードを決定します。
    Partitionはこの時点ではPrimary Keyと考えてください。必ずしもPartition=Primary Keyではありませんが、ここでは、とりあえずPartition=Primary Keyという前提で読み進めていただければと思います。
    CassandraにおけるPartition、Primary Keyの考え方は、非常に重要な概念なので、詳細は別の機会に説明します。

    これらの用語を使ってwriteのシーケンスを言い換えます。

    ①coordinator nodeがクライアントからwriteリクエストを受信する。
    ②coordinator nodeがwriteリクエストデータのPartition値を元に複製先のノードを決める。
    ③複製先のノードにwriteリクエストを送信する。
    ④wirteリクエストを受け取ったノードのテーブルのPartitionのデータがwirteされる。
    ⑤ノードがwirte成功の応答をcoordinator nodeに返す。
    ⑥coordinator nodeは、クライアントにwirte成功の応答を返す。

    ⑥について、誤解を招かないようにするための補足説明します。

    “ 複数ノードに同じデータがwirteされる場合、全ノードのwirteが成功したことを確認してからクライアントに成功したと返答すべきだよね ”

    と直感的に考えたくなるかと思います。図の例でもそのように表現しています。
    しかし、Cassandraでは、

    “ 複数ノードに同じデータがwirteされる場合、全ノードのwirteが成功したことを確認しなくても、一部のノードのwirteが成功したことをもってクライアントに成功したと返答する調整ができる ”

    のです。
    Cassandraは、CAP定理の一貫性 (Consistency)を調整できるということです。

    以下の図は、⑤のシーケンスでのwirte成功の応答がノード1のみから返ってきており、ノード2とノード3が返さなくてもよい一貫性のパタンです。

    全ノードが応答を返すことをもってwirte完了とする条件としてしまうと、クライアントへの応答性能が悪くなることや、一部のノードに障害が発生した場合にシステムの可用性が低下することが想定されます。
    一貫性を調整することによって、応答を返すノードは1ノードであってもクライアントにwirte成功の応答を返す、とする設定も可能なのです。
    一貫性は、性能や耐障害性とのトレードオフとして調整する必要があります。

    複数ノードへの分散配置の挙動を確認

    実際にデータを更新してみて、複数ノードへのwirteの複製に関する挙動を確認してみます。
    上記の図で例として挙げた5ノードクラスタは作成済みです。

    また、3ノードに複製するように、Keyspaceを作成済みです。
    Keyspace「killr_video」では、データセンター「east-side」の3ノードに複製するという設定をしました。

    まずは、デフォルトの一貫性の設定を確認してみます。

    これは、先の説明で、

    “ 複数ノードに同じデータが複製される場合、全ノードのwirteが成功したことを確認しなくても、一部のノードのwirteが成功したことをもってクライアントに成功したと返答する調整ができる ”

    に該当し、クライアントにwirteが成功したことの応答を返すのは全3ノードでなくてもよくて、1ノードでよいという一貫性の設定です。

    サンプルデータとして、以下のデータを挿入済みです。

    このデータは、以下の3ノードに分散配置されております。

    updateしてみます。

    成功しました。

    それでは、

    “ 複数ノードに同じデータがwirteされる場合、全ノードのwirteが成功したことを確認してからクライアントに成功したと返答すべきだよね ”

    に該当するケースを試してみます。


    複製先の3ノードの内、172.18.0.4と172.18.0.6の2ノードをダウンさせます。
    7行目と8行目のDNがダウンしているという意味です。

    “ 複数ノードに同じデータがwirteされる場合、全ノードのwirteが成功したことを確認してからクライアントに成功したと返答すべきだよね ”

    に該当する一貫性に変更します。

    「CONSISTENCY THREE」とは、複製先の3ノード全てからの応答が必要という一貫性です。

    updateしてみます。

    失敗しました。
    エラーメッセージの中に、「Cannot achieve consistency level THREE」と記載されております。

    では、失敗したwriteは取り消されるのか? rollbackすべきでは?と考えたくなるかと思います。

    安心してください、writeが取り消させることがありません。
    CassandraにはHinted Handoffという仕組みがあり、writeの複製に失敗したノードが復活した時に備えて、coordinator nodeがwriteできなかったデータを一定期間保持してくれます。保持期間はデフォルトで3時間です。

    coordinator nodeが保持しているhintsデータの例です。

    2ノードへのwriteの複製ができなかったので、2つのhintsファイルをcoordinator nodeが保持しています。
    複製に失敗した2ノードが復旧すると、coordinator nodeはhintsファイルから2ノードに対してwriteの複製を実施して復旧します。復旧が終わるとhintsファイルが消えます。
    ログには、以下のようなメッセージが出力されます。

    ここで1点、誤解を招かないようにするための補足説明をします。

    複製先を3ノード、CONSISTENCY ONEで設定した場合、複製先の2ノードがダウンしていてもクライアントには成功と応答する。
    この場合、クライアントに1ノードへのwirteが成功したと応答してしまえば複製先の2ノードが復旧してもwriteされないのか?

    というと、そうではないということです。
    複製先を3ノードと指定していれば、CONSISTENCYの設定に関わらず、全ての複製先へのwriteは裏で実施されます。安心してください。

    まとめ

    このブログの冒頭で記載した素朴な質問に対する回答をまとめてみます。

    1. データが更新された時に複製ノードに障害が発生して書き込みできなかったらどうなるのか?
    2. 複数ノードへ同じデータが複製されることを保証してくれる仕組みは無いと困るが大丈夫か?

    <回答>
    データがwriteされた時に複製ノードに障害が発生してwriteできなかった場合には、coodinator nodeがhintsファイルとして障害中にwriteできなかったデータを保持してくれます。
    障害復旧後は、このhintsファイルからwriteするはずだったデータを復旧したノードにwriteします。このような仕組みがあるため、複数ノードへ同じデータが複製されることが保証されるのです。





    ご覧いただきありがとうございます。
    ブログの最新情報はSNSでも発信しております。
    ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



    >> 雑誌等の執筆依頼を受付しております。
       ご希望の方はお気軽にお問い合わせください!


    ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

    役に立った 役に立たなかった

    0人がこの投稿は役に立ったと言っています。

    Be the first to comment

    Leave a Reply

    Your email address will not be published.


    *