Tanzu GemFire Deep Dive - データ整合性とGemFire Function
はじめに GemFireは一言で言うと「分散key/valueインメモリストレージ」であり、インメモリストレージとしてアプリケーションの高速キャッシュとして利用が一般的です。例えばデータベース等の永続ストレージへの依存の為充分なレスポンスタイムが得れない場合、頻繁にDBへのアクセスが発生する場合での利用です。アプリとデータストアの間にGemFireを置くことにより、ピンポイントにレスポンスタイム/スループットを向上する事が可能です。この様なユースケースでは開発観点でも利用は簡単で、一般的なREST APIやRDBMSにアクセスするのと同じ要領で、水平スケール可能な巨大インメモリストレージを利用できます。 一方、GemFireの特徴を捉えることにより、単純なメモリキャッシュとしてだけではなくより戦略的にGemFire利用する事が可能です。アプリのメモリ領域を数百GBレベルの巨大メモリグリッドと接続したり、他のソリューションでは困難な超低レイテンシ/高スループットのデータプラットフォームとしても利用できます。今回はGemFireのデータ整合性に対する思想、ランタイム構成、そして活用パターンと事例についてご説明します。 まずはGemFireの設計思想と特徴からご説明します。 分散ストレージとデータ整合性 GemFireは分散ストレージでありながら、データの可用性より整合性を重んじます。 多くの分散ストレージでは分散したデータコピーの同期は非同期処理によって行いますが、これは整合性より可用性を重んじる為です。とはいっても「データが複数ノード上で同じ状態である」事は保証しており、一般的な「データが壊れない/一貫している」という認識に近いものです。(具体的には同じレコードを分散配置したとしてもこれら全てが同じ値に帰結するという事を保証。) 多くのユースケースでは、このレベルの整合性を確保出来ればデータは安全に分散配置でき、またこの処理を非同期で行う事によりWriteのスループットを落とさずにデータを分散配置できます。確かに登録したばかりのエントリーがリストに表示されなかったり、更新したはずの情報がまだ古い状態で表示されたりする事が稀に発生します。ただ一般的にはキャッシュ技術を用いたシステムでは昔から良くある事象である為、ユーザーは無意識にページをリロードすることにより解消してしまうのが常です。UXには影響はありますが業務的な影響はあまりありません。 しかしながら、この整合性では高い並列処理を求められるケースでは充分でないケースが多々あります。 例えば証券の売買取引や飛行機の座席確保といったユースケースでは「全てのユーザーがどのタイミングでどのレコードを参照しても同じ値を見る」ことが業務上の必須非機能要件となり、これが達成できない場合にはビジネスとして成立しません。この要件はシステムのスループットに関わらず要求され、多くのシステムではこの要件の為キャッシュではなくデータベースへの直接参照という選択肢が取られます。 この要件を満たすためにはKleppmann氏の説明する線形化可能性 (Linealizability) を達成する必要があります。GemFireは分散インメモリストレージながらこの要件を満たしています。 上記はMartin Kleppmann氏の線形化可能性に関する考察で表現されている線形化可能性が達成できていないケースの図です。ここではLeaderからFollower1及びFollower2に非同期に更新情報が渡されています。この同期処理が完了する前にこれらFollowerにアクセスしたユーザーが複数いる場合、参照しているノードにその更新が反映されたか否かによって異なった結果が返ってくる可能性があることを示唆しています。 座席が空いている認識で決済を完了したが、実は既に座席は他のユーザーに確保されていた、という事が起こりえます。 GemFireとデータ整合性 GemFireは『Consistency over Availability』を設計思想として謳っており、この線形化可能性を担保する為に以下の制約を設けています。 Writeは常に1ノードのみ許容。...