Redis の事情を徹底的に理解するのに役立つ記事

WBOY
リリース: 2022-11-01 13:48:31
転載
1828 人が閲覧しました

この記事では、Redis に関する関連知識を提供します。主にトランザクションに関する関連コンテンツを紹介します。本質的にはコマンドのコレクションです。トランザクションは、一度に複数のコマンドの実行をサポートします。トランザクション中に、実行プロセスでは、キュー内のコマンドが順番に実行されます。これを見てみましょう。皆さんのお役に立てれば幸いです。

推奨される学習: Redis ビデオ チュートリアル

Redis トランザクションの概要

Redis単純なトランザクション機能を提供するだけです。その本質はコマンドのセットです。トランザクションは、一度に複数のコマンドの実行をサポートします。トランザクションの実行プロセス中、キュー内のコマンドは順番に実行されます。他のクライアントによって送信されたコマンド要求は、トランザクションのシーケンスに挿入されません。このトランザクションによって実行されるコマンド。コマンドの実行処理はシーケンシャルに実行されますが、原子性は保証されません。 MySQL のような分離レベルはなく、問題が発生した後にデータやその他の高度な操作をロールバックできます。これについては後で詳しく分析します。

Redis の基本的なトランザクション手順

Redis では、トランザクションに関連する次の基本的な手順が提供されます。

MULTI トランザクションが有効になると、Redis は、EXEC を使用してこれらのコマンドがアトミック オーダーで実行されるまで、実際には実行せずに後続のコマンドをキューに追加します。 ##EXECトランザクション ブロック内のすべてのコマンドを実行しますDISCARDトランザクションをキャンセルし、トランザクション ブロック内のすべてのコマンドの実行を中止しますWATCHトランザクションが無効になっている場合は、1 つ以上のキーを監視します実行中 これらのキーが以前に他のコマンドによって変更された場合、トランザクションは終了され、トランザクション内のコマンドは実行されません UNWATCHCancelWATCHコマンドはすべてのキーを監視します

全般 この場合、単純な Redis トランザクションは主に次の部分に分かれています。

コマンド

MULTI を実行してトランザクションを開始します。トランザクション開始後、コマンドを実行するための複数のコマンドが順番にキューに入れられ、配置に成功すると QUEUED メッセージが返されます。コマンド EXEC を実行してトランザクションを送信します。Redis はキュー内のコマンドを順番に実行し、すべてのコマンドの結果を順番に返します。 (トランザクションのコミットを中止したい場合は、DISCARD を実行してください)。

次の図は、Redis トランザクションの実行プロセスを簡単に示しています:

サンプル分析

以下でいくつかの実用的な例を見てみましょう。 Redis でのトランザクションを体験してください。また、Redis トランザクションは実際のトランザクションではなく、標準トランザクションの

ACID 特性を完全には満たすことができないことも前述しました。次の例を通して、Redis の「破産バージョン」トランザクションの問題点を見てみましょう。

[A] サブミットの通常実行

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
127.0.0.1:6379> SET b 2
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> GET b
"2"
ログイン後にコピー

トランザクションオープン後、サブミットされたコマンドはキューに追加されます (QUEUED)。EXEC 実行後、コマンドは段階的に実行されますそして結果が返されます。これは、トランザクションの開始やコミットなど、MySQL で通常使用するトランザクション操作に似ていますか?

[B]トランザクションを正常にキャンセルします

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
127.0.0.1:6379> SET b 2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> 
127.0.0.1:6379> GET a
(nil)
127.0.0.1:6379> GET b
(nil)
ログイン後にコピー

トランザクションを開いた後、トランザクションを続行したくない場合は、DISCARDを使用してトランザクションをキャンセルしてください。以前にサブミットされたコマンドは実際には実行されません。となり、関連するキーの値は変更されません。これも MySQL トランザクションに似ており、トランザクションの開始とロールバックに似ています。

[C]監視キー

-- 线程 1 中执行
127.0.0.1:6379> del a
(integer) 1
127.0.0.1:6379> get a
(nil)
127.0.0.1:6379> SET a 0
OK
127.0.0.1:6379> WATCH a
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
----------------------------------------- 线程 2 中执行
----------------------------------------- 127.0.0.1:6379> SET a 2
----------------------------------------- OK
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> GET a
"2"
ログイン後にコピー

