7

データ モデルを単純化しすぎると、次のテーブルがあります。

CREATE TABLE storage (
    id timeuuid,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY ((id))
);

CREATE TABLE storage_idx_by_foo (
    foo blob,
    id timeuuid,
    PRIMARY KEY ((foo), id)
);

CREATE TABLE storage_idx_by_bar (
    bar blob,
    id timeuuid,
    PRIMARY KEY ((bar), id)
);

CREATE TABLE storage_idx_by_baz (
    baz blob,
    id timeuuid,
    PRIMARY KEY ((baz), id)
);

最初のテーブルには数億のレコードを含めることができ、インデックス テーブルを使用して、クエリ可能なパラメーターに基づいてデータを簡単に検索します。

問題は、foobar、またはbazのいずれかに基づいてデータをパージする必要がある場合に発生します。ストレージテーブルとすべてのインデックス テーブルからエントリを削除する必要があります。したがって、たとえばfooで削除すると仮定すると、実行される手順は次のとおりです。

  1. 適切なインデックス テーブルに基づいて ID を見つけます (この場合はstorage_idx_by_foo ) 。
  2. barbazを取得し、ストレージテーブルからレコードを削除します
  3. 残りの 2 つのインデックス テーブルからレコードを削除します ( bar / bazidがあります) 。

ステップ 3 は、トゥームストーンが原因で問題になります。残りの 2 つのインデックス テーブルから何百万ものレコードを削除すると (つまり、パーティションによってではなく)、Cassandra は何百万ものトゥームストーンを作成し、圧縮が発生する前にデータを読み取るときに多くの頭痛の種となります。

簡単なブレインストーミングでは、次のことができることが示唆されています。

  1. パージ プロセス後に圧縮を強制する
  2. これらの 2 つのテーブルから削除せず、コード内の存在しないものを指すインデックス エントリを処理します
  3. ????

推奨されるアプローチは何ですか? 他の Cassandra ユーザーもこの問題に遭遇したと思いますが、「Cassandra のやり方が間違っている」以外のアドバイスをオンラインで見つけることができませんでした。この問題を回避するためにデータを別の方法でモデル化することはできなかったと思います (もし可能であれば、それについてのフィードバックもいただければ幸いです)。

現在、私たちはオプション 2 に傾いていますが、データベースにゴミが残るという考えは好きではありません。

4

1 に答える 1

2

「あなたはカサンドラを間違っているかもしれません」!!

あなたの質問は何ですか?クエリを知らずに一般化しようとすると、通常、Cassandra で適切なモデルが得られません。モデリングは実際にはクエリ駆動型でなければなりません。正確なクエリがわからない場合でも、クエリの種類(つまり、何にインデックスを付けているかなど) を知っておく必要があります。

foo、bar、および baz にインデックスを作成することがわかっている場合は、パーティション キーとして機能する制約を追加できるかどうかを考えてください。概説したスキーマの場合、同じ foo 値 (または bar 値または baz 値) のエントリが大量にある場合に遭遇する主要な問題の 1 つです。理論的には、パーティションは非常に大きくなる可能性がありますが、パーティションが数十メガまたは数百メガを超えると、問題が発生する可能性がありますパフォーマンスのために。そのため、幅の広い行を実行する場合は、幅の広い行のサイズを制限する方法を考えてください。各 foo または bar または baz に数百から数千のエントリがある場合、これは問題になりません。そうでなければ、あなたはトラブルを求めています。この場合、バケットの一部を追加することができます。たとえば、クエリを「この日付の foo x のデータを取得する」または「この国/郵便番号などの foo x のデータを取得する」に制限できるかどうかを確認します。これにより、巨大な幅の行が防止されます。

手動インデックス作成のもう 1 つの問題は、インデックスの更新がアトミックではなく、インデックスが実際のデータとは異なるノードにある可能性があることです。クエリをバケットに制限できる場合、スキーマは次のようになります。

CREATE TABLE storage (
    some_bucket text,
    id timeuuid,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY (somebucket, id)
);

または、ストレージをそのままにして、インデックスを次のようにすることもできます。

CREATE TABLE storage (
    bucket text,
    foo blob,
    bar blob,
    baz blob,
    data blob,
    PRIMARY KEY (bucket)
);

どちらの場合も、foo、bar、および baz に cassandra セカンダリ インデックスを作成します。これにより、クエリが許可されます。セカンダリ インデックスを使用する場合は、常に最初にパーティションにヒットすることを忘れないでください。そうしないと、クラスター全体のクエリになり、タイムアウトする可能性があります。Cassandra 3.0 では、グローバル インデックスと呼ばれる機能が登場します。これは、最初にパーティションをヒットする必要性を軽減することを目的としていますが、それまでは、パーティション + セカンダリ インデックスをヒットすると、クエリが高速になります。

さて…墓石の話に移ります。Cassandra の削除では、トゥームストーンが使用されます。それを回避する方法はありません。どの LSM データベースでも圧縮が必要であり、廃棄 (tombstone) は、負荷に関係なく (ほぼ) 安定した書き込みスループットを達成する cassandra のメカニズムです。ただし、できることはいくつかあります。このような大規模な削除が行われるタイミングを制限できる場合、nodetool を使用して自動圧縮を無効にすることができます。

http://www.datastax.com/documentation/cassandra/2.1/cassandra/tools/toolsDisableAutoCompaction.html

その後、パージを実行してから、圧縮を強制できます。

http://www.datastax.com/documentation/cassandra/2.1/cassandra/tools/toolsCompact.html

そして、自動圧縮を再度有効にします。

これは明らかに「きちんとした」ものではありませんが、テーブルから削除するデータが大量にある場合でも機能しますが、すべてではありません。

それが役立つことを願っています。

于 2014-12-29T10:59:24.247 に答える