Redis從入門到精通:中級篇

五月的倉頡發表於2018-05-01

原文連結:http://www.cnblogs.com/xrq730/p/8944539.html,轉載請註明出處,謝謝

 

本文目錄

上一篇文章以認識Redis為主,寫了Redis系列的第一篇,現在開啟第二部分的學習,在本文中,我們將看到以下內容:

  • Redis資料結構String、Hash、List、Set、SortedSet及相關操作,提一下Redis在3.2.0之後有新增了一種GEO的資料型別表示地理位置,不過本文這種資料結構略過
  • Redis其他一些常用命令,分為Key操作與伺服器操作
  • Redis事務機制

主要以實戰為主,希望通過本文可以讓大家掌握Redis的基本使用。

本來這篇文章還準備加上Redis執行緒模型分析的,但是寫完發現篇幅實在太長,就把Redis執行緒模型放到最後一篇中了,也挺好的,本文專注於對Redis命令的講解。

另外說一下,本文講Redis中的資料結構,但是資料結構本身不在本文的講解範圍內,如果想知道Hash、List、Set等資料結構特點及使用場景,可以自己查閱資料結構相關資料。

 

String資料結構的基本操作

首先說一下資料結構String,這是Redis中最簡單的一種資料結構,和MemCache資料結構是一樣的,即Key-Value型的資料,根據Redis官方文件,Value最大值為512M

下面用表格來看一下String操作的相關命令:

命令 描述 用法
SET

(1)將字串值Value關聯到Key

(2)Key已關聯則覆蓋,無視型別

(3)原本Key帶有生存時間TTL,那麼TTL被清除

SET key value [EX seconds] [PX milliseconds] [NX|XX]
GET

(1)返回key關聯的字串值

(2)Key不存在返回nil

(3)Key儲存的不是字串,返回錯誤,因為GET只用於處理字串

GET key
MSET

(1)同時設定一個或多個Key-Value鍵值對

(2)某個給定Key已經存在,那麼MSET新值會覆蓋舊值

(3)如果上面的覆蓋不是希望的,那麼使用MSETNX命令,所有Key都不存在才會進行覆蓋

(4)MSET是一個原子性操作,所有Key都會在同一時間被設定,不會存在有些更新有些沒更新的情況

MSET key value [key value ...]
MGET

(1)返回一個或多個給定Key對應的Value

(2)某個Key不存在那麼這個Key返回nil

MGET key [key ...]
SETEX

(1)將Value關聯到Key

(2)設定Key生存時間為seconds,單位為秒

(3)如果Key對應的Value已經存在,則覆蓋舊值

(4)SET也可以設定失效時間,但是不同在於SETNX是一個原子操作,即關聯值與設定生存時間同一時間完成

SETEX key seconds value
SETNX

(1)將Key的值設定為Value,當且僅當Key不存在

(2)若給定的Key已經存在,SEXNX不做任何動作

SETNX key value

首先,演示一下SET、GET、SETEX的效果:

圖中我們應該能看到SET、GET、SETNX幾個命令的效果了,在這之外,專門提兩點:

  • Redis的命令不區分大小寫
  • Redis的Key區分大小寫

接著我們演示一下SETEX命令的效果:

這裡順帶介紹了TIME命令,它返回的是當前伺服器Unix時間戳,但單位為秒(通常Unix時間戳取的時間為毫秒)。看到設定Redis-Expire這個Key,馬上獲取不失效,第26秒獲取的時候失效,關於失效,Redis的策略是這樣的:

  • 被動觸發,即GET的時候檢查一下Key是否失效
  • 主動觸發,後臺每1秒跑10次定時任務(通過redis.conf的hz引數配置,預設為10,這個上文沒有寫),隨機選擇100個設定了過期時間的Key,對過期的Key進行失效

最後看一下MGET和MSET命令:

看到可以同時設定多個Key-Value,也可以同時獲取多個Key對應的Value,再次注意,Redis的Key是嚴格區分大小寫的。

 