トランザクションを開く前に a の値を監視し、トランザクションを開きます。別スレッドで a の値を設定し(SET a 2)、EXEC を実行してトランザクションを実行すると、結果は nil(トランザクションが実行されていないことを示す

)になります。 WATCH 後に a の値が変更されたため、トランザクションはキャンセルされました。

これはトランザクションの開始時間とは関係がなく、MULTI と別のスレッドが a の値を設定する順序とも関係がないことに注意してください。 WATCH後に変化する限り。トランザクションが開始されているかどうかに関わらず、トランザクションを実行(EXEC)するとトランザクションはキャンセルされます。

通常の状況では、EXEC および DISCARD コマンドを実行すると、デフォルトで UNWATCH が実行されます。

[D] 構文エラー

127.0.0.1:6379> SET a 1
OK
127.0.0.1:6379> SET b 2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 11
QUEUED
127.0.0.1:6379> SETS b 22
(error) ERR unknown command 'SETS'
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> GET b
"2"
ログイン後にコピー

Redis がトランザクションを開始するときに、追加されたコマンドに構文エラーがあると、トランザクションの送信は失敗します。この場合、トランザクション キュー内のコマンドはいずれも実行されません。上記の例と同様に、a と b の値は両方とも元の値です。

コマンド名エラー、コマンドパラメータエラーなど、EXEC 実行前に発生するエラーは、EXEC 実行前に検出されるため、これらのエラーが発生するとトランザクションがキャンセルされ、トランザクション内のすべてのコマンドが無効になります。キャンセルされます。実行されません。 (この状況はロールバックに少し似ていますか?)

[E]実行時エラー

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a 1
QUEUED
127.0.0.1:6379> SET b hello
QUEUED
127.0.0.1:6379> INCR b
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> GET b
"hello"
ログイン後にコピー

当 Redis 开启一个事务后,添加的命令没有出现前面说的语法错误,但是在运行时检测到了类型错误,导致事务最提交失败(说未完全成功可能更准确点)。此时事务并不会回滚,而是跳过错误命令继续执行。
如上面的例子,未报错的命令值已经修改,a 被设置成了 1,b 被设置为了 hello,但是报错的值未被修改,即 INCR b 类型错误,并未执行,b 的值也没有被再更新。

Redis 事务与 ACID

通过上面的例子,我们已经知道 Redis 的事务和我们通常接触的 MySQL 等关系数据库的事务还有有一定差异的。它不保证原子性。同时 Redis 事务也没有事务隔离级别的概念。下面我们来具体看下 Redis 在 ACID 四个特性中,那些是满足的,那些是不满足的。
事务执行可以分为命令入队(EXEC 执行前)和命令实际执行(EXEC 执行之后)两个阶段。下面我们在分析的时候,很多时候都会分这两种情况来分析。

原子性(A)

上面的实例分析中,[A],[B],[C]三种正常的情况,我们可以很明显的看出,是保证了原子性的。
但是一些异常情况下,是不满足原子性的。

如 [D] 所示的情况,客户端发送的命令有语法错误,在命令入队列时 Redis 就判断出来了。等到执行 EXEC 命令时,Redis 就会拒绝执行所有提交的命令,返回事务失败的结果。此种情况下,事务中的所有命令都不会被执行了,是保证了原子性的。 如 [E] 所示的情况,事务操作入队时,命令和操作类型不匹配,此时 Redis 没有检查出错误(这类错误是运行时错误)。等到执行 EXEC 命令后,Redis 实际执行这些命令操作时,就会报错。需要注意的是,虽然 Redis 会对错误的命令报错不执行,但是其余正确的命令会依次执行完。此种情况下,是无法保证原子性的。 在执行事务的 EXEC 命令时,Redis 实例发生了故障,导致事务执行失败。此时,如果开启了 AOF 日志,那么只会有部分事务操作被记录到 AOF 日志中。使用redis-check-aof工具检测 AOF 日志文件,可以把未完成的事务操作从 AOF 文件中去除。这样一来,使用 AOF 文件恢复实例后,事务操作不会被再执行,从而保证了原子性。若使用的 RDB 模式,最新的 RDB 快照是在 EXEC 执行之前生成的,使用快照恢复之后,事务中的命令也都没有执行,从而保证了原子性。若 Redis 没有开启持久化,则重启后内存中的数据全部丢失,也就谈不上原子性了。 一致性(C)

