RedisはMULTI、EXEC、WATCHコマンドを使って「トランザクションライク」な機能を実装します。なぜ「トランザクションライク」なのかというと、従来のデータベースのトランザクションとは多少異なるからです。
MULTI、EXECコマンド
取引は通常、開始から終了まで3つの段階を経ます:
- 営業開始
- チームに参加させる
- トランザクション実行
営業開始
MULTIコマンドによるトランザクション・モードの有効化
Redisサーバーはこのコマンドを受け取ると、Redisクライアントのステータスフラグ属性でREDIS_MULTIを特定します。
チームに参加させる
一般的に、RedisサーバはRedisクライアントから送信されたコマンドを即座に実行しますが、Redisクライアントがトランザクションをオープンした後、Redisサーバはクライアントから送信されたコマンドを即座には実行せず、キュー構造に格納します。
コマンドキュー
各 Redis クライアントは、トランザクションキューとキューに入れられたコマンドのカウンタで構成される独自のトランザクション状態を持ちます。
トランザクション・キューの各要素は、コマンド実装関数へのポインタ、コマンド・パラメータ、およびパラメータの数を含んでいます。
トランザクション実行
EXECを使用すると、サーバは直ちにこのクライアントのトランザクションキューを走査し、キュー内のすべてのコマンドを順番に実行し、最後にすべての実行結果をクライアントに返します。
WATCHコマンド
上記の理解では、クライアントから送信されたコマンドをステージングして一緒に実行するだけで、特別なことは何もありません。もし、コマンドキューにあるコマンドが実行される前に、他のクライアントによっていくつかのキーが変更された場合、このトランザクションのセキュリティは破られます。
WATCHコマンドは、このプロセスを強化するチェックサムです。WATCHコマンドは、EXECコマンドが実行される前に任意の数のデータベースキーを監視することができる楽観的ロックであり、EXECが実行されると、監視されているキーのいずれかが変更されているかどうかをチェックし、変更されている場合は、トランザクションの実行を拒否し、クライアントの実行が失敗した旨のNULL応答を返します。
WATCH実施の原則
各Redisデータベースはwatched_keysディクショナリを保持しており、このディクショナリは既知です:
- 監視対象キー
- キーを監視しているクライアント
クライアントがWATCHコマンドによってキーを監視するとき、クライアント情報は、ディクショナリ内の対応するキーのバリューチェーンに挿入されます。
データベースに変更を加えるすべてのコマンドは、実行後にこの関数を呼び出してwatched_keys辞書をチェックし、クライアントが監視しているデータベースのキーのいずれかが変更されたかどうかを確認します。
トランザクションのACID性
従来のリレーショナル・データベースでは、ACID特性はトランザクションの信頼性と安全性をチェックするために一般的に使用されています。
RedisはACIDトランザクションを積極的に実装したくはないようなので、RedisでACIDをトランザクションにマッチさせる試みを以下に示します。
原子性
一般的な原子性とは、これらの操作が一緒に実行されるか、一緒に実行されないかを意味します。
Redisのトランザクションでは、Redisはコマンドをキューに入れ、順番に実行しに行きます。シングルスレッドであるため、他のクライアントが実行したコマンドと実行が重なることはありません。
しかし、Redisのトランザクションにはロールバック操作がなく、実行中に1つのコマンドが失敗しても、そのコマンドは実行され続けるので、まとめて実行しないという要件を満たしていません。
つまり、伝統的な意味での原子性を満たしていないのです
トランザクションのロールバックは複雑な機能であり、Redisの設計意図であるシンプルさと効率性に合致しないため、サポートされていません。
一貫性
トランザクションがAを変更した場合、Bはトランザクションの終了時にA+B=100を満たすように変更されなければなりません。
Redisのトランザクションは従来の原子性を満たさないため、一貫性も満たしません。
アイソレーション
分離とは、トランザクションの同時実行が互いに影響し合わないことを意味します。
Redisはシングルスレッドでトランザクションを実行するため、トランザクションはシリアルに実行され、分離されます。
耐久性
Redisトランザクションの永続化は、実際にはRedisサーバーが使用する永続化モデルに依存します。
- サーバーが非パーシステント・メモリ・モードで実行されている場合、トランザクションは永続化されません。
- サーバーがRDBモードの場合、このモードのトランザクションは永続化されません。これは、サーバーが永続化のためにBGSAVEコマンドを実行するのは特定の条件が満たされたときだけで、操作は非同期だからです。
- サーバが AOF モードで、appendfsync オプションの値が always の場合、トランザクションは永続化されます。appendfsync オプションの値が evertsec または no の場合、トランザクションは永続的ではありません。
この記事は mdniceを 使用して組版されました。