クエリーのタイムスタンプ

異なるクエリーからの同じ列値に対する操作の優先順位は、タイムスタンプに基づいて決定されます。

異なるクエリーからの同じ列値に対する操作の優先順位は、タイムスタンプに基づいて決定されます。DataStax EnterpriseおよびCassandraでは、各ミューテーション(更新、挿入、削除)に精度がマイクロ秒単位のタイムスタンプが割り当てられ、それに基づいて各操作が相対的に順序付けされます。異なるクエリーからの同じカラムの値に対する操作の優先順位は、以下のとおりです。

  1. 最新のタイムスタンプを持つデータ。
  2. 操作のタイムスタンプが同じ場合、削除は挿入および更新よりも優先されます。
  3. それ以外の場合は、辞書的に値の大きいデータが優先されます。たとえば、1よりも2が優先して選択されます。

タイムスタンプは、ドライバー・クライアントまたは要求をコーディネートするサーバー側ノードによって割り当てることができます。DataStaxドライバーの最新バージョンはすべて、DataStax Enterpriseバージョン4.7以降ではデフォルトでクライアント生成のタイムスタンプを使用します。クライアントのタイムスタンプはCQLネイティブ・プロトコル・バージョン3で導入されたため、古いバージョンのDSE(および2.1より古いApache Cassandraのバージョン)では、サポートされていません。

1つのクライアントの観点から操作の順序を予測可能な状態に保つために、クライアント側のタイムスタンプの生成がデフォルトです。ドライバーは、クライアント側のタイムスタンプを単調に増加させることにより、すべての操作が、そのインスタンスのスコープ内で実行された順番どおりに書き込まれるようにします。

クライアントのタイムスタンプがないと、クライアントはコーディネートを行うノードによって割り当てられたタイムスタンプに左右されます。コーディネートを行うノードは、内部システム・クロックに基づいてタイムスタンプを割り当てます。分散システムでは、異なるノードのシステム・クロックの同期を維持することは困難です。各ノードは、たとえNTPやその他のクロック同期ソフトウェアを使用している場合でも、数十ミリ秒から数秒の範囲のクロック・ドリフトの影響を受けます。

たとえば、サーバーのタイムスタンプを使用する次のシナリオを考えてみます。

  1. クライアントは以下のクエリーを実行します。
    DELETE FROM tbl_a WHERE key = 0
    クエリーがノードAに送信され、タイムスタンプ10の削除ミューテーションが作成されます。
  2. その後、クライアントは以下を実行します。
    UPDATE tbl_a SET x = ‘hello’ where key = 0
    クエリーがノードBに送信され、タイムスタンプ9の更新ミューテーションが作成されます。
  3. クライアントは実行し、
    SELECT x from tbl_a where key = 0
    0行の結果セットを受け取ります。

ステップ3でSELECTクエリーから行が返されなかったことは驚きです。ステップ1のDELETE操作は、ステップ2のUPDATE操作の前に実行されました。最大のタイムスタンプ(10)が割り当てられていたため、優先されたのです。このシナリオは、クライアントのタイムスタンプを使用することで完全に回避されます。

ドライバーでタイムスタンプの生成を構成する

クライアントのタイムスタンプの生成は、各ドライバーで構成または無効にできます。各ドライバーの詳細については、個々のドライバーのマニュアルを参照してください。

1. ドライバー用のクライアント・タイムスタンプの生成
C/C++ C# Java Node.js PHP Python Ruby

サーバーのタイムスタンプを使用した方が良い場合

クライアントのタイムスタンプを使用することで考えられる1つの欠点は、クライアント・アプリケーション・サーバーの数がプロダクション環境のDataStax Enterpriseノードの数を上回ることが多くなることです。同じDSEクラスターを使用する異なるアプリケーションが異なるチームによって管理されることは珍しいことではありません。このような場合、多くの異なるクライアント・アプリケーション・サーバー間でクロックの同期を維持することは、運用上難しい場合があります。

非同期クライアント・アプリケーション・サーバーのクロックは、クライアント・ノード間の予想されるクロック・ドリフトよりも小さい時間内に、他のクライアントと同じパーティション値を更新するクライアントがある場合にのみ問題になります。この場合でも、この時間内で行われる更新が、実行順に適切に順序付けられていることが重要でない場合があります。これらの更新は、互いを認識していない別々の関係者によって行われた可能性があります。順序が重要な場合は、軽量トランザクションを使用することを検討してください。

軽量トランザクションとクライアント・タイムスタンプ

軽量トランザクション(LWT)を実行すると、それらの操作に割り当てられたクライアント・タイムスタンプは破棄されます。これは、DSEが、割り当てられたタイムスタンプがすべてのLWTにわたって単調に増加することを保証するために別々のタイムスタンプ・ジェネレータを維持するためです。

ユーザーがよく犯す過ちの1つは、LWTの使用と他のミューテーション操作を1つのテーブルに混在させてしまうことです。特に、通常の操作に使用されるタイムスタンプ・メカニズムは、サーバーのタイムスタンプを使用する場合でも、LWTで使用されるタイムスタンプ・メカニズムとは異なるため、これは推奨できません。

サーバー間でクロックの同期を維持する

タイムスタンプ戦略に関係なく、DataStaxは、NTPなどのサービスを使用して、データ・エコシステム内のすべてのマシンでシステム・クロックの同期を維持することを強く推奨します。また、DataStaxは、組織がプロダクション環境のすべてのサーバー間のクロック・ドリフトの程度を測定および理解して、ノード間に存在する可能性のある時間枠を理解することを推奨します。サーバー間のクロック差を測定するには、clockdiffntpdate -qntp -qなどのユーティリティとコマンドを使用します。