Redis の高度な機能の紹介

王林
リリース: 2021-01-13 10:11:34
転載
2081 人が閲覧しました

Redis の高度な機能の紹介

リモート辞書サービスである Redis (Remote Dictionary Server) は、オープンソースのログタイプの Key-Value データベースであり、複数の言語で API を提供します。

(学習ビデオ共有: redis ビデオ チュートリアル )

1.redis パブリッシュおよびサブスクライブ モード

Redis は、リストのようなメッセージ キューを提供することに加えて、モードには、パブリッシュ/サブスクライブ モードを実装するための一連のコマンドも提供されます。例えば、Weiboやパブリックアカウントなどはすべてこれによって実現できます。

Redis の高度な機能の紹介

1.2 チャンネルへの登録

パブリッシャーは、サブスクライバーがメッセージを購読できる場所にメッセージを送信する必要があります。この場所がチャンネルです。加入者は 1 つ以上のチャネルに加入でき、このチャネルのすべての加入者がこのメッセージを受信します。

テスト用に 2 つのクライアントを開きます

客户端1 订阅channel1
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1

客户端2 发布一则消息
127.0.0.1:6379> publish channel1 test
(integer) 1

客户端1 订阅消息
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "test"
ログイン後にコピー

1.2 ルールによるサブスクライブ

サポートされていますか?および * プレースホルダー。 ?は 1 文字、* は 0 文字以上を表します。

4 つの redis-cli を開始します。1 つはメッセージのパブリッシャーとして、他の 3 つはサブスクライバーとしてです。
購読者 1: スポーツ関連の購読

psubscribe *sport
ログイン後にコピー

購読者 2: ニュース関連の購読

psubscribe news*
ログイン後にコピー

購読者 3: 天気関連の購読

psubscribe new weather*
ログイン後にコピー

パブリッシャー:

publish news-sport Kobe
publish news-music jaychou
publish news-weather rain
ログイン後にコピー

この時点で、サブスクライバ 1 は神戸を受信し、サブスクライバ 2 はすべての情報を受信し、サブスクライバ 3 は雨を受信します。

Redis の高度な機能の紹介

2.redis トランザクション

2.1 トランザクションを使用する理由

redis の 1 つのコマンドがアトミックであることは誰もが知っていますが、分離できない一連の操作として複数のコマンドを使用する必要がある場合は、トランザクションを使用する必要があります。
たとえば、分散ロックを実装するために setnx を使用する場合、通常は最初に分散ロックを設定し、次に del で例外が発生したときにロックが解放されないようにキーに Expire を設定します。ビジネスが処理された後、これら 3 つが必要になります。 del.implement で一連のコマンドとして使用される操作。
Redis トランザクションには 2 つの特徴があります:

  • キューに入った順に実行されます

  • 他のクライアント要求の影響を受けません

Redis のトランザクション設計には、multi (トランザクションの開始)、exec (トランザクションの実行)、dicard (トランザクションのキャンセル)、watch (監視) の 4 つのコマンドがあります。

2.2 の使用法トランザクション

送金シナリオ A と B がそれぞれ 100 元を持っており、A が 10 元を B に送金し、A が 10 元を減算し、B が 10 元を追加します

127.0.0.1:6379> set A 100
OK
127.0.0.1:6379> set B 100
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby A 10
QUEUED
127.0.0.1:6379> incrby B 10
QUEUED
127.0.0.1:6379> exec
1) (integer) 90
2) (integer) 110
127.0.0.1:6379> get A
"90"
127.0.0.1:6379> get B
"110"
ログイン後にコピー

multi コマンドでトランザクションを開きます。トランザクションをネストすることはできません。複数のマルチ コマンドは同じ効果を持ちます。
マルチを使用してトランザクションを開始した後、クライアントは複数のコマンドをサーバーに送信します。これらのコマンドはすぐには実行されず、キューに入れられます。 exec コマンドが呼び出されると、キュー内のコマンドが実行されます。
discard を使用してトランザクション キューをクリアできます。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> set k2 2
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)
ログイン後にコピー

トランザクションの実行時に問題が発生した場合、トランザクションはロールバックされますか?

実行前にエラーが発生しました (コマンド構文エラーなど)

127.0.0.1:6379> clear
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name test
QUEUED
127.0.0.1:6379> hset user lisi
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name
(nil)
ログイン後にコピー

実行後にエラーが発生しました (同じキーに対して異なるデータ型のコマンドを使用した場合)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> hset k1 a b
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"1"
ログイン後にコピー

Through上記の操作により、実行前のトランザクションでエラーが発生した場合はすべての操作がロールバックされ、実行後にエラーが発生した場合は間違ったコマンドのみが実行されないことがわかります。
トランザクションでエラーが発生したときに Redis がロールバックしないのはなぜですか?
上記の操作から、redis は命令の構文が間違っている場合にのみロールバックすることがわかり、命令の操作エラーは開発者によって引き起こされたバグです。例: int 型で 1 を実行し、その後誤って 2 を実行した場合、または実行した場合文字列型の場合は 1、ロールバックは適用されません

2.3 監視命令