一致性指的是事务执行前后,数据符合数据库的定义和要求。这点在 Redis 事务中是满足的,不论是发生语法错误还是运行时错误,错误的命令均不会被执行。

EXEC 执行之前,入队报错(实例分析中的语法错误)

事务会放弃执行,故可以保证一致性。

EXEC 执行之后,实际执行时报错(实例分析中的运行时错误)

错误的命令不会被执行,正确的命令被执行,一致性可以保证。

EXEC 执行时,实例宕机

若 Redis 没有开启持久化,实例宕机重启后,数据都没有了,数据是一致的。
若配置了 RDB 方式,RDB 快照不会在事务执行时执行。所以,若事务执行到一半,实例发生了故障,此时上一次 RDB 快照中不会包含事务所做的修改,而下一次 RDB 快照还没有执行,实例重启后,事务修改的数据会丢失,数据是一致的。若事务已经完成,但新一次的 RDB 快照还没有生成,那事务修改的数据也会丢失,数据也是一致的。
若配置了 AOF 方式。当事务操作还没被记录到 AOF 日志时,实例就发生故障了,使用 AOF 日志恢复后数据是一致的。若事务中的只有部分操作被记录到 AOF 日志,可以使用 redis-check-aof清除事务中已经完成的操作,数据库恢复后数据也是一致的。

隔离性(I) 并发操作在 EXEC 执行前,隔离性需要通过 WATCH 机制来保证 并发操作在 EXEC 命令之后,隔离性可以保证

情况 a 可以参考前面的实例分析 WATCH 命令的使用。
情况 b,由于 Redis 是单线程执行命令,EXEC 命令执行后,Redis 会保证先把事务队列中的所有命令执行完之后再执行之后的命令。

持久性(D)

Redis で永続性が有効になっていない場合、すべてのデータはメモリに保存され、再起動するとデータが失われるため、現時点でのトランザクションの耐久性は保証できません。
Redis で永続性が有効になっている場合でも、インスタンスがクラッシュして再起動されたときにデータが失われる可能性があるため、永続性を完全に保証することはできません。
したがって、Redis トランザクションは必ずしも耐久性を保証できるわけではなく、特殊な状況下でのみ耐久性を保証できると言えます。

Redis で永続性を有効にしてもデータが失われる理由については、著者が Redis の永続性とマスター/スレーブに関連する別記事を作成して紹介する予定です。
RDB モードが構成されている場合、トランザクションの実行後、次の RDB スナップショットが実行される前に、Redis インスタンスがクラッシュし、データが失われます。
AOF モードが構成されており、次の 3 つのパラメーターAOF モード 設定オプション no、everysec、always もデータ損失を引き起こす可能性があります。

要約すると、Redis トランザクションは ACID をサポートします:

ある程度のアトミック性はありますが、ロールバックはサポートされていません。整合性と分離性は満たされていますが、耐久性は保証できません。Redis トランザクションがサポートされていない理由ロールバック?ロール

公式 Web サイトの説明を参照してください:

ロールバックについてはどうですか?
ロールバックのサポートはシンプルさとトランザクションに大きな影響を与えるため、Redis はトランザクションのロールバックをサポートしていません。 Redis のパフォーマンス。

トランザクション ロールバックが必要な状況のほとんどは、プログラム エラーによって引き起こされます。この状況は通常、開発環境で発生し、運用環境では発生しません。
たとえば、論理エラーの場合、1 を加算する必要がありますが、結果は 2 を加算するように記述されます。この状況はロールバックでは解決できません。
Redis はシンプルさと効率性を追求していますが、従来のトランザクションの実装は比較的複雑であり、Redis の設計思想に反しています。 Redis のスピードを享受すれば、それ以上のものを求めることはできません。

推奨される学習: Redis ビデオ チュートリアル

以上がRedis の事情を徹底的に理解するのに役立つ記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:jb51.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート