redis發佈訂閱、事務、腳本

Redis 發佈訂閱

  Redis 發佈訂閱(pub/sub)是一種消息通訊模式:發送者(pub)發送消息,訂閱者(sub)接收消息。redis

  Redis 客戶端能夠訂閱任意數量的頻道。數組

  下圖展現了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關係:緩存

pubsub1

  當有新消息經過 PUBLISH 命令發送給頻道 channel1 時, 這個消息就會被髮送給訂閱它的三個客戶端:ide

pubsub2

實例函數

如下實例演示了發佈訂閱是如何工做的。在實例中建立了訂閱頻道名爲 redisChat:ui

redis 127.0.0.1:6379> SUBSCRIBE redisChat

Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1

 

如今,從新開啓個 redis 客戶端,而後在同一個頻道 redisChat 發佈兩次消息,訂閱者就能接收到消息。spa

redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"

(integer) 1

redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"

(integer) 1

# 訂閱者的客戶端會顯示以下消息
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by runoob.com"
# 1. 訂閱一個或多個符合給定模式的頻道。
PSUBSCRIBE pattern [pattern ...] 
'''
返回值:接收到的信息。
redis 127.0.0.1:6379> PSUBSCRIBE mychannel
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "mychannel"
3) (integer) 1
'''

# 2.查看訂閱與發佈系統狀態。
PUBSUB subcommand [argument [argument ...]] 
'''
返回值:由活躍頻道組成的列表。
redis 127.0.0.1:6379> PUBSUB CHANNELS
(empty list or set)
'''

# 3.將信息發送到指定的頻道。
PUBLISH channel message 
'''
返回值:接收到信息的訂閱者數量。
redis 127.0.0.1:6379> PUBLISH mychannel "hello, i m here"
(integer) 1
'''

# 4.退訂全部給定模式的頻道。
PUNSUBSCRIBE [pattern [pattern ...]] 
'''
返回值:這個命令在不一樣的客戶端中有不一樣的表現。
redis 127.0.0.1:6379> PUNSUBSCRIBE mychannel 
1) "punsubscribe"
2) "a"
3) (integer) 1
'''

# 5.訂閱給定的一個或多個頻道的信息。
SUBSCRIBE channel [channel ...] 
'''
返回值:接收到的信息
redis 127.0.0.1:6379> SUBSCRIBE mychannel 
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mychannel"
3) (integer) 1
1) "message"
2) "mychannel"
3) "a"
'''

# 6.指退訂給定的頻道。
UNSUBSCRIBE [channel [channel ...]] 
'''
返回值:這個命令在不一樣的客戶端中有不一樣的表現。
redis 127.0.0.1:6379> UNSUBSCRIBE mychannel 
1) "unsubscribe"
2) "a"
3) (integer) 0
'''
redis 發佈訂閱命令

 

Redis 事務

Redis 事務能夠一次執行多個命令, 而且帶有如下兩個重要的保證:3d

  • 批量操做在發送 EXEC 命令前被放入隊列緩存。
  • 收到 EXEC 命令後進入事務執行,事務中任意命令執行失敗,其他的命令依然被執行。
  • 在事務執行過程,其餘客戶端提交的命令請求不會插入到事務執行命令序列中。

一個事務從開始到執行會經歷如下三個階段:code

  • 開始事務。
  • 命令入隊。
  • 執行事務。

實例blog

  如下是一個事務的例子, 它先以 MULTI 開始一個事務, 而後將多個命令入隊到事務中, 最後由 EXEC 命令觸發事務, 一併執行事務中的全部命令:

redis 127.0.0.1:6379> MULTI
OK

redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED

redis 127.0.0.1:6379> GET book-name
QUEUED

redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED

redis 127.0.0.1:6379> SMEMBERS tag
QUEUED

redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"

  單個 Redis 命令的執行是原子性的,但 Redis 沒有在事務上增長任何維持原子性的機制,因此 Redis 事務的執行並非原子性的。

  事務能夠理解爲一個打包的批量執行腳本,但批量指令並不是原子化的操做,中間某條指令的失敗不會致使前面已作指令的回滾,也不會形成後續的指令不作。

這是官網上的說明 From redis docs on transactions:

It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.

好比:

redis 127.0.0.1:7000> multi
OK
redis 127.0.0.1:7000> set a aaa
QUEUED
redis 127.0.0.1:7000> set b bbb
QUEUED
redis 127.0.0.1:7000> set c ccc
QUEUED
redis 127.0.0.1:7000> exec
1) OK
2) OK
3) OK

若是在 set b bbb 處失敗,set a 已成功不會回滾,set c 還會繼續執行。

# 1.取消事務,放棄執行事務塊內的全部命令。
DISCARD 
'''
返回值
老是返回 OK 。
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> PING
QUEUED
redis 127.0.0.1:6379> SET greeting "hello"
QUEUED
redis 127.0.0.1:6379> DISCARD
OK
'''