特殊的String操作:INCR/DECR

前面介紹的是基本的Key-Value操作,下面介紹一種特殊的Key-Value操作即INCR/DECR,可以利用Redis自動幫助我們對一個Key對應的Value進行加減,用表格看一下相關命令:

命令 描述 用法
INCR

(1)Key中儲存的數字值+1,返回增加之後的值

(2)Key不存在,那麼Key的值被初始化為0再執行INCR

(3)如果值包含錯誤型別或者字串不能被表示為數字,那麼返回錯誤

(4)值限制在64位有符號數字表示之內,即-9223372036854775808~9223372036854775807

INCR key
DECR

(1)Key中儲存的數字值-1

(2)其餘同INCR

DECR key
INCRBY

(1)將key所儲存的值加上增量返回增加之後的值

(2)其餘同INCR

INCRBY key increment
DECRBY

(1)將key所儲存的值減去減量decrement

(2)其餘同INCR

DECRBY key decrement

下面實際看一下四個命令相關使用:

INCR/DECR在實際工作中還是非常管用的,舉兩個例子:

  • 原先單機環境中統計線上人數,變成分散式部署之後可以使用INCR/DECR
  • 由於Redis本身極高的讀寫效能,一些秒殺的場景庫存增減可以基於Redis來做而不是直接操作DB

 

Hash資料結構相關操作

接著講一下Hash,Hash本質上和String是一樣的,無非String是純粹的Key-Value,Hash是外面套了一層東西,裡面還是Key-Value,接著我們用表格看一下Hash資料結構的相關命令:

命令 描述 用法
HSET

(1)將雜湊表Key中的域field的值設為value

(2)key不存在,一個新的Hash表被建立

(3)field已經存在,舊的值被覆蓋

HSET key field value
HGET (1)返回雜湊表key中給定域field的值 HGET key field
HDEL

(1)刪除雜湊表key中的一個或多個指定域

(2)不存在的域將被忽略

HDEL key filed [field ...]
HEXISTS (1)檢視雜湊表key中,給定域field是否存在,存在返回1,不存在返回0 HEXISTS key field
 HGETALL  (1)返回雜湊表key中,所有的域和值  HGETALL key 
HINCRBY

 (1)為雜湊表key中的域field加上增量increment

(2)其餘同INCR命令

HINCRYBY key filed increment 
HKEYS (1)返回雜湊表key中的所有域  HKEYS key
HLEN (1)返回雜湊表key中域的數量  HLEN key 
HMGET

(1)返回雜湊表key中,一個或多個給定域的值

(2)如果給定的域不存在於雜湊表,那麼返回一個nil值

HMGET key field [field ...]
HMSET

(1)同時將多個field-value對設定到雜湊表key中

(2)會覆蓋雜湊表中已存在的域

(3)key不存在,那麼一個空雜湊表會被建立並執行HMSET操作

HMSET key field value [field value ...]
HVALS (1)返回雜湊表key中所有的域和值 HVALS key

同樣的,實際看一下這些命令的相關使用:

稍亂,但是除了HMSET、HMGET以外把所有命令都演示到了。

 

List資料結構相關操作

接著我們看一下Redis中的List,相關命令有:

命令 描述 用法
LPUSH

(1)將一個或多個值value插入到列表key的表頭

(2)如果有多個value值,那麼各個value值按從左到右的順序依次插入表頭

(3)key不存在,一個空列表會被建立並執行LPUSH操作

(4)key存在但不是列表型別,返回錯誤

LPUSH key value [value ...]
LPUSHX

(1)將值value插入到列表key的表頭,當且晉檔key存在且為一個列表

(2)key不存在時,LPUSHX命令什麼都不做

LPUSHX key value
LPOP

(1)移除並返回列表key的頭元素

LPOP key
LRANGE

(1)返回列表key中指定區間內的元素,區間以偏移量start和stop指定

(2)start和stop都以0位底

