セカンダリインデックスが配置されているときにCassandra DBをスケールアップする間違った方法

Cassandraは、多くの理由で私のお気に入りの(管理されていない)デー

すべてのデータベースと同様に、データアクセスパターンに基づいてCassandraを使用する必要があるため、アドホッククエリ用の柔軟なデータベースが必要な場合や、

Cassandraは列指向のDBであり、データクエリが既に定義されている場合は本当に強力です。 CassandraをサポートしているDatastaxは、まずクエリを設計し、次にcassandraでデータモデルを設計することをお勧めします。 列構造の事実にもかかわらず、CassandraはMapsなどの列型として多くのデータ構造をサポートしています。

Cassandraは主キーデータベースであり、主キーのハッシュ値(パーティションキー)に基づいてデータが永続化され、クラスターの周りに編成されることを意味します。 複数のPKを持つテーブルの場合、CassandraはPKの最初の部分のみをパーティションキーとして考慮します。 複合キーの詳細はこちらを参照してください。

より明確にするために、Cassandra DBの最も重要な特性の1つに戻りましょう: それはアーキテクチャであり、SPoFを持っていないという事実です。

Cassandraクラスターはノード(3つ以上)で構成され、それらのノードは一緒にノードのリングを構成します:

六つのノードで構成されるCassandraクラスター(n6)

六つのノードで構成されるCassandraクラスター(n6)

6つのノードを持つCassandraクラスター(n6)

Cassandraのクラスター上の各ノードは”独立して”動作しますが、クラスター用に構成されたreplication factor(RF)構成に応じて、異なるノードが同じデータを格納することができます。

データが永続化される場所(どのノード)を知るために、Cassandraは特定のテーブルのPK列を使用して一貫性のあるハッシュ関数で計算されたハッシュ値(トークン)を

クエリを実行すると、コーディネーターノード(通常はアプリケーションインスタンスの中で最も近いノード)は、リング内のどのノードがデータを持っているかを探 これは、リング内のすべてのノードが読み取りと書き込みの点で等しいマスターレスアプローチについての魔法です。

PKとレプリケーション係数に関するこの概念は、アプリケーションが高負荷条件下にあるときにCassandraクラスターをスケールする方法について理解する

セカンダリインデックス

Cassandraにはセカンダリインデックスの概念もあります。 リレーショナルデータベースでは、特定のテーブルに多くのインデックスを持つことができ、セカンダリインデックスを持つコストは、読み取り操作ではな Cassandraではこれは真実ではありません。Cassandraのセカンダリインデックスは、データモデルが変更され、新しい列に基づいてクエリを実行する必要がある場合に便利で魅力的です。

そのようにして、セカンダリインデックスを使用すると、次のようなクエリを実行できます:

SELECT*FROM my_table WHERE SECONDARY_INDEX=’value’;

セカンダリインデックス

の使用に関する問題シナリオを想像してみてください:あなたはBlackfriday/CyberMondayにいて、Cassandraクラスタはピークイベントに苦しんでいます。 いいだろ?

通常、拡張性の高いアプリケーションでは通常の状況です。 しかし、アプリケーションがセカンダリインデックスを使用してクエリを実行している場合はどうでしょうか?

うん、あなたはポイントを得ました。

Cassandraがパーティションキーを使用してリング内のデータを配布すると言ったときを覚えていますか? これはすでに起こっていますが、問題はクエリにセカンダリインデックスを導入するときです。 セカンダリインデックスはパーティションキーの一部ではなく、Cassandraはパーティションキーを介してデータがどこに存在しているかを知っています。 この種のインデックスを使用するクエリを実行すると、Cassandraが行うことは、クエリを満たすためにリング内の各ノードを探していることです。

実際のシナリオ

ブラックフライデーの間、我々のアプリケーションは高負荷でした。 Blackfridayイベントによって提供される巨大な割引の恩恵を受けたい多くの多くの顧客。

