1.redis是什麼?
redis(REmote DIctionary Server)是一種使用C語言開發的NOSQL,即非關系資料庫;Redis是一個操作資料結構的語言工具是一種記憶體資料庫或者資料結構伺服器,将資料直接儲存在記憶體中,但又提供了持久化支援;是一種鍵值對資料庫,儲存的是鍵值對資料,相當于儲存了一個變量及變量的值;以字典結構存儲資料,并允許其他應用通過TCP協定讀寫字典中的内容;是Memcached緩存伺服器的替代者。
2.redis可以用來做什麼?
資料庫、隊列、緩存系統,新浪微網誌大量使用了redis.Key-Value Store 是當下比較流行的話題,尤其在建構諸如搜尋引擎、IM、P2P、遊戲伺服器、SNS等大型網際網路應用以及提供雲計算服務的時候,保證系統在海量資料環境下的高性能、高可靠性、高擴充性、高可用性、低成本.
适用場合:
a.取最新 N 個資料的操作
b.排行榜應用,取 TOP N 操作
c.需要精準設定過期時間的應用
d.計數器應用 INCR DECR
e.Uniq 操作,擷取某段時間所有資料排重值
f.實時系統,反垃圾系統 SET集合
g.Pub/Sub 建構實時消息系統
h.建構隊列系統
i.緩存
3.redis與memcashed的優劣
在性能上Redis是單線程模型,而Memcached支援多線程,是以在多核伺服器上後者的性能更高一些。然而,前面已經介紹過,Redis的性能已經足夠優異,在絕大部分場合下其性能都不會成為瓶頸。是以在使用時更應該關心的是二者在功能上的差別,如果需要用到進階的資料類型或是持久化等功能,Redis将會是Memcached很好的替代品。
作為緩存系統,Redis還可以限定資料占用的最大記憶體空間,在資料達到空間限制後可以按照一定的規則自動淘汰不需要的鍵。
除此之外,Redis的清單類型鍵可以用來實作隊列,并且支援阻塞式讀取,可以很容易地實作一個高性能的優先級隊列。同時在更高層面上,Redis還支援“釋出/訂閱”的消息模式,可以基于此建構聊天室等系統。
4.redis安裝與啟動
伺服器端啟動:
>redis-server :直接啟動,預設端口6379
>redis-server --port 6380 :指定端口上啟動
>redis-server redis.conf :啟動時使用配置檔案初始化,redis.conf 位于安裝檔案中。
>redis-cli SHUTDOWN :安全終止redis伺服器
可以再主機的多個端口啟動多個redis-server
用戶端啟動:
>redis-cli -h 127.0.0.1 -p 6379 :用戶端啟動并連接配接伺服器
5.redis指令執行的傳回值(5種)
a.狀态回複 回複指令的執行狀态,如set和PING的回複
b.錯誤回複 指令執行錯誤,回複形式為:(error)...
c.整數回複 redis雖然沒有整數類型,但提供了一組用于字元整數操作的指令,這些指令的回複傳回整數,如INCR,DBSIZE ,回複形式為:(integer) n
e.字元串回複 當請求一個字元串類型鍵的鍵值或一個其他類型鍵中的某個元素時就會得到一個字元串回複,如GET,回複形式為:“...”
f.多行字元串回複 如KEYS指令,回複時會添加字元串行号。
6.redis的多資料庫
如mysql可以建立多個資料庫一樣,redis可以建立的資料庫個數通過redis.conf中的databases來配置,預設為16個,資料庫号從0-15,不支援自定義資料庫名稱。用戶端redis-cli與Redis建立連接配接後會自動選擇0号資料庫,不過可以随時使用SELECT n指令更換資料庫。
7.常用指令
KEYS glob_pattern :查詢目前資料庫中所有的鍵glob_pattern : ?,*,[],\x
EXISTS key :判斷一個鍵是否存在,存在傳回1,否則0
DEL key [key …] :删除一個或多個鍵
TYPE key :傳回key鍵的資料類型
EXPIRE key time :設定一個鍵的過期時間
PERSIST key :移除該鍵的過期時間
MOVE key n :将目前資料庫的key鍵移動到n号資料庫
SELECT n :選擇n号資料庫作為目前資料庫,0-15
RANDOMKEY :随機傳回目前資料庫的一個鍵
RENAME key newkey :重命名一個key
伺服器相關指令
PING :測試連接配接是否存活
ECHO "..." :在指令行列印一行内容
QUIT :退出連接配接
DBSIZE :傳回目前資料庫中鍵的個數
INFO :傳回伺服器的資訊和統計
MONITOR :實時轉儲收到的請求
CONFIG GET dir :擷取伺服器配置資訊
FLUSHDB :删除目前資料庫中的所有key
FLUSHALL :删除所有資料庫中的key
8.redis的5大資料(鍵)類型
字元串(string)、散列(hash)、清單(list)、集合(set)、有序集合(zset),每一個鍵都是這5種資料類型中的一種,根據鍵的建立方式不同來決定屬于哪種類型。Redis不支援資料類型嵌套。清單(list)、集合(set)、有序集合鍵隻能儲存字元串類型的資料。
a.字元串類型:一個字元串類型鍵允許存儲的資料的最大容量是512MB。字元串類型是其他4種資料類型的基礎,其他資料類型和字元串類型的差别從某種角度來說隻是組織字元串的形式不同。例如,清單類型是以清單的形式組織字元串,而集合類型是以集合的形式組織字元串。
指令:
對字元串的操作
SET key value :建立字元串變量并指派
GET key :當鍵不存在時會傳回空結果。
SETNX key value :如果鍵key不存在,則設定該鍵;存在則傳回0,不進行設定
SETEX key time value :設定鍵key的同時指定該鍵的有效期為time,可以使用TTL檢視
SETRANGE key start jointvalue :将鍵key從第8個字元起,替換為jointvalue
APPEND key value :向一個字元串的尾部增加值
STRLEN key :擷取字元串長度
MSET key value [key value …] :同時設定多個鍵的值
MGET key [key …] :同時擷取多個鍵的值
MSETNX key value [key value …] :當失敗時,一個鍵也不會被設定
GETSET key value :設定并傳回key的值
GETRANGE key start end :傳回key字元串中從start到end的子竄
對實數字元串的操作
INCR key :遞增數字,對非數字遞增将傳回錯誤
INCRBY key increment :按指定數字增加
DECR key :遞減數字
DECRBY key decrement :按指定數字遞減
INCRBYFLOAT key increment :對浮點數加
對字元串進行位操作的4大指令(是記憶體意義上的二進制位的操作)
GETBIT key offset :擷取字元串中總第offset位的二進制值
SETBIT key offset value :設定字元串中總第offset位的二進制值
BITCOUNT key [m] [n] :統一字元串中從第m位元組到第n位元組中的二進制數中的1的個數
BITOP operation destkey key [key …]:BITOP指令可以對多個字元串類型鍵進行位運算,并将結果存儲在destkey參數指定的鍵中。BITOP指令支援的運算操作有AND、OR、XOR 和NOT
b.散列類型(python中的字典類型)
散列類型(hash)的鍵值是一種字典結構,其存儲了字段(field)和字段值的映射,但字段值隻能是字元串,不支援其他資料類型,一個散列類型鍵可以包含至多2的32次方-1個字段。
指派與取值:
HSET key field value :設定該鍵指定字段的值
HGET key field :擷取該鍵指定字段的值
HMSET key field value [field value …] :設定該鍵多個字段的值
HMGET key field [field …] :擷取該鍵多個字段的值
HGETALL key :擷取該鍵所有字段名及域值
HKEYS key :擷取該鍵所有字段名
HVALS key :擷取該鍵所有字段的值
HLEN key :擷取該鍵字段的個數
HEXISTS key field :判斷該鍵中是否存在某個字段
HSETNX key field value :該字段不存在時指派
HINCRBY key field increment :對數字字元串加increment
HDEL key field [field …] :删除字段
c.清單類型(雙端連結清單)
向清單兩端壓入和彈出元素
LPUSH key value [value …] :向清單左端添加元素
RPUSH key value [value …] :向清單右端添加元素
LPOP key :由清單左端彈出元素
RPOP key :由清單右端彈出元素
LLEN key :擷取清單中元素的個數
LRANGE key start stop :獲得清單片段,-1,最後一個元素,-2倒數第二個元素
LREM key count value :當count>會從左邊删除清單中前count個值為value的元素,傳回值是實際删除的元素個數;當count<0從右邊起删除;count=0,會删除所有值為value的元素。
LINDEX key index :獲得指定索引的元素值,支援負索引
LSET key index value :設定指定索引的元素值
LTRIM key start end :隻保留清單指定片段
LINSERT key BEFORE|AFTER pivot value :從左到右查找值為pivot的元素,将value插入到該元素的BEFORE或AFTER
RPOPLPUSH source destination :将元素從一個清單的右邊彈出轉到另一個清單的左邊
d.集合(存儲不相同的字元串)
在集合中的每個元素都是不同的,且沒有順序。一個集合類型(set)鍵可以存儲至多2次方32-1個(相信這個數字對大家來說已經很熟悉了)字元串。集合類型的常用操作是向集合中加入或删除元素、判斷某個元素是否存在等,由于集合類型在Redis内部是使用值為空的散清單(hash table)實作的,是以這些操作的時間複雜度都是0(1)。最友善的是多個集合類型鍵之間還可以進行并集、交集和差集運算。
SADD key member [member …] :增加元素
SREM key member [member …] :删除元素
SMEMBERS key :獲得集合中的所有元素
SISMEMBER key member :判斷元素是否在集合中
SDIFF key [key …] :差集
SINTER key [key …] :交集
SUNION key [key …] :并集
SCARD key :獲得集合中元素個數
SDIFFSTORE destination key [key …] :進行集合運算并将結果存儲
SINTERSTORE destination key [key …]
SUNIONSTORE destination key [key …]
SRANDMEMBER key [count] :随機獲得集合中的元素(預設1個)當count為正數時,SRANDMEMBER會随機從集合裡獲得count個不重複的元素。如果count的值大于集合中的元素個數,則SRANDMEMBER會傳回集合中的全部元素;)當count為負數時,SRANDMEMBER會随機從集合裡獲得|count|個的元素,這些元素有可能相同。
SPOP key :從集合中彈出一個元素
SMOVE source destination value :将鍵source中的value移動到destination中。
e.有序集合類型(sorted set)
在集合類型的基礎上有序集合類型為集合中的每個元素都關聯了一個分數,這使得我們不僅可以完成插入、删除和判斷元素是否存在等集合類型支援的操作,還能夠獲得分數最高(或最低)的前N個元素、獲得指定分數範圍内的元素等與分數有關的操作。雖然集合中每個元素都是不同的,但是它們的分數卻可以相同。
有序集合類型在某些方面和清單類型有些相似。
(1)二者都是有序的。
(2)二者都可以獲得某一範圍的元素。
但是二者有着很大的差別,這使得它們的應用場景也是不同的。
(1)清單類型是通過連結清單實作的,擷取靠近兩端的資料速度極快,而當元素增多後,通路中間資料的速度會較慢,是以它更加适合實作如“新鮮事”或“日志”這樣很少通路中間元素的應用。
(2)有序集合類型是使用散清單和跳躍表(Skip list)實作的,是以即使讀取位于中間部分的資料速度也很快(時間複雜度是O(log(N)))。
(3)清單中不能簡單地調整某個元素的位置,但是有序集合可以(通過更改這個元素的分數)。
(4)有序集合要比清單類型更耗費記憶體
有序集合類型算得上是 Redis的5種資料類型中最進階的類型。
ZADD key score member [score member …] :增加元素,score可以是任意實數
ZSCORE key member :獲得指定元素的分數
ZRANGE key start stop [WITHSCORES] :獲得排名在某個範圍的元素清單(升序),如前三ZRANGE key 0 2 ,[WITHSCORES]傳回member的同時傳回分數
ZREVRANGE key start stop [WITHSCORES] :按分數降序傳回
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] :獲得指定分數範圍的成員(升序),[LIMIT offset count]從offset成員開始,傳回count個成員
例 ZRANGEBYSCORE scoreboard (80 +inf LIMIT 5 3 傳回80以上(不包括80)的從第5個人開始的3個人
Z INCRBY key increment member :增加某個元素的分數,increment可以為負
ZCARD key :獲得集合中元素的個數
ZCOUNT key min max :獲得指定分數範圍內的元素個數
ZREM key member [member …] :删除一個或多個元素
ZREMRANGEBYRANK key start stop :按照升序排名範圍删除元素
ZREMRANGEBYSCORE key min max :按照分數範圍删除元素
ZRANK key member :獲得指定元素的升序排名
ZREVRANK key member :獲得指定元素的降序排名
ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGREGATE SUM|MIN|MAX] :計算有序集合的交集,如果權重相同,分數則按[AGREGATE SUM|MIN|MAX]計算
9.redis的事務
a.事務文法
redis的事務是需要原子執行的一組指令的集合。事務的原理是先将屬于一個事務的指令發送給Redis,然後再讓Redis依次執行這些指令。MULTI-EXEC關鍵字
redis>MULTI
OK
redis>SADD "user:1:following" 2
QUEUED
redis>SADD "user:2:followers" 1
redis>EXEC
1) (integer) 1
2) (integer) 1
在執行過程中如果有文法錯誤,則離開傳回;如果是其它錯誤(如指令與鍵值類型不比對)則不傳回,繼續執行下面的指令,直到結束。不過由于Redis不支援復原功能,也使得Redis在事務上可以保持簡潔和快速。另外回顧剛才提到的會導緻事務執行失敗的兩種錯誤,其中文法錯誤完全可以在開發時找出并解決,另外如果能夠很好地規劃資料庫(保證鍵名規範等)的使用,是不會出現如指令與資料類型不比對這樣的運作錯誤的。
b.監控-WATCH key
WATCH指令可以監控一個或多個鍵,一旦其中有一個鍵被修改(或删除),之後的事務就不會執行。監控一直持續到WATCH後面執行的第一個EXEC指令為止(事務中的指令是在EXEC之後才執行的,是以在MULTI指令後可以修改WATCH監控的鍵值)。
例子:
redis>SET key 1
redis>WATCH key
redis>SET key 2
redis>SET key 3
redis>EXEC //在執行EXEC前,修改了WATCH監控的key值,是以WATCH緊跟的EXEC沒有執行。
(nil)
redis>GET key
"2"
c.取消監控-UNWATCH -可以在EXEC之前,認為的取消監控
10.鍵的生存時間
EXPIRE key seconds 設定某個鍵的生存時間,時間到達後,鍵被删除;TTL key檢視剩餘的時間;PERSIST key取消生存時間
redis>SET foo bar
redis>EXPIRE foo 20
(integer) 1
redis>TTL foo
(integer) 15
(integer) 7
redis> TTL foo
(integer) -1 //鍵不存在,或者該鍵沒有生存時間
redis>SET foo bar //使用SET對鍵重新指派,相當于删除該鍵,然後重建立立了一個新鍵
(integer) -1
如果使用WATCH指令監測了一個擁有生存時間的鍵,該鍵時間到期自動删除并不會被WATCH指令認為該鍵被改變。
EXPIREAT key stamps 時間戳,s機關
PEXPIREAT key stamps 時間戳,ms機關
11.排序
排序可以使用有序集合,也可以使用SORT指令。
SORT指令可以多LIST、SET、ZSET類型的key進行排序。
a.指令格式: SORT key [ALPHA] [DESC] LIMIT start end :[ALPHA]表示按字母排序;預設是升序;LIMIT start end取排序結果的從start到end結果傳回
b.SORT的BY參數:BY 參數的文法為“BY參考鍵”。其中參考鍵可以是字元串類型鍵或者是散列類型鍵的某個字段(表示為鍵名->字段名)。如果提供了BY參數,SORT指令将不再依據元素自身的值進行排序,而是對每個元素使用元素的值替換參考鍵中的第一個“*”并擷取其值,然後依據該值對元素排序。參考鍵可以是散列或字元串類型。
redis>SORT tag:ruby:posts BY post:*->time DESC
1) "12"
2) "26"
3) "6"
4) "2"
對字元串進行排序:參考鍵為字元串
redis>LPUSH sortbylist 2 1 3
(integer) 3
redis>SET itemscore:1 50
redis>SET itemscore:2 100
redis>SET itemscore:3 -10
redis>SORT sortbylist BY itemscore:* DESC
1) "2"
2) "1"
3) "3"
例子中anytext是常量鍵名(甚至anytext鍵可以不存在),此時SORT的結果與LRANGE的結果相同,沒有執行排序操作;如果幾個元素的參考鍵值相同,則SORT指令會再比較元素本身的值來決定元素的順序。
c.SORT的GET參數:GET參數不影響排序,它的作用是使SORT指令的傳回結果不再是元素自身的值,而是GET參數中指定的鍵值。GET參數的規則和BY參數一樣,GET參數也支援字元串類型和散列類型的鍵,并使用“*”作為占位符。
redis>SORT tag:ruby:posts BY post:*->time DESC GET post:*->title
1) "Windows 8 app designs"
2) "RethinkDB - An open-source distributed database built with love"
3) "Uses for cURL"
4) "The Nature of Ruby"
排序後傳回的不是ID,而是ID對應的文章。(redis是否隻能對數字和字母進行排序,不能對字元串進行排序?)
d.SORT的STORE參數:預設情況下SORT會直接傳回排序結果,如果希望儲存排序結果,可以使用STORE參數。
SORT some.list STORE cache.sort
12.消息通知
a.任務隊列
說到隊列很自然就能想到Redis的清單類型。如果要實作任務隊列,隻需要讓生産者将任務使用LPUSH指令加入到某個鍵中,另一邊讓消費者不斷地使用RPOP指令從該鍵中取出任務即可。 BRPOP(右邊出棧)和BLPOP(左邊出棧) 指令就可以實作請求阻塞。
BRPOP指令接收兩個參數,第一個是鍵名,第二個是逾時時間,機關是秒。當超過了此時間仍然沒有獲得新元素的話就會傳回nil。上例中逾時時間為“0”,表示不限制等待的時間,即如果沒有新元素加入清單就會永遠阻塞下去。當獲得一個元素後BRPOP指令傳回兩個值,分别是鍵名和元素值。
例子:(多個用戶端執行個體中實作生産者與消費者模型)
在執行個體A中:
redis A>BRPOP queue 0
鍵入回車後執行個體1會處于阻塞狀态,這時在執行個體B中向queue中加入一個元素:
redis B>LPUSH queue task
在LPUSH指令執行後執行個體A馬上就傳回了結果:
1) "queue"
2) "task"
b.優先級隊列
BRPOP指令和BLPOP指令實際上可以同時阻塞的讀取多個鍵,最前面的鍵優先級最高;如果所有鍵都沒有元素則阻塞;如果都有元素,則先讀取第一個鍵的元素。
BLPOP key [key …] timeout :最前面的鍵具有更高的優先級
>LPUSH queue2 task2
>LPUSH queue3 task3
redis>BRPOP queue1 queue2 queue3 0
1) "queue:2"
2) "task2"
c.“釋出/訂閱”模式
“釋出/訂閱”模式同樣可以實作程序間的消息傳遞,其原理是這樣的:“釋出/訂閱”模式中包含兩種角色,分别是釋出者和訂閱者。訂閱者可以訂閱一個或若幹個頻道(channel),而釋出者可以向指定的頻道發送消息,所有訂閱此頻道的訂閱者都會收到此消息。釋出者釋出消息的指令是PUBLISH,用法是:
PUBLISH channel message,如向channel.1說一聲“hi”:
redis>PUBLISH channel.1 hi
(integer) 0
PUBLISH指令的傳回值表示接收到這條消息的訂閱者數量訂閱頻道的指令是SUBSCRIBE,可以同時訂閱多個頻道,用法是
SUBSCRIBEchannel[channel …] 現在新開一個redis-cli執行個體A,用它來訂閱channel.1:
redis A>SUBSCRIBE channel.1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel.1"
3) (integer) 1
執行SUBSCRIBE指令後用戶端會進入訂閱狀态,處于此狀态下用戶端不能使用除SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE這4個屬于“釋出/訂閱”模式的指令之外的指令(後面3個指令會在下面介紹),否則會報錯。相當于阻塞在訂閱模式中。UNSUBSCRIBE退訂。
按照通配規則訂閱:可以使用PSUBSCRIBE指令按照通配規則訂閱指定的規則
>PSUBSCRIBE channel.?*
Reading messages... (press Ctrl-C to quit)1) "psubscribe"
2) "channel.?*"
redis B>PUBLISH channel.1 hi!
(integer) 2
訂閱者傳回結果:
1) "pmessage"
3) "channel.1"
4) "hi!"
使用PSUBSCRIBE指令可以重複訂閱一個頻道,如某用戶端執行了PSUBSCRIBE channel.? channel.?*,這時向channel.2釋出消息後該用戶端會收到兩條消息,而同時PUBLISH指令傳回的值也是2而不是1。
PUNSUBSCRIBE指令可以退訂指定的規則,用法是
PUNSUBSCRIBE [pattern[pattern …]]
如果沒有參數則會退訂所有規則。
UNSUBSCRIBE指令隻能退訂通過PSUBSCRIBE指令訂閱的規則,不會影響直接通過SUBSCRIBE指令訂閱的頻道;同樣UNSUBSCRIBE指令也不會影響通過PSUBSCRIBE指令訂閱的規則。另外容易出錯的一點是使用PUNSUBSCRIBE指令退訂某個規則時不會将其中的通配符展開,而是進行嚴格的字元串比對,是以PUNSUBSCRIBE*無法退訂channel.*規則,而是必須使用PUNSUBSCRIBE channel.*才能退訂。
13.管道
Redis的底層通信協定對管道(pipelining)提供了支援。通過管道可以一次性發送多條指令并在執行完後一次性将結果傳回,當一組指令中每條指令都不依賴于之前指令的執行結果時就可以将這組指令一起通過管道發出。管道通過減少用戶端與Redis的通信次數來實作降低往返時延累計值的目的。降低TCP消息包的數量。
14.redis與python
a.redis的python用戶端在python程式設計中的使用方法:
import redis //首先需要引入redis-py:
r=redis.StrictRedis() //下面的代碼将建立一個預設連接配接到位址127.0.0.1,端口6379的Redis連接配接:
r=redis.StrictRedis(host='127.0.0.1', port=6379, db=0) //也可以顯式地指定需要連接配接的位址:
r.set('foo', 'bar') # True
a=r.get('foo') # 'bar'
b.HMSET/HGETALL
HMSET支援将字典作為參數存儲,同時HGETALL的傳回值也是一個字典,搭配使用十分友善:
r.hmset('dict', {'name': 'Bob'})
people=r.hgetall('dict')
print people # {'name': 'Bob'}
c.事務和管道
redis-py的事務使用方式如下:
pipe=r.pipeline()
pipe.set('foo', 'bar')
pipe.get('foo')
result=pipe.execute()
print result # [True, 'bar']
管道的使用方式和事務相同,隻不過需要在建立時加上參數transaction=False:
pipe=r.pipeline(transaction=False)
事務和管道還支援鍊式調用:
result=r.pipeline().set('foo', 'bar').get('foo').execute()
# [True, 'bar']
15.redis腳本
Redis在2.6版推出了腳本功能,允許開發者使用Lua語言編寫腳本傳到Redis中執行。在Lua腳本中可以調用大部分的Redis指令
使用腳本的好處如下:
(1)減少網絡開銷:6.1節中的第一段代碼最多需要向Redis發送5次請求,而使用腳本功能完成同樣的操作隻需要發送一個請求即可,減少了網絡往返時延。
(2)原子操作:Redis會将整個腳本作為一個整體執行,中間不會被其他指令插入。換句話說在編寫腳本的過程中無需擔心會出現競态條件,也就無需使用事務。事務可以完成的所有功能都可以用腳本來實作。
(3)複用:用戶端發送的腳本會永久存儲在Redis中,這就意味着其他用戶端(可以是其他語言開發的項目)可以複用這一腳本而不需要使用代碼完成同樣的邏輯。
下面是一段lua腳本,名字為a.lua
local times=redis.call('incr', KEYS[1])
if times==1 then -- KEYS[1]鍵剛建立,是以為其設定生存時間
redis.call('expire', KEYS[1], ARGV[1])
end
if times>tonumber(ARGV[2]) then
return 0
return 1
那麼,如何測試這個腳本呢?首先把這段代碼存為a.lua,然後在命名行中輸入:
redis-cli --eval a.lua rate.limiting:127.0.0.1 , 10 3
其中--eval 參數是告訴redis-cli讀取并運作後面的Lua腳本,後面跟着的是傳給Lua腳本的參數。其中“,”前的
rate.limiting:127.0.0.1是要操作的鍵,可以在腳本中使用KEYS[1]擷取,“,”後面的10和3是參數,在腳本中
能夠使用ARGV[1]和ARGV[2]獲得。結合腳本的内容可知這行指令的作用就是将通路頻率限制為每10秒最多3次,
是以在終端中不斷地運作此指令會發現當通路頻率在10秒内小于或等于3次時傳回1,否則傳回0。注意上面
的指令中“,”兩邊的空格不能省略,否則會出錯。
16.redis與lua
a.在腳本中調用Redis指令
在腳本中可以使用redis.call函數調用Redis指令。就像這樣:
redis.call('set', 'foo', 'bar')
local value=redis.call('get', 'foo') --value的值為bar
redis.call函數的傳回值就是Redis指令的執行結果。第2章介紹過Redis指令的傳回值有5種
類型,redis.call函數會将這5種類型的回複轉換成對應的Lua的資料類型.
Redis還提供了redis.pcall函數,功能與redis.call相同,唯一的差別是當指令執行出錯時redis.pcall會記錄錯誤并繼續執行,而redis.call會直接傳回錯誤,不會繼續執行。
b. 從腳本中傳回值 return
在腳本中可以使用return語句将值傳回給用戶端,如果沒有執行return語句則預設傳回nil。因為我們可以像調用其他Redis内置指令一樣調用我們自己寫的腳本
c. 腳本相關指令
EVAL指令:EVAL指令的格式是:EVAL腳本内容key參數的數量[key …] [arg …]
可以通過key和arg這兩類參數向腳本傳遞資料,它們的值可以在腳本中分别使用KEYS和ARGV兩個表類型的全局變量通路
例如,我們希望用腳本功能實作一個SET指令(當然現實中我們不會這麼幹),腳本内容是這樣的:
return redis.call('SET', KEYS[1], ARGV[1])
現在打開redis-cli執行此腳本:
redis>EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
redis>GET foo
"bar"
EVALSHA指令:
考慮到在腳本比較長的情況下,如果每次調用腳本都需要将整個腳本傳給Redis會占用較
多的帶寬。為了解決這個問題,Redis提供了EVALSHA指令允許開發者通過腳本内容的SHA1
摘要來執行腳本,該指令的用法和EVAL一樣,隻不過是将腳本内容替換成腳本内容的SHA1
摘要.在程式中使用EVALSHA指令的一般流程如下:
(1)先計算腳本的SHA1摘要,并使用EVALSHA指令執行腳本。
(2)獲得傳回值,如果傳回“NOSCRIPT”錯誤則使用EVAL指令重新執行腳本。
雖然這一流程略顯麻煩,但值得慶幸的是很多程式設計語言的Redis用戶端都會代替開發者完
成這一流程。比如使用node_redis用戶端執行EVAL指令時,node_redis會先嘗試執行EVALSHA
指令,如果失敗了才會執行EVAL指令
本文轉自 a_liujin 51CTO部落格,原文連結:http://blog.51cto.com/a1liujin/1719646,如需轉載請自行聯系原作者