(3)可使用負數下標,-1表示列表最後一個元素,-2表示列表倒數第二個元素,以此類推

(4)start大於列表最大下標,返回空列表

(5)stop大於列表最大下標,stop=列表最大下標

LRANGE key start stop
LREM

(1)根據count的值,移除列表中與value相等的元素

(2)count>0表示從頭到尾搜尋,移除與value相等的元素,數量為count

(3)count<0表示從從尾到頭搜尋,移除與value相等的元素,數量為count

(4)count=0表示移除表中所有與value相等的元素

LREM key count value
LSET

(1)將列表key下標為index的元素值設為value

(2)index引數超出範圍,或對一個空列表進行LSET時,返回錯誤

LSET key index value
LINDEX

(1)返回列表key中,下標為index的元素

LINDEX key index
LINSERT

(1)將值value插入列表key中,位於pivot前面或者後面

(2)pivot不存在於列表key時,不執行任何操作

(3)key不存在,不執行任何操作

LINSERT key BEFORE|AFTER pivot value
LLEN

(1)返回列表key的長度

(2)key不存在,返回0

LLEN key
LTRIM (1)對一個列表進行修剪,讓列表只返回指定區間內的元素,不存在指定區間內的都將被移除 LTRIM key start stop
RPOP (1)移除並返回列表key的尾元素 RPOP key
RPOPLPUSH

在一個原子時間內,執行兩個動作:

(1)將列表source中最後一個元素彈出並返回給客戶端

(2)將source彈出的元素插入到列表desination,作為destination列表的頭元素

RPOPLPUSH source destination
RPUSH (1)將一個或多個值value插入到列表key的表尾 RPUSH key value [value ...]
RPUSHX

(1)將value插入到列表key的表尾,當且僅當key存在並且是一個列表

(2)key不存在,RPUSHX什麼都不做

RPUSHX key value

接著看一下這些命令的實際使用效果:

工具所限,LSET、LINSERT、RPOPLPUSH幾個命令沒法演示,上面演示了其他的基本命令,應該足以理解Redis的List了,操作List千萬注意區分LPUSH、RPUSH兩個命令,把資料新增到表頭和把資料新增到表尾是完全不一樣的兩種結果

另外List還有BLPOP、BRPOP、BRPOPLPUSH三個命令沒有說,它們是幾個POP的阻塞版本,即沒有資料可以彈出的時候將阻塞客戶端直到超時或者發現有可以彈出的元素為止

 

SET資料結構相關操作

接著我們看一下SET資料結構的相關操作:

命令 描述 用法
SADD 

(1)將一個或多個member元素加入到key中,已存在在集合的member將被忽略

(2)假如key不存在,則只建立一個只包含member元素做成員的集合

(3)當key不是集合型別時,將返回一個錯誤 

SADD key number [member ...] 
SCARD   (1)返回key對應的集合中的元素數量  SCARD key
SDIFF  (1)返回一個集合的全部成員,該集合是第一個Key對應的集合和後面key對應的集合的差集  SDIFF key [key ...]
 SDIFFSTORE

(1)和SDIFF類似,但結果儲存到destination集合而不是簡單返回結果集

(2) destination如果已存在,則覆蓋

SDIFFSTORE destionation key [key ...] 
 SINTER

 (1)返回一個集合的全部成員,該集合是所有給定集合的交集

(2)不存在的key被視為空集

SINTER key [key ...] 
SINTERSTORE 

(1)和SINTER類似,但結果儲存早destination集合而不是簡單返回結果集

(2)如果destination已存在,則覆蓋

(3)destination可以是key本身

SINTERSTORE destination key [key ...] 
SISMEMBER  (1)判斷member元素是否key的成員,0表示不是,1表示是  SISMEMBER key member 
SMEMBERS

 (1)返回集合key中的所有成員

(2)不存在的key被視為空集

SMEMBERS key 
SMOVE 

(1)原子性地將member元素從source集合移動到destination集合

(2)source集合中不包含member元素,SMOVE命令不執行任何操作,僅返回0

