通過這部分讓大家對Redis的五種資料結構有初步的認識,對於Redis來說,每一種資料結構都有著自己的內部編碼,而且是多種實現的,這樣Redis會在合適的場景選擇合適的內部編碼,通過OBJECT ENCODING [key]可以參看指定key的內部編碼。 這樣做的好處:
a. 改進內部編碼,對外的資料結構和命令沒有影響,對使用者提供黑箱模型。
b. 多種內部編碼可在不同場景下發揮各自的優勢。如:ziplist比較節約記憶體,但是元素比較多的時候,效能會有所下降,此時Redis會將編碼自動轉換為linkedlist,效能會有所改善。
單執行緒
瞭解Redis的單執行緒架構,有助於大家對Redis的進一步學習和排解問題。
Redis處理網路請時候的求單執行緒可以抽象成這樣,通向Redis的路只有一條,且這條路是個單車道,只容的下一輛車同時使用,而我們使用的Redis命令即為這些車輛,當我們執行多個命令的時候,只有等第一個命令執行完成了後面的命令才會執行,否則會一直處於等待狀態。
Redis單執行緒的架構需要我們注意幾點
a. 一次只執行一條命令
b. 拒絕長(慢)命令(keys、flushall、flushdb、slow lua script、mutil/exec、operate、big value)
至於為什麼單執行緒還這麼快,這裡有個原因,Redis客戶端的到Redis伺服器的網路請求採用了多路I/O複用模型(非阻塞I/O),利用select、poll、epoll可以同時監聽多個流的I/O(客戶端到伺服器的網路請求)事件的能力,在空閒的時候,會把當前執行緒阻塞掉,當有一個或者多個流有I/O事件時,就從阻塞態中喚醒,輪訓一遍所有的流並且依次處理就緒的流。這樣就算出現有的流的I/O因為網路原因很慢,也不會影響別的流的I/O(非阻塞),因為是輪訓所有的流的I/O。這裡的“多路”指的是多個網路連線,“複用”指的是複用同一個執行緒。
# 使用 EX 選項
redis> SET key-with-expire-time "hello" EX 10086
OK
redis> GET key-with-expire-time
"hello"
redis> TTL key-with-expire-time
(integer) 10069
複製程式碼
GET key
時間複雜度O(1)。
獲取與鍵key相關聯的字串值。 返回值:
如果鍵key不存在,那麼返回特殊值nil;否則,返回鍵key的值。
如果鍵key的值並非字串型別,那麼返回一個錯誤,因為GET命令只能用於字串值。 程式碼演示:
redis> GET db
(nil)
redis> SET db redis
OK
redis> GET db
"redis"複製程式碼
DEL key [key ...]
時間複雜度為O(N),N為被刪除的key的數量,其中刪除單個字串型別的key,時間複雜度為O(1);刪除單個列表、集合、有序集合或雜湊表型別的key,時間複雜度為O(M),M為以上資料結構內的元素數量。
刪除指定的一個或者多個key,不存在的key會被忽略。 返回值: 被刪除的key的數量。 程式碼演示:
# 同時刪除多個 key
redis> SET name "redis"
OK
redis> SET type"key-value store"
OK
redis> SET website "redis.com"
OK
redis> DEL name type website
(integer) 3
複製程式碼
MSET key value [key value ...]
時間複雜度O(N),其中N為被設定的鍵數量。
同時為多個鍵設定值。如果某個給定鍵已經存在,那麼MSET將使用新值去覆蓋舊值,如果這不是你所希望的效果,請考慮使用MSETNX命令,這個命令只會在所有給定鍵都不存在的情況下進行設定。MSET是一個原子性(atomic) 操作,所有給定鍵都會在同一時間內被設定,不會出現某些鍵被設定了但是另一些鍵沒有被設定的情況。 返回值:MSET命令總是返回OK。 程式碼演示:
redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
OK
redis> MGET date time weather
1) "2012.3.30"
2) "11:00 a.m."
3) "sunny"複製程式碼
MSETNX key value [key value ...]
時間複雜度O(N),其中N為被設定的鍵數量。
當且僅當所有給定鍵都**不存在時,為所有給定鍵設定值。即使只有一個給定鍵已經存在,MSETNX命令也會拒絕執行對所有鍵的設定操作。MSETNX是一個原子性(atomic) 操作,所有給定鍵要麼就全部都被設定,要麼就全部都不設定,不可能出現第三種狀態。 返回值: 當所有給定鍵都設定成功時,命令返回1;如果因為某個給定鍵已經存在而導致設定未能成功執行,那麼命令返回0。 程式碼演示:
HSET key field value
時間複雜度O(1)。
將雜湊表key中域field的值設定為value,如果給定的雜湊表不存在,那麼一個新的雜湊表將被建立並執行HSET操作,如果域field已存在於雜湊表中,那麼它的舊值將被新值value覆蓋。 返回值: 當HSET命令在雜湊表中新建立field域併成功為它設定值時,命令返回1;如果域field已經存在於雜湊表,並且HSET命令成功使用新值覆蓋了它的舊值,那麼命令返回0。 程式碼演示:
redis> HSET website google "www.g.cn"
(integer) 1
redis> HGET website google
"www.g.cn"複製程式碼
HGET key field
時間複雜度O(1)。
返回雜湊表中給定域的值。 返回值:HGET命令在預設情況下返回給定域的值,如果給定域不存在於雜湊表中,又或者給定的雜湊表並不存在,那麼命令返回nil。
程式碼演示:
HMSET key field value [field value ...]
時間複雜度O(N),N為field-value對的數量。
同時將多個field-value(域-值)對設定到雜湊表key中,此命令會覆蓋雜湊表中已存在的域,如果key不存在,一個空雜湊表被建立並執行HMSET操作。 返回值: 如果命令執行成功,返回OK,當key不是雜湊表(hash)型別時,返回一個錯誤。
程式碼演示:
redis> HMSET website google www.google.com yahoo www.yahoo.com
OK
redis> HGET website google
"www.google.com"
redis> HGET website yahoo
"www.yahoo.com"複製程式碼
HMGET key field [field ...]
時間複雜度O(N),N為給定域的數量。
返回雜湊表key中,一個或多個給定域的值,如果給定的域不存在於雜湊表,那麼返回一個nil值,因為不存在的key被當作一個空雜湊表來處理,所以對一個不存在的key進行HMGET操作將返回一個只帶有nil值的表。 返回值: 一個包含多個給定域的關聯值的表,表值的排列順序和給定域引數的請求順序一樣。 程式碼演示:
redis> HMSET pet dog "doudou" cat "nounou"# 一次設定多個域
OK
redis> HMGET pet dog cat fake_pet # 返回值的順序和傳入引數的順序一樣
1) "doudou"
2) "nounou"
3) (nil) # 不存在的域返回nil值複製程式碼
N次HGET和一次HMGET對比
參考字串的N次GET和一次MGET對比,大概相同
列表
列表用於儲存多個有序的字串,列表是一種比較靈活的資料結構,可以充當棧和佇列的角色。
鍵值結構
列表的value其實是一個雙向連結串列,可以在連結串列的兩頭插入或者刪除元素
命令
LPUSH key value [value ...]
時間複雜度O(1)。
將一個或多個值value插入到列表key的表頭,如果有多個value值,那麼各個value值按從左到右的順序依次插入到表頭:比如說,對空列表mylist執行命令LPUSH mylist a b c,列表的值將是c b a,這等同於原子性地執行LPUSH mylist a、LPUSH mylist b和LPUSH mylist c三個命令,如果key不存在,一個空列表會被建立並執行LPUSH操作,當key存在但不是列表型別時,返回一個錯誤。 返回值: 執行LPUSH命令後,列表的長度。
程式碼演示:
# 加入單個元素
redis> LPUSH languages python
(integer) 1
# 加入重複元素
redis> LPUSH languages python
(integer) 2
redis> LRANGE languages 0 -1 # 列表允許重複元素
1) "python"
2) "python"# 加入多個元素
redis> LPUSH mylist a b c
(integer) 3
redis> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"複製程式碼
RPUSH key value [value ...]
時間複雜度O(1)。
將一個或多個值value插入到列表key的表尾(最右邊),如果有多個value值,那麼各個value值按從左到右的順序依次插入到表尾:比如說,對空列表mylist執行命令RPUSH mylist a b c,列表的值將是c b a,這等同於原子性地執行RPUSH mylist a、RPUSH mylist b和RPUSH mylist c三個命令,如果key不存在,一個空列表會被建立並執行RPUSH操作,當key存在但不是列表型別時,返回一個錯誤。 返回值: 執行RPUSH命令後,列表的長度。
程式碼演示:
# 新增單個元素
redis> RPUSH languages c
(integer) 1
# 新增重複元素
redis> RPUSH languages c
(integer) 2
redis> LRANGE languages 0 -1 # 列表允許重複元素
1) "c"
2) "c"# 新增多個元素
redis> RPUSH mylist a b c
(integer) 3
redis> LRANGE mylist 0 -1
1) "a"
2) "b"
3) "c"複製程式碼
LINDEX key index
時間複雜度O(N),N為到達下標index過程中經過的元素數量。因此,對列表的頭元素和尾元素執行LINDEX命令,複雜度為O(1)。
返回列表key中,下標為index的元素,下標(index)引數start和stop都以0為底,也就是說,以0表示列表的第一個元素,以1表示列表的第二個元素,以此類推,你也可以使用負數下標,以-1表示列表的最後一個元素,-2表示列表的倒數第二個元素,以此類推,如果key不是列表型別,返回一個錯誤。 返回值: 列表中下標為index的元素。如果index引數的值不在列表的區間範圍內(out of range),返回nil。 程式碼演示: