您好,登錄后才能下訂單哦!
這篇文章主要介紹了redis的高級特性有哪些,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。
1.redis發布訂閱模式
Redis除了提供像list的這種的消息隊列模式,還提供了一組命令實現發布/訂閱模式。例如微博,公眾號等都是可以由此實現。
1.2 訂閱頻道
發布者需要將消息發送到一個地方,讓訂閱者可以訂閱消息,這個地方就是頻道(channel)。訂閱者可以訂閱一個或者多個頻道,所有訂閱了這個頻道的訂閱者都會受到這條消息。
開啟兩個客戶端進行測試
客戶端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 按規則訂閱
支持?和*占位符。?代表一個字符,*代表 0 個或者多個字符。
啟動四個redis-cli,一個作為消息的發布者,另外三個作為訂閱者。
訂閱者1:訂閱體育相關
psubscribe *sport
訂閱者2:訂閱新聞相關
psubscribe news*
訂閱者3:訂閱天氣相關
psubscribe new weather*
發布者:
publish news-sport Kobe publish news-music jaychou publish news-weather rain
此時訂閱者1將會收到Kobe,訂閱者2將會收到全部信息,訂閱者3將會收到rain。
2.redis事務
2.1 為什么要用事務
我們都是知道redis的單個命令是原子性的,但是如果需要用多個命令作為一個不可分割的操作序列,就需要用到事務。
例如使用setnx實現分布式鎖,我們一般先set,然后對key設置expire,防止del發生異常時候鎖不會釋放,業務處理完之后在del,這三個操作我們就希望作為一組命令執行。
redis事務有兩個特點:
按照進入隊列的順序執行
不會受到其他客戶端請求影響
redis的事務設計四個命令:multi(開啟事務),exec(執行事務),dicard(取消事務),watch(監視)
2.2 事務的用法
轉賬場景A和B各有100元,A向B轉賬10元,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命令開啟事務。事務不能嵌套,多個multi命令效果一樣的
使用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)
當我們執行事務的時候出現了問題會回滾嗎?
exec之前發生錯誤 (如指令語法錯誤)
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)
exec之后發生錯誤(對同一個key使用不同數據類型的命令)
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"
通過上面操作,我們可以知道當事務在exec前發生錯誤,將會回滾所有操作;如果在exec后發生錯誤,只有錯誤的命令不會被執行。
為什么redis在一個事務中存在錯誤不進行回滾呢?
我們從上面操作可以看出,redis只有在指令語法錯誤的時候進行回滾,而指令操作錯誤是有開發人員導致的bug,例如:你對一個int類型進行+1,然后不小心+2,或者對一個string類型進行+1,回滾是不適用的
2.3 watch指令
它可以為Redis事務提供CAS樂觀鎖操作,也就是多個線程更新某個變量的時候,會讓舊值跟內存地址相比較,如果相等,則更新為新值。
我們可以用watch監視一個或者多個key,如果開啟事務之后,至少有一個被監視的key在exec執行之前被修改,則會取消整個事務。
首先client 1執行watch監視money這個key,并開啟事務對money進行增加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
在事務結束之前,在client 2對money進行減少100
127.0.0.1:6379> decrby money 100 (integer) 900
此時client 1結束事務,money的值并沒有被增加,反而減少,說明事務的修改失效
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腳本
script 代表lua腳本的內容
numkeys key的數量
[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的高級特性有哪些”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。