(3)destination中已包含member元素,SMOVE命令只是簡單做source集合的member元素移除

 SMOVE source desination member
SPOP

(1)移除並返回集合中的一個隨機元素,如果count不指定那麼隨機返回一個隨機元素

(2)count為正數且小於集合元素數量,那麼返回一個count個元素的陣列且陣列中的元素各不相同

(3)count為正數且大於等於集合元素數量,那麼返回整個集合

(4)count為負數那麼命令返回一個陣列,陣列中的元素可能重複多次,數量為count的絕對值

SPOP key [count]
SRANDMEMBER

(1)如果count不指定,那麼返回集合中的一個隨機元素

(2)count同上

SRANDMEMBER key [count]
SREM (1)移除集合key中的一個或多個member元素,不存在的member將被忽略 SREM key member [member ...]
SUNION

(1)返回一個集合的全部成員,該集合是所有給定集合的並集

(2)不存在的key被視為空集

SUNION key [key ...]
SUNIONSTORE

(1)類似SUNION,但結果儲存到destination集合而不是簡單返回結果集

(2)destination已存在,覆蓋舊值

(3)destination可以是key本身

SUNION destination key [key ...]

同樣,實際測試一下Set:

除了SINTER沒有用到,其他應該比較全面地展示了Set的相關使用。

 

SortedSet資料結構相關操作

資料結構最後說一下SortedSet相關操作,最近有一個場景需要實現Redis分頁+高效移除資料,一下子沒找到好的資料結構,後來想起了SortedSet才解決了問題,看來積累與儲備還是非常有用的,

SortedSet顧名思義,即有序的Set,看下相關命令:

命令 描述 用法
ZADD

(1)將一個或多個member元素及其score值加入有序集key中

(2)如果member已經是有序集的成員,那麼更新member對應的score並重新插入member保證member在正確的位置上

(3)score可以是整數值或雙精度浮點數

ZADD key score member [[score member] [score member] ...]
ZCARD  (1)返回有序集key的元素個數 ZCARD key 
 ZCOUNT  (1) 返回有序集key中,score值>=min且<=max的成員的數量 ZCOUNT key min max 
ZRANGE 

 (1)返回有序集key中指定區間內的成員,成員位置按score從小到大排序

(2)具有相同score值的成員按字典序排列

(3)需要成員按score從大到小排列,使用ZREVRANGE命令

(4)下標引數start和stop都以0為底,也可以用負數,-1表示最後一個成員,-2表示倒數第二個成員

(5)可通過WITHSCORES選項讓成員和它的score值一併返回

ZRANGE key start stop [WITHSCORES] 
ZRANK

 (1)返回有序集key中成員member的排名,有序整合員按score值從小到大排列

(2)排名以0為底,即score最小的成員排名為0

(3)ZREVRANK命令可將成員按score值從大到小排名

ZRANK key number 
ZREM

(1)移除有序集key中的一個或多個成員,不存在的成員將被忽略

(2)當key存在但不是有序集時,返回錯誤 

ZREM key member [member ...] 
ZREMRANGEBYRANK (1)移除有序集key中指定排名區間內的所有成員  ZREMRANGEBYRANK key start stop 
ZREMRANGEBYSCORE (1)移除有序集key中,所有score值>=min且<=max之間的成員  ZREMRANGEBYSCORE key min max 

還有若干不是很常用的命令沒有寫,就略過了,有興趣的可以自己看一下,接著看一下SortedSet實際使用: 

這個地方排名的時候稍微注意下,和我們認為的排名有些微區別,比如1 1 2 3,由於有兩個1,因此3正序的Rank應當為2(以0為下標),但實際上會是3,所以Rank應當理解為元素在集合中的下標位置更加準確

 

Redis的Key相關操作

寫完了Redis的資料結構,接著我們看下Redis的Key相關操作:

命令 描述 用法
DEL

(1)刪除給定的一個或多個key

(2)不存在的Key將被忽略

