2016-07-08 5 views
2

私はcsv-filesのバージョンを格納するCassandraのテーブルを持っています。バージョン(パーティションキー)と行番号(クラスタリングキー)の一意のIDを持つ主キーが使用されます。私が新しいバージョンを挿入すると、挿入しようとしているパーティションキーにdeleteステートメントが実行され、不完全なデータがすべて消去されます。次に、データが挿入されます。パーティションCassandraのDELETE/INSERT同時実行の問題

ここに問題があります。アプリケーション内で削除と後続の挿入が同期して実行されても、Cassandraにはまだ並行性のレベルが存在するようです。後で読み込むと、挿入された行が時々見つからなくなるためです。ここではいくつかの事実です:

  • カサンドラ3.0
  • 一貫ALL(R + W)は
  • 火花カサンドラコネクタ
  • ノードの
  • 数使用して
  • 挿入するJavaドライバーを使用して削除します。2
  • レプリケーションファクタ:2

私が実行するdelete文は次のようになります。

私はそれを省略した場合、問題が消える

"バージョン= 'ID' mytableはFROM DELETE"。削除と挿入の間に遅延を挿入すると、問題が少なくなります(欠落行が少なくなります)。当初は、より限定的ではない一貫性レベルを使用しましたが、これが問題だと確信していましたが、問題には影響しませんでした。私の仮説は何らかの理由でdeleteステートメントがALLの整合性レベルにもかかわらずレプリカに非同期的に送信されていることですが、なぜこれがどうなるのか、それを避ける方法はわかりません。

+0

一般に、C *は最終的に一貫性のあるデータベースです。これは、さまざまなことを意味しますが、操作順序に頼ることはできません。従属操作を決して行なわないでください。スキーマを再設計し、アプローチを変更する方がよいでしょう。データモデルを投稿し、達成したいことを説明した場合は、それを手助けすることがあります。あなたの状況で理解できる限り、たとえばクライアント側でデータを取得した後に古いバージョンをフィルタリングするほうがよいでしょう。 –

+0

最終的な一貫性の程度は、自分の選択した一貫性レベルによって制限されると私は予想しています。現在はボトルネックではないため、単純化のためにプロトタイプでALLを使用しています。最も守秘的な整合性レベルで順番に完了する操作のシーケンスに依存できない場合は、整合性レベルをどのように使用できますか? –

+0

ALLは、すべてのノードが照会に関してコンセンサスを持つことを保証します(したがって、その単一の照会の後、すべてのノードは影響を受けた行と同じバージョンを持ちます)が、照会の順序に関しては何も保証しません。私は、あなたのアプローチを再設計し、C *をリレーショナルデータベースとして考えるのをやめてください。それは動作しません。 –

答えて

1

すべての突然変異はデフォルトでその書き込みのコーディネータの書き込み時間を取得します。ドキュメントから

TIMESTAMP:操作のタイムスタンプを設定します。 指定されていない場合、 コーディネーターは、 開始時の現時刻(マイクロ秒単位)をタイムスタンプとして使用します。通常これは適切なデフォルトの です。

http://cassandra.apache.org/doc/cql3/CQL.html

異なる変異をコーディネータが異なる可能性があるので、コーディネーターとの間のクロック・スキューは、他に対して斜めになるように一台のマシンへの変異で終わることができます。

書き込み時間はC *履歴を制御するので、同期挿入と削除を行うドライバを持つことができますが、コーディネータによっては挿入が「前」に行われる可能性があります。

は、2つのノードA及びBを想像し、Bは、時間0でA.

後ろ5第2のクロック・スキューで動作している:クラスタにデータを挿入し、Aは、コーディネータとして選択されます。変異は、Aに到着し、Aは、クラスタ

INSERT VALUE AT TIME 0 

両方のノードがこのメッセージが含まれているとの書き込みを確認要求リターンが成功したのレコードが用意されましたタイムスタンプ(0)

を割り当てます。

時刻2:以前に挿入されたデータに対して削除を発行し、コーディネーターとしてBが選択されました。 Bは、クロックがAの時の後ろに5秒を歪めているので(-3)これは、我々は我々はすべてのノードがこのレコードを受け取ったことを認め

DELETE VALUE AT TIME -3 

のような文で終わることを意味のタイムスタンプを割り当てます。値がまだ存在して削除した後、挿入が発生するので

は今グローバル一貫したタイムラインが

DELETE VALUE AT TIME -3 
INSERT VALUE AT TIME 0 

です。

+0

しかし、私が驚いているのは、削除が整合性ALLで実行されているとすれば、呼び出し元に戻る前にすべてのレプリカで削除を確認すると思います。この問題は、内部的にDELETEを実行する前に戻されるのではなく、タイムスタンプでログに記録され、次のinsert文で順序が乱れて終了するために発生しますか?挿入は私が信じているバッチで起こるので、もし各バッチがそれ自身のタイムスタンプを取得すれば、これは私の観測とよく一致するでしょう。 –

+0

rddベースのコネクタAPIで書き込み時間を設定することがサポートされていますが、その機能はデータフレームベースのAPIから削除されているようです。それには理由がありますか? –

+0

削除は「確認されていません」、セマンティクスが「承認済み」であるためです。タイムスタンプは、あなたが挿入し、別のノードがある場合は、この全体の変異は が これは、すべてのノード に出て送信される「時間5 AT XをDELETE」のようになりますコーディネーター(1つのノード)での変異に適用されますコーディネーターとそのノードが時計に歪んでいる場合があります "INSERT X at 2" これらのメッセージがすべてのレプリカで認識され、ドライバーを介して確認されても、2つのことがDelete - > INSERT 確認されたログは "DELETE INSERT" – RussS

0

私は同様の問題を抱えていますが、INSERTとDELETEリクエスト(実際にはUPDATEを含むすべてのクエリ)に対してLight-Weight-Transactionを有効にすることで修正しました。このパーティションへのすべてのクエリが1つの "スレッド"を通してシリアル化されるようにします。したがって、DELETEはINSERTを上書きしません。

INSERT INTO myTable (instance_id, instance_version, data) VALUES ('myinstance', 0, 'some-data') IF NOT EXISTS; 
UPDATE myTable SET instance_version=1, data='some-updated-data' WHERE instance_id='myinstance' IF instance_version=0; 
UPDATE myTable SET instance_version=2, data='again-some-updated-data' WHERE instance_id='myinstance' IF instance_version=1; 
DELETE FROM myTable WHERE instance_id='myinstance' IF instance_version=2 
//or: 
DELETE FROM myTable WHERE instance_id='myinstance' IF EXISTS 

句が行ごとに光ワイト・トランザクションを有効にした場合は、ので、それらの全てが直列化される:例えば、(INSTANCE_IDを仮定すると、主キーがあります)。警告:LWTは通常の呼び出しよりも高価ですが、この並行性の問題のように、LWTが必要になることがあります。

関連する問題