私たちはAPMを見て、すべての分析は私たちの永続性、この場合はCassandra DBにつながりました。 私たちは待ち時間の長い期間を得ましたが、すべての要求ではなく、いくつかのためだけです。

物事を再び通常の状態に戻そうとすると、私たちの最初の操作はCassandraクラスターにノードを追加することでした。

追加しましたが、まだ遅延の問題に苦しんでいます。 質問は、なぜこれがまだ起こっているのですか?

私たちは間違っていました。 それは単純な結論であり、私たちは非常に重要な詳細を気にしませんでした:この動作はすべての要求ではなく、それらのいくつかで起こっていました。

二次索引を考えたら、ビンゴ! それはまさに問題でした。

ノードを追加すると、問題はデータベースに到着するすべてのクエリに関連しておらず、問題は一部にあり、それらはデータベースのパフォーマンスを低下させる それは完全にパレートのものでした。

問題の詳細とそれをどのように軽減するか

Blackfridayイベントの前のある瞬間に、データモデルを変更する必要がありました。 私たちはアプリケーションを地域化し、顧客の地域が私たちにとって重要なことになり始め、製品や地域に基づいてデータを照会する必要がありました。

振り返ってみると、この新しい動作をAPIレイヤー(new query param)だけでなく、Cassandraのデータにアクセスする方法にも反映したいので、実装について非常に貴重であ

そして、なぜ私たちはとても貴重でしたか? クエリ時間がそれほど増加しなかったことを考慮しても、変更を行いました。

この実装では、セカンダリインデックスを使用してクエリ時間を増加させただけでなく、Cassandraのインフラストラクチャをスケールアップしたため、より多くの問題を発生させました。 クラスターにノードを追加すると、データを見つけるために検索するノードが増えたため、問題は指数関数的に増加していました。

この問題を軽減するために、私たちがしたことは、以前に持っていたノードの数を取り戻し、クラスタ内の大部分のノードの複製係数を増やすことでした。

また、読み取り一貫性レベルも一貫性が低いように変更しました。 私たちは*QUORUMを使用していましたが、代わりに1つに変更しました。 これにより、ノードの負荷を下げることができました。

イベントの数日前にアプリケーションを凍結したため、新しいデータ(書き込み操作)がなく、データが現在の状態で一貫していることがわかりました。

翌日とDBモデルの解決策

最終的な解決策の一部として、データベースモデルについて(再)考え、イベント中に緩和パスとして行った変更をロールバックす

イベントの前に、製品ID(PID)をパーティションキーとして使用していましたが、PIDは連番(高い基数)であるという性質のためにPKであるという良い属性を持

新しいフィールド「region」について、Cassandra collectionsデータ型を利用し、各regionのマップをproductテーブルの列として使用しました。

セカンダリインデックスは常に悪い考えですか?

短い答えはいいえです。

もう少しよく説明すると、Cassandraにはローカルインデックスとグローバルインデックスの二種類のインデックスがあります。

名前が言うようにローカルインデックスは、ローカルにのみ存在するインデックスの一種で、ノード内を意味します。 セカンダリインデックスを作成すると、Cassandraは新しい(非表示の)テーブルを作成し、セカンダリがこのテーブルの主キーになります。 この新しいテーブルの可視性は、リング(クラスタ)ではなくノードの観点からのものです。 これは、セカンダリインデックスの場合です。

一方、グローバルインデックスは、そのパーティションキーを介してリング可視性を持っているので、Cassandraは、そのパーティションキーを介してデータがリング内のどこにあるかを知っています。

セカンダリインデックスは、クエリにプライマリインデックスとセカンダリインデックスの両方がある場合、代替になる可能性があります。 その場合、Cassandraはパーティションキーを介してデータがどこにあるか(どのノードか)を認識し、(ローカル)セカンダリインデックスを参照するノード内のローカルテーブル

ここでよく説明されているセカンダリインデックスに関する他のニュアンスもいくつかありますが、ベストプラクティスはデータモデルを非正規化

コメントを残す

メールアドレスが公開されることはありません。