DEL key [key ...]
EXISTS (1)檢查給定key是否存在 EXISTS key
EXPIRE

(1)為給定key設定生存時間,key過期時它會被自動刪除

(2)對一個已經指定生存時間的Key設定執行EXPIRE,新的值會代替舊的值

EXPIRE key seconds
EXPIREAT (1)同EXPIRE,但此命令指定的是UNIX時間戳,單位為秒 EXPIRE key timestamp
KEYS

(1)查詢所有符合給定模式pattern的key,下面舉一下例子

(2)KEYS *匹配所有key

(3)KEYS h?llo匹配hello、hallo、hxllo等

(4)KEYS h*llo匹配hllo、heeeeello等

(5)KEYS h[ae]llo匹配hello和hallo

(6)特殊符號想當做查詢內容經的使用\

KEYS pattern

MIGRATE 

 (1)原子性地將key從當前例項傳送到目標例項指定的資料庫上

(2)原資料庫Key刪除,新資料庫Key增加

(3)阻塞進行遷移的兩個例項,直到遷移成功、遷移失敗、等待超時三個之一發生

MIGRATE host port key destination-db timeout [COPY] [REPLACE] 

 MOVE

 (1)將當前資料庫的key移動到給定資料庫的db中

(2)執行成功的條件為當前資料庫有key,給定資料庫沒有key

MOVE key db 
PERSIST   (1)移除給定key的生存時間,將key變為持久的 PERSIST key
RANDOMKEY  (1)從當前資料庫隨機返回且不刪除一個key, RANDOMKEY 
RENAME

(1)將key改名為newkey

(2)當key和newkey相同或key不存在,報錯

(3)newkey已存在,RENAME將覆蓋舊值

RENAME key newkey
TTL (1)以秒為單位,返回給定的key剩餘生存時間 TTL key
PTTL (1)以毫秒為單位,返回給定的key剩餘生存時間 PTTL key
TYPE (1)返回key鎖儲存的值的型別 TYPE key

簡單看一下實際使用:

這裡特別注意KEYS命令,雖然KEYS命令速度非常快,但是當Redis中百萬、千萬甚至過億資料的時候,掃描所有Redis的Key,速度仍然會下降,由於Redis是單執行緒模型,這將導致後面的命令阻塞直到KEYS命令執行完。

因此當Redis中儲存的資料達到了一定量級(經驗值從10W開始就值得注意了)的時候,必須警惕KEYS造成Redis整體效能下降

 

系統相關命令

接著介紹一下部分系統相關命令:

命令 描述 用法
BGREWRITEAOF (1)手動觸發AOF重寫操作,用於減小AOF檔案體積 BGREWRITEAOF
BGSAVE (1)後臺非同步儲存當前資料庫的資料到磁碟 BGSAVE
CLIENT KILL

(1)關閉地址為ip:port的客戶端

(2)由於Redis為單執行緒設計,因此噹噹前命令執行完之後才會關閉客戶端

CLIENT KILL ip:port
CLIENT LIST (1)以可讀的格式,返回所有連線到伺服器的客戶端資訊和統計資料 CLIENT LIST
CONFIG GET

(1)取得執行中的Redis伺服器配置引數

(2)支援*

CONFIG GET parameter
CONFIG RESETSTAT (1)重置INFO命令中的某些統計資料,例如Keyspace hits、Keyspace misses等 CONFIG RESETSTAT
CONFIG REWRITE (1)對啟動Redis時指定的redis.conf檔案進行改寫 CONFIG REWRITE
CONFIG SET

(1)動態調整Redis伺服器的配置而無需重啟

(2)修改後的配置立即生效

CONFIG SET parameter value
SELECT

(1)切換到指定資料庫,資料庫索引index用數字指定,以0作為起始索引值

(2)預設使用0號資料庫

SELECT index
DBSIZE (1)返回當前資料庫的Key的數量 DBSIZE
DEBUG OBJECT

(1)這是一個除錯命令,不應當被客戶端使用