Redis トランザクションに対して CAS オプティミスティック ロック操作を提供できます。つまり、複数のスレッドが特定の変数を更新します。古い値とメモリアドレスを比較し、等しい場合は新しい値に更新します。
watch を使用して 1 つ以上のキーを監視できます。トランザクションの開始後、exec が実行される前に監視対象のキーの少なくとも 1 つが変更された場合、トランザクション全体がキャンセルされます。

まず、クライアント1は礼金を監視するためのwatchを実行し、100

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby money 100
QUEUED
ログイン後にコピー

を増やすトランザクションを開始します。トランザクションが終了する前に、クライアント2は100

127.0.0.1:6379> decrby money 100
(integer) 900
ログイン後にコピー
#を減らします。 # #この時点で、クライアント 1 はトランザクションを終了し、金額は増加していませんが減少しており、トランザクションの変更が失敗したことを示しています

127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get money
"900"
ログイン後にコピー

3. Lua スクリプト

Lua スクリプトは軽量のスクリプト言語であり、C 言語で書かれており、ストアド プロシージャに似ています。なぜ lua スクリプトを使用するのでしょうか?

一度に複数のコマンドを送信して、ネットワークのオーバーヘッドを削減します。Redis はスクリプトを全体として実行して、アトミック性 (この方法でトランザクションを置き換えることができます) とスクリプトの再利用を確保し、複数のクライアントが簡単にコマンドを完了できるようにします。同じロジックです。

3.1

を使用すると、次のコマンドを使用して lua スクリプトを呼び出すことができます。


eval script numkeys [key1 key2 key3 ....] [arg1 arg2 arg3 ....]
ログイン後にコピー

eval は lua スクリプトを実行します。

スクリプトはコンテンツを表します。 lua スクリプトの

numkeys キー番号

[key1 key2 key3 ....] 键名参数,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。

[arg1 arg2 arg3 ....] 全局变量,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)

来个简单的例子

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],KEYS[2],ARGV[2]}" 2 key1 key2 val1 val1
1) "key1"
2) "val1"
3) "key2"
4) "val1"
127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 val1 val1
1) "key1"
2) "key2"
3) "val1"
4) "val1"
ログイン後にコピー

在lua脚本如何调用redis命令呢?
我们可以使用 redis.call(command, key [param1, param2…])进行操作

commond redis的命令,如set,get等key 被操作的键[param1, param2…]表示给key的参数

127.0.0.1:6379> eval "redis.call('mset',KEYS[1],ARGV[1],KEYS[2],ARGV[2])" 2 name age lisi 18
(nil)
127.0.0.1:6379> mget name age
1) "lisi"
2) "18
ログイン後にコピー

以上命令等价于 mset name lisi age 18, key的数量为2,2 后面两个值为key,在之后就是args

直接在redis-cli中写lua脚本不够方便,通常我们会把脚本放在文件中,然后执行这个文件
我们在一个目录下新建一个test.lua的脚本,填写以下内容后执行。

root@VM-0-5-centos src]# mkdir testlua
[root@VM-0-5-centos src]# cd testlua/
[root@VM-0-5-centos testlua]# ll
total 0
[root@VM-0-5-centos testlua]# touch test.lua
[root@VM-0-5-centos testlua]# vim test.lua
redis.call('set',KEYS[1],ARGV[1])
return redis.call('get',KEYS[1])
[root@VM-0-5-centos testlua]# redis-cli --eval test.lua 1 myname , Armin
"Armin"
ログイン後にコピー

值得注意的是key和arg之间需要加上空格逗号空格(myname , Armin)

3.2 缓存lua脚本

之所以需要缓存lua脚本,这是因为每次调用的时候都将整个脚本传给redis服务端,会产生较大的网络开销。为了解决这个问题,Redis提供了evalsha命令,让开发人员通过脚本内容的SHA1摘要执行脚本。

那么怎么将生成这个SHA1并将脚本内容加载到缓存呢,这就用到script load命令去计算脚本的SHA1摘要并记录脚本到缓存中,执行evalsha时,redis会根据提供的摘要去脚本缓存找到对应脚本内容,如果找到则执行,否则返回错误提示: “NOSCRIPT No matching script. Please use EVAL”

127.0.0.1:6379> script load "return 'Hey boy'"
"3760855b303510c83f0be2e8acfb0be64113ae6e"
127.0.0.1:6379> evalsha 3760855b303510c83f0be2e8acfb0be64113ae6e 0
"Hey boy"
127.0.0.1:6379> script exists 3760855b303510c83f0be2e8acfb0be64113ae6e //判断是否存在
1) (integer)
ログイン後にコピー

Redis还给lua脚本的执行提供了超时时间,默认的超时时间为5s,超过5s之后redis会接受其他命令但是会返回一个"BUSY"的错误
可在redis.conf中修改指定参数

lua-time-limit 5000
ログイン後にコピー

Redis提供了个script kill的命令来终止正在运行的脚本

127.0.0.1:6379> set name lisi
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
127.0.0.1:6379> script kill
OK
127.0.0.1:6379> set name lisi
OK
ログイン後にコピー

如果数据进行了修改操作,将无法使用script kill终止脚本,因为违反了原子性。此时只能通过shutdown nosave来强行终止redis。
shutdown nosave 和 shutdown 的区别在于 shutdown nosave 不会进行持久化 操作,意味着发生在上一次快照后的数据库修改都会丢失。

相关推荐:redis数据库教程

以上がRedis の高度な機能の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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