Redisトランザクションの実装と制約事項

Redisトランザクションの基本概念

Redisトランザクションは複数のコマンドを単一の操作として実行する仕組みです。すべてのコマンドは順序付けられ、他のコマンドによる割り込みが発生しないよう直列化して実行されます。

主要なトランザクションコマンド

コマンド機能
MULTIトランザクション開始を宣言
EXECトランザクション内の全コマンド実行
DISCARDトランザクション中断
WATCHキーの変更監視
UNWATCH監視状態の解除

トランザクション実行フロー

  1. 開始: MULTIコマンドでトランザクション開始
  2. キュー登録: コマンドを実行キューに追加(即時実行されない)
  3. 実行: EXECコマンドでキュー内コマンドを一括実行

特性と制約

  • 分離性: トランザクション実行中は外部コマンドの割り込み不可
  • 原子性保証なし: 一部コマンド失敗時も後続処理は継続
  • エラーハンドリング:
    • EXEC前エラー: 全コマンドがキャンセル
    • EXEC後エラー: エラーコマンドのみ失敗

楽観的ロックによる競合制御

WATCHコマンドの動作原理

WATCHで監視したキーがトランザクション実行前に変更されると、トランザクション全体が中止されます。これは楽観的ロックの実装であり、競合状態を検出します。

監視パターン実装例

WATCH account_balance
current_balance = GET account_balance
MULTI
SET account_balance (current_balance - 100)
EXEC

CAS(Compare-and-Swap)の概念

RedisのWATCHメカニズムはCAS操作に類似しており、以下の要素で構成されます:

  • メモリ値(V)
  • 期待値(A)
  • 更新値(B)

V == Aの場合のみVをBに更新し、不一致時は操作を中止します。

ABA問題への対応

値がA→B→Aと変化した場合、標準のCASでは検出不能です。RedisではWATCHによるキー監視でこの問題を回避します。

JavaでのAtomicStampedReference実装

public boolean compareAndSet(
    Object expectedRef, 
    Object newRef, 
    int expectedStamp, 
    int newStamp
) {
    ReferencePair<Object> current = internalPair;
    return expectedRef == current.reference &&
           expectedStamp == current.stamp &&
           ((newRef == current.reference && 
             newStamp == current.stamp) ||
            updatePair(current, newRef, newStamp));
}

監視解除のタイミング

EXECまたはDISCARD実行後、すべてのWATCH監視が自動的に解除されます。明示的な解除にはUNWATCHを使用します。

タグ: redis Transaction watch cas AtomicOperation

7月13日 16:25 投稿