(2)key存在時返回有關資訊,key不存在時返回錯誤

DEBUG OBJECT key
FLUSHALL (1)清空整個Redis伺服器的資料 FLUSHALL
FLUSHDB (1)清空當前資料庫中的所有資料 FLUSHDB
INFO

(1)以一種易於解釋且易於閱讀的格式,返回Redis伺服器的各種資訊和統計數值

(2)通過給定可選引數section,可以讓命令只返回某一部分資訊

INFO [section]
LASTSAVE (1)返回最近一次Redis成功將資料儲存到磁碟上的時間,以UNIX時間戳格式表示 LASTSAVE
MONITOR (1)實時列印出Redis伺服器接收到的命令,除錯用 MONITOR
SHUTDOWN

(1)停止所有客戶端

(2)如果至少有一個儲存點在等待,執行SAVE命令

(3)如果AOF選項被開啟,更新AOF檔案

(4)關閉Redis伺服器

SHUTDOWN [SAVE|NOSAVE]

看下命令的使用演示:

SELECT命令忘了,想起來的時候資料庫已經清空了就算了,使用SELECT後控制檯會變成"127.0.0.1:6379[3]>",即帶上資料庫的index。

 

Redis的事務

最後,本文簡單說一下Redis的事務機制,首先Redis的事務是由DISCARD、EXEC、MULTI、UNWATCH、WATCH五個命令來保證的:

命令 描述 用法
DISCARD

(1)取消事務

(2)如果正在使用WATCH命令監視某個/某些key,那麼取消所有監視,等同於執行UNWATCH

DISCARD
EXEC

(1)執行所有事務塊內的命令

(2)如果某個/某些key正處於WATCH命令監視之下且事務塊中有和這個/這些key相關的命令,那麼EXEC命令只在這個/這些key沒有被其他命令改動的情況下才會執行並生效,否則該事務被打斷

EXEC
MULTI

(1)標記一個事務塊的開始

(2)事務塊內的多條命令會按照先後順序被放入一個佇列中,最後由EXEC命令原子性地執行

MULTI
UNWATCH

(1)取消WATCH命令對所有key的監視

(2)如果WATCH之後,EXEC/DISCARD命令先被執行了,UNWATCH命令就沒必要執行了

UNWATCH
WATCH (1)監視一個/多個key,如果在事務執行之前這個/這些key被其他命令改動,那麼事務將被打斷 WATCH key [key ...]

首先我們看一下事務沒有被打斷的情況:

看到開啟事務之後,所有的命令返回的都是QUEUED,即放入佇列,而不是直接執行。

接著模擬一下事務被打斷的情況,WATCH一下Number這個Key,我另外起了一個Redis客戶端INCR了一下Number,結果為:

看到,並沒有命令被執行,返回nil即事務被打斷。

接著簡單說一下事務,和資料庫類似的,事務保證的是兩點:

  • 隔離,所有命令序列化、按順序執行,事務執行過程中不會被其他客戶端發來的命令打斷
  • 原子性,事務中的命令要麼全部執行,要麼全部不執行

另外,Redis的事務並不支援回滾,這個其實網上已經說法挺多了,大致上是兩個原因:

  • Redis命令只會因為語法而失敗(且這些問題不能再入隊時被發現),或是命令用在了錯誤型別的鍵上面,也就是說,從實用性角度來說,失敗的命令是由於程式設計錯誤造成的,而這些錯誤應該在開發的過程中被發現而不應該出現在生產環境中
  • Redis內部可以保持簡單且快速,因為不需要對回滾進行支援

總而言之,對Redis來說,回滾無法解決程式設計錯誤帶來的問題,因此還不如更簡單、更快速地無回滾處理事務。

 

下期預告

最後預告一下最後一篇文章會寫的內容,四部分:

  • Redis執行緒模型
  • Redis的RDB
  • Redis的AOF
  • Redis的叢集方式

喜歡的朋友可以關注一下最後一篇文章。

相關文章