# 2.執行全部事務塊內的命令。
EXEC 
'''
返回值:事務塊內全部命令的返回值,按命令執行的前後順序排列。 當操做被打斷時,返回空值 nil 。
# 事務被成功執行
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> INCR user_id
QUEUED
redis 127.0.0.1:6379> INCR user_id
QUEUED
redis 127.0.0.1:6379> INCR user_id
QUEUED
redis 127.0.0.1:6379> PING
QUEUED
redis 127.0.0.1:6379> EXEC
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG

# 監視 key ,且事務成功執行
redis 127.0.0.1:6379> WATCH lock lock_times
OK
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET lock "huangz"
QUEUED
redis 127.0.0.1:6379> INCR lock_times
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
2) (integer) 1

# 監視 key ,且事務被打斷
redis 127.0.0.1:6379> WATCH lock lock_times
OK
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET lock "joe"        # 就在這時,另外一個客戶端修改了 lock_times 的值
QUEUED
redis 127.0.0.1:6379> INCR lock_times
QUEUED
redis 127.0.0.1:6379> EXEC                  # 由於 lock_times 被修改, joe 的事務執行失敗
(nil)
'''

# 3.標記一個事務塊的開始。
MULTI 
'''
返回值:老是返回 OK 。
redis 127.0.0.1:6379> MULTI            # 標記事務開始
OK
redis 127.0.0.1:6379> INCR user_id     # 多條命令按順序入隊
QUEUED
redis 127.0.0.1:6379> INCR user_id
QUEUED
redis 127.0.0.1:6379> INCR user_id
QUEUED
redis 127.0.0.1:6379> PING
QUEUED
redis 127.0.0.1:6379> EXEC             # 執行
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG
'''

# 4.取消 WATCH 命令對全部 key 的監視。
UNWATCH 
'''
返回值: 老是返回 OK 。
redis 127.0.0.1:6379> WATCH lock lock_times
OK
redis 127.0.0.1:6379> UNWATCH
OK
'''

# 5.監視一個(或多個) key ,若是在事務執行以前這個(或這些) key 被其餘命令所改動,那麼事務將被打斷。
WATCH key [key ...] 
'''
返回值:老是返回 OK 。
redis> WATCH lock lock_times
OK
'''
redis 事務基本操做

 

Redis 腳本

  Redis 腳本使用 Lua 解釋器來執行腳本。 Redis 2.6 版本經過內嵌支持 Lua 環境。執行腳本的經常使用命令爲 EVAL

Eval 命令的基本語法以下:

redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]

實例

如下實例演示了 redis 腳本工做過程

redis 127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

1) "key1"
2) "key2"
3) "first"
4) "second"
# 1.執行 Lua 腳本。
EVAL script numkeys key [key ...] arg [arg ...] 
'''
參數說明:
script: 參數是一段 Lua 5.1 腳本程序。腳本沒必要(也不該該)定義爲一個 Lua 函數。
numkeys: 用於指定鍵名參數的個數。
key [key ...]: 從 EVAL 的第三個參數開始算起,表示在腳本中所用到的那些 Redis 鍵(key),這些鍵名參數能夠在 Lua 中經過全局變量 KEYS 數組,用 1 爲基址的形式訪問( KEYS[1] , KEYS[2] ,以此類推)。
arg [arg ...]: 附加參數,在 Lua 中經過全局變量 ARGV 數組訪問,訪問的形式和 KEYS 變量相似( ARGV[1] 、 ARGV[2] ,諸如此類)。
redis 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
'''

# 2.執行 Lua 腳本。
EVALSHA sha1 numkeys key [key ...] arg [arg ...] 
'''
參數說明:
sha1 : 經過 SCRIPT LOAD 生成的 sha1 校驗碼。
numkeys: 用於指定鍵名參數的個數。
key [key ...]: 從 EVAL 的第三個參數開始算起,表示在腳本中所用到的那些 Redis 鍵(key),這些鍵名參數能夠在 Lua 中經過全局變量 KEYS 數組,用 1 爲基址的形式訪問( KEYS[1] , KEYS[2] ,以此類推)。
arg [arg ...]: 附加參數,在 Lua 中經過全局變量 ARGV 數組訪問,訪問的形式和 KEYS 變量相似( ARGV[1] 、 ARGV[2] ,諸如此類)。

redis 127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"
redis 127.0.0.1:6379> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
"hello moto"
'''

# 3.查看指定的腳本是否已經被保存在緩存當中。
SCRIPT EXISTS script [script ...] 
'''
返回值:一個列表,包含 0 和 1 ,前者表示腳本不存在於緩存,後者表示腳本已經在緩存裏面了。
列表中的元素和給定的 SHA1 校驗和保持對應關係,好比列表的第三個元素的值就表示第三個 SHA1 校驗和所指定的腳本在緩存中的狀態。
redis 127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"    # 載入一個腳本
"232fd51614574cf0867b83d384a5e898cfd24e5a"
redis 127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
1) (integer) 1
redis 127.0.0.1:6379> SCRIPT FLUSH     # 清空緩存
OK
redis 127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
1) (integer) 0
'''

# 4.從腳本緩存中移除全部腳本。
SCRIPT FLUSH 
'''
返回值:OK
redis 127.0.0.1:6379> SCRIPT FLUSH
OK
'''

# 5.殺死當前正在運行的 Lua 腳本。
SCRIPT KILL 
'''
返回值:OK
redis 127.0.0.1:6379> SCRIPT KILL
OK
'''

# 6.將腳本 script 添加到腳本緩存中,但並不當即執行這個腳本。
SCRIPT LOAD script 
'''
返回值:給定腳本的 SHA1 校驗和
redis 127.0.0.1:6379> SCRIPT LOAD "return 1"
"e0e1f9fabfc9d4800c877a703b823ac0578ff8db"
'''
redis 腳本基本操做
相關文章
相關標籤/搜索