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官方只提供了POSIX系統版的redis版本,http://download.redis.io/redis-stable.tar.gz能夠下載最新的穩定版。redis沒有其它外部依賴。在window中安裝,須要使用cygwin環境。
服務器端啓動:
>redis-server :直接啓動,默認端口6379
>redis-server --port 6380 :指定端口上啓動
>redis-server redis.conf :啓動時使用配置文件初始化,redis.conf 位於安裝文件中。
>redis-cli SHUTDOWN :安全終止redis服務器node
能夠再主機的多個端口啓動多個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 :刪除全部數據庫中的keypython
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 …] :刪除字段mysql
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 :將元素從一個列表的右邊彈出轉到另外一個列表的左邊git
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種數據類型中最高級的類型。github
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
QUEUED
redis>EXEC
1) (integer) 1
2) (integer) 1
在執行過程當中若是有語法錯誤,則離開返回;若是是其它錯誤(如命令與鍵值類型不匹配)則不返回,繼續執行下面的命令,直到結束。不過因爲Redis不支持回滾功能,也使得Redis在事務上能夠保持簡潔和快速。另外回顧剛纔提到的會致使事務執行失敗的兩種錯誤,其中語法錯誤徹底能夠在開發時找出並解決,另外若是可以很好地規劃數據庫(保證鍵名規範等)的使用,是不會出現如命令與數據類型不匹配這樣的運行錯誤的。
b.監控-WATCH key
WATCH命令能夠監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),以後的事務就不會執行。監控一直持續到WATCH後面執行的第一個EXEC命令爲止(事務中的命令是在EXEC以後才執行的,因此在MULTI命令後能夠修改WATCH監控的鍵值)。
例子:
redis>SET key 1
OK
redis>WATCH key
OK
redis>SET key 2
OK
redis>MULTI
OK
redis>SET key 3
QUEUED
redis>EXEC //在執行EXEC前,修改了WATCH監控的key值,因此WATCH緊跟的EXEC沒有執行。
(nil)
redis>GET key
"2"redis
c.取消監控-UNWATCH -能夠在EXEC以前,認爲的取消監控
10.鍵的生存時間sql
EXPIRE key seconds 設置某個鍵的生存時間,時間到達後,鍵被刪除;TTL key查看剩餘的時間;PERSIST key取消生存時間
例子:
redis>SET foo bar
OK
redis>EXPIRE foo 20
(integer) 1
redis>TTL foo
(integer) 15
redis>TTL foo
(integer) 7
redis> TTL foo
(integer) -1 //鍵不存在,或者該鍵沒有生存時間數據庫
redis>EXPIRE foo 20
(integer) 1
redis>SET foo bar //使用SET對鍵從新賦值,至關於刪除該鍵,而後從新創建了一個新鍵
OK
redis>TTL foo
(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
OK
redis>SET itemscore:2 100
OK
redis>SET itemscore:3 -10
OK
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
(integer) 1
在LPUSH命令執行後實例A立刻就返回告終果:
1) "queue"
2) "task"
b.優先級隊列
BRPOP命令和BLPOP命令實際上能夠同時阻塞的讀取多個鍵,最前面的鍵優先級最高;若是全部鍵都沒有元素則阻塞;若是都有元素,則先讀取第一個鍵的元素。
BLPOP key [key …] timeout :最前面的鍵具備更高的優先級
>LPUSH queue2 task2
1) (integer) 1
>LPUSH queue3 task3
1) (integer) 1
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.?*"
3) (integer) 1
redis B>PUBLISH channel.1 hi!
(integer) 2
訂閱者返回結果:
1) "pmessage"
2) "channel.?*"
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
Redis官方推薦的Python客戶端是redis-py,見https://github.com/andymccurdy/redis-py。
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
end
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 barOKredis>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命令