來自:簡書,作者:kelgon
連結:http://www.jianshu.com/p/2f14bc570563
Redis 是一個開源的,基於記憶體的結構化資料儲存媒介,可以作為資料庫、快取服務或訊息服務使用。
Redis 支援多種資料結構,包括字串、雜湊表、連結串列、集合、有序集合、點陣圖、Hyperloglogs 等。
Redis 具備 LRU 淘汰、事務實現、以及不同級別的硬碟持久化等能力,並且支援副本集和透過 Redis Sentinel 實現的高可用方案,同時還支援透過 Redis Cluster 實現的資料自動分片能力。
Redis 的主要功能都基於單執行緒模型實現,也就是說 Redis 使用一個執行緒來服務所有的客戶端請求,同時 Redis 採用了非阻塞式 IO,並精細地最佳化各種命令的演演算法時間複雜度,這些資訊意味著:
-
Redis 是執行緒安全的(因為只有一個執行緒),其所有操作都是原子的,不會因併發產生資料異常
-
Redis 的速度非常快(因為使用非阻塞式 IO,且大部分命令的演演算法時間複雜度都是 O(1))
-
使用高耗時的 Redis 命令是很危險的,會佔用唯一的一個執行緒的大量處理時間,導致所有的請求都被拖慢。(例如時間複雜度為 O(N) 的 KEYS 命令,嚴格禁止在生產環境中使用)
本文只對 Redis 命令進行扼要的介紹,且只列出了較常用的命令。如果想要瞭解完整的 Redis 命令集,或瞭解某個命令的詳細使用方法,請參考官方檔案:https://redis.io/commands
常用命令一:Key
Redis 採用 Key-Value 型的基本資料結構,任何二進位制序列都可以作為 Redis 的 Key 使用(例如普通的字串或一張 JPEG 圖片)
關於 Key 的一些註意事項:
不要使用過長的 Key。例如使用一個 1024 位元組的 key 就不是一個好主意,不僅會消耗更多的記憶體,還會導致查詢的效率降低
Key 短到缺失了可讀性也是不好的,例如”u1000flw” 比起”user:1000:followers” 來說,節省了寥寥的儲存空間,卻引發了可讀性和可維護性上的麻煩
最好使用統一的規範來設計 Key,比如”object-type:id:attr”,以這一規範設計出的 Key 可能是”user:1000” 或”comment:1234:reply-to”
Redis 允許的最大 Key 長度是 512MB(對 Value 的長度限制也是 512MB)
常用命令二:String
String 是 Redis 的基礎資料型別,Redis 沒有 Int、Float、Boolean 等資料型別的概念,所有的基本型別在 Redis 中都以 String 體現。
與 String 相關的常用命令:
-
SET:為一個 key 設定 value,可以配合 EX/PX 引數指定 key 的有效期,透過 NX/XX 引數針對 key 是否存在的情況進行區別操作,時間複雜度 O(1)
-
GET:獲取某個 key 對應的 value,時間複雜度 O(1)
-
GETSET:為一個 key 設定 value,並傳回該 key 的原 value,時間複雜度 O(1)
-
MSET:為多個 key 設定 value,時間複雜度 O(N)
-
MSETNX:同 MSET,如果指定的 key 中有任意一個已存在,則不進行任何操作,時間複雜度 O(N)
-
MGET:獲取多個 key 對應的 value,時間複雜度 O(N)
上文提到過,Redis 的基本資料型別只有 String,但 Redis 可以把 String 作為整型或浮點型數字來使用,主要體現在 INCR、DECR 類的命令上:
-
INCR:將 key 對應的 value 值自增 1,並傳回自增後的值。只對可以轉換為整型的 String 資料起作用。時間複雜度 O(1)
-
INCRBY:將 key 對應的 value 值自增指定的整型數值,並傳回自增後的值。只對可以轉換為整型的 String 資料起作用。時間複雜度 O(1)
-
DECR/DECRBY:同 INCR/INCRBY,自增改為自減。
INCR/DECR 系列命令要求操作的 value 型別為 String,並可以轉換為 64 位帶符號的整型數字,否則會傳回錯誤。
也就是說,進行 INCR/DECR 系列命令的 value,必須在 [-2^63 ~ 2^63 – 1] 範圍內。
前文提到過,Redis 採用單執行緒模型,天然是執行緒安全的,這使得 INCR/DECR 命令可以非常便利的實現高併發場景下的精確控制。
例 1:庫存控制
在高併發場景下實現庫存餘量的精準校驗,確保不出現超賣的情況。
設定庫存總量:
SET inv:remain “100”
庫存扣減 + 餘量校驗:
DECR inv:remain
當 DECR 命令傳回值大於等於 0 時,說明庫存餘量校驗透過,如果傳回小於 0 的值,則說明庫存已耗盡。
假設同時有 300 個併發請求進行庫存扣減,Redis 能夠確保這 300 個請求分別得到 99 到 – 200 的傳回值,每個請求得到的傳回值都是唯一的,絕對不會找出現兩個請求得到一樣的傳回值的情況。
例 2:自增序列生成
實現類似於 RDBMS 的 Sequence 功能,生成一系列唯一的序列號
設定序列起始值:
SET sequence “10000”
獲取一個序列值:
INCR sequence
直接將傳回值作為序列使用即可。
獲取一批(如 100 個)序列值:
INCRBY sequence 100
假設傳回值為 N,那麼 [N – 99 ~ N] 的數值都是可用的序列值。
當多個客戶端同時向 Redis 申請自增序列時,Redis 能夠確保每個客戶端得到的序列值或序列範圍都是全域性唯一的,絕對不會出現不同客戶端得到了重覆的序列值的情況。
常用命令三:List
Redis 的 List 是連結串列型的資料結構,可以使用 LPUSH/RPUSH/LPOP/RPOP 等命令在 List 的兩端執行插入元素和彈出元素的操作。雖然 List 也支援在特定 index 上插入和讀取元素的功能,但其時間複雜度較高(O(N)),應小心使用。
與 List 相關的常用命令:
-
LPUSH:向指定 List 的左側(即頭部)插入 1 個或多個元素,傳回插入後的 List 長度。時間複雜度 O(N),N 為插入元素的數量
-
RPUSH:同 LPUSH,向指定 List 的右側(即尾部)插入 1 或多個元素
-
LPOP:從指定 List 的左側(即頭部)移除一個元素並傳回,時間複雜度 O(1)
-
RPOP:同 LPOP,從指定 List 的右側(即尾部)移除 1 個元素並傳回
-
LPUSHX/RPUSHX:與 LPUSH/RPUSH 類似,區別在於,LPUSHX/RPUSHX 操作的 key 如果不存在,則不會進行任何操作
-
LLEN:傳回指定 List 的長度,時間複雜度 O(1)
-
LRANGE:傳回指定 List 中指定範圍的元素(雙端包含,即 LRANGE key 0 10 會傳回 11 個元素),時間複雜度 O(N)。應盡可能控制一次獲取的元素數量,一次獲取過大範圍的 List 元素會導致延遲,同時對長度不可預知的 List,避免使用 LRANGE key 0 -1 這樣的完整遍歷操作。
應謹慎使用的 List 相關命令:
-
LINDEX:傳回指定 List 指定 index 上的元素,如果 index 越界,傳回 nil。index 數值是迴環的,即 – 1 代表 List 最後一個位置,-2 代表 List 倒數第二個位置。時間複雜度 O(N)
-
LSET:將指定 List 指定 index 上的元素設定為 value,如果 index 越界則傳回錯誤,時間複雜度 O(N),如果操作的是頭 / 尾部的元素,則時間複雜度為 O(1)
-
LINSERT:向指定 List 中指定元素之前 / 之後插入一個新元素,並傳回操作後的 List 長度。如果指定的元素不存在,傳回 – 1。如果指定 key 不存在,不會進行任何操作,時間複雜度 O(N)
由於 Redis 的 List 是連結串列結構的,上述的三個命令的演演算法效率較低,需要對 List 進行遍歷,命令的耗時無法預估,在 List 長度大的情況下耗時會明顯增加,應謹慎使用。
換句話說,Redis 的 List 實際是設計來用於實現佇列,而不是用於實現類似 ArrayList 這樣的串列的。如果你不是想要實現一個雙端出入的佇列,那麼請儘量不要使用 Redis 的 List 資料結構。
為了更好支援佇列的特性,Redis 還提供了一系列阻塞式的操作命令,如 BLPOP/BRPOP 等,能夠實現類似於 BlockingQueue 的能力,即在 List 為空時,阻塞該連線,直到 List 中有物件可以出隊時再傳回。針對阻塞類的命令,此處不做詳細探討,請參考官方檔案(https://redis.io/topics/data-types-intro) 中”Blocking operations on lists” 一節。
常用命令四:Hash
Hash 即雜湊表,Redis 的 Hash 和傳統的雜湊表一樣,是一種 field-value 型的資料結構,可以理解成將 HashMap 搬入 Redis。
Hash 非常適合用於表現物件型別的資料,用 Hash 中的 field 對應物件的 field 即可。
Hash 的優點包括:
-
可以實現二元查詢,如” 查詢 ID 為 1000 的使用者的年齡”
-
比起將整個物件序列化後作為 String 儲存的方法,Hash 能夠有效地減少網路傳輸的消耗
-
當使用 Hash 維護一個集合時,提供了比 List 效率高得多的隨機訪問命令
與 Hash 相關的常用命令:
-
HSET:將 key 對應的 Hash 中的 field 設定為 value。如果該 Hash 不存在,會自動建立一個。時間複雜度 O(1)
-
HGET:傳回指定 Hash 中 field 欄位的值,時間複雜度 O(1)
-
HMSET/HMGET:同 HSET 和 HGET,可以批次操作同一個 key 下的多個 field,時間複雜度:O(N),N 為一次操作的 field 數量
-
HSETNX:同 HSET,但如 field 已經存在,HSETNX 不會進行任何操作,時間複雜度 O(1)
-
HEXISTS:判斷指定 Hash 中 field 是否存在,存在傳回 1,不存在傳回 0,時間複雜度 O(1)
-
HDEL:刪除指定 Hash 中的 field(1 個或多個),時間複雜度:O(N),N 為操作的 field 數量
-
HINCRBY:同 INCRBY 命令,對指定 Hash 中的一個 field 進行 INCRBY,時間複雜度 O(1)
應謹慎使用的 Hash 相關命令:
-
HGETALL:傳回指定 Hash 中所有的 field-value 對。傳回結果為陣列,陣列中 field 和 value 交替出現。時間複雜度 O(N)
-
HKEYS/HVALS:傳回指定 Hash 中所有的 field/value,時間複雜度 O(N)
上述三個命令都會對 Hash 進行完整遍歷,Hash 中的 field 數量與命令的耗時線性相關,對於尺寸不可預知的 Hash,應嚴格避免使用上面三個命令,而改為使用 HSCAN 命令進行遊標式的遍歷,具體請見 https://redis.io/commands/scan
常用命令五:Set
Redis Set 是無序的,不可重覆的 String 集合。
與 Set 相關的常用命令:
-
SADD:向指定 Set 中新增 1 個或多個 member,如果指定 Set 不存在,會自動建立一個。時間複雜度 O(N),N 為新增的 member 個數
-
SREM:從指定 Set 中移除 1 個或多個 member,時間複雜度 O(N),N 為移除的 member 個數
-
SRANDMEMBER:從指定 Set 中隨機傳回 1 個或多個 member,時間複雜度 O(N),N 為傳回的 member 個數
-
SPOP:從指定 Set 中隨機移除並傳回 count 個 member,時間複雜度 O(N),N 為移除的 member 個數
-
SCARD:傳回指定 Set 中的 member 個數,時間複雜度 O(1)
-
SISMEMBER:判斷指定的 value 是否存在於指定 Set 中,時間複雜度 O(1)
-
SMOVE:將指定 member 從一個 Set 移至另一個 Set
慎用的 Set 相關命令:
-
SMEMBERS:傳回指定 Hash 中所有的 member,時間複雜度 O(N)
-
SUNION/SUNIONSTORE:計算多個 Set 的並集並傳回 / 儲存至另一個 Set 中,時間複雜度 O(N),N 為參與計算的所有集合的總 member 數
-
SINTER/SINTERSTORE:計算多個 Set 的交集並傳回 / 儲存至另一個 Set 中,時間複雜度 O(N),N 為參與計算的所有集合的總 member 數
-
SDIFF/SDIFFSTORE:計算 1 個 Set 與 1 或多個 Set 的差集並傳回 / 儲存至另一個 Set 中,時間複雜度 O(N),N 為參與計算的所有集合的總 member 數。
上述幾個命令涉及的計算量大,應謹慎使用,特別是在參與計算的 Set 尺寸不可知的情況下,應嚴格避免使用。可以考慮透過 SSCAN 命令遍歷獲取相關 Set 的全部 member(具體請見 https://redis.io/commands/scan ),如果需要做並集 / 交集 / 差集計算,可以在客戶端進行,或在不服務實時查詢請求的 Slave 上進行。
常用命令六:Sorted Set
Redis Sorted Set 是有序的、不可重覆的 String 集合。Sorted Set 中的每個元素都需要指派一個分數 (score),Sorted Set 會根據 score 對元素進行升序排序。如果多個 member 擁有相同的 score,則以字典序進行升序排序。
Sorted Set 非常適合用於實現排名。
Sorted Set 的主要命令:
-
ZADD:向指定 Sorted Set 中新增 1 個或多個 member,時間複雜度 O(Mlog(N)),M 為新增的 member 數量,N 為 Sorted Set 中的 member 數量
-
ZREM:從指定 Sorted Set 中刪除 1 個或多個 member,時間複雜度 O(Mlog(N)),M 為刪除的 member 數量,N 為 Sorted Set 中的 member 數量
-
ZCOUNT:傳回指定 Sorted Set 中指定 score 範圍內的 member 數量,時間複雜度:O(log(N))
-
ZCARD:傳回指定 Sorted Set 中的 member 數量,時間複雜度 O(1)
-
ZSCORE:傳回指定 Sorted Set 中指定 member 的 score,時間複雜度 O(1)
-
ZRANK/ZREVRANK:傳回指定 member 在 Sorted Set 中的排名,ZRANK 傳回按升序排序的排名,ZREVRANK 則傳回按降序排序的排名。時間複雜度 O(log(N))
-
ZINCRBY:同 INCRBY,對指定 Sorted Set 中的指定 member 的 score 進行自增,時間複雜度 O(log(N))
慎用的 Sorted Set 相關命令:
-
ZRANGE/ZREVRANGE:傳回指定 Sorted Set 中指定排名範圍內的所有 member,ZRANGE 為按 score 升序排序,ZREVRANGE 為按 score 降序排序,時間複雜度 O(log(N)+M),M 為本次傳回的 member 數
-
ZRANGEBYSCORE/ZREVRANGEBYSCORE:傳回指定 Sorted Set 中指定 score 範圍內的所有 member,傳回結果以升序 / 降序排序,min 和 max 可以指定為 – inf 和 + inf,代表傳回所有的 member。時間複雜度 O(log(N)+M)
-
ZREMRANGEBYRANK/ZREMRANGEBYSCORE:移除 Sorted Set 中指定排名範圍 / 指定 score 範圍內的所有 member。時間複雜度 O(log(N)+M)
上述幾個命令,應儘量避免傳遞 [0 -1] 或 [-inf +inf] 這樣的引數,來對 Sorted Set 做一次性的完整遍歷,特別是在 Sorted Set 的尺寸不可預知的情況下。可以透過 ZSCAN 命令來進行遊標式的遍歷(具體請見 https://redis.io/commands/scan ),或透過 LIMIT 引數來限制傳回 member 的數量(適用於 ZRANGEBYSCORE 和 ZREVRANGEBYSCORE 命令),以實現遊標式的遍歷。
常用命令七:Bitmap 和 HyperLogLog
Redis 的這兩種資料結構相較之前的並不常用,在本文中只做簡要介紹,如想要詳細瞭解這兩種資料結構與其相關的命令,請參考官方檔案 https://redis.io/topics/data-types-intro 中的相關章節
Bitmap 在 Redis 中不是一種實際的資料型別,而是一種將 String 作為 Bitmap 使用的方法。可以理解為將 String 轉換為 bit 陣列。使用 Bitmap 來儲存 true/false 型別的簡單資料極為節省空間。
HyperLogLogs 是一種主要用於數量統計的資料結構,它和 Set 類似,維護一個不可重覆的 String 集合,但是 HyperLogLogs 並不維護具體的 member 內容,只維護 member 的個數。也就是說,HyperLogLogs 只能用於計算一個集合中不重覆的元素數量,所以它比 Set 要節省很多記憶體空間。
其他常用命令
-
EXISTS:判斷指定的 key 是否存在,傳回 1 代表存在,0 代表不存在,時間複雜度 O(1)
-
DEL:刪除指定的 key 及其對應的 value,時間複雜度 O(N),N 為刪除的 key 數量
-
EXPIRE/PEXPIRE:為一個 key 設定有效期,單位為秒或毫秒,時間複雜度 O(1)
-
TTL/PTTL:傳回一個 key 剩餘的有效時間,單位為秒或毫秒,時間複雜度 O(1)
-
RENAME/RENAMENX:將 key 重新命名為 newkey。使用 RENAME 時,如果 newkey 已經存在,其值會被改寫;使用 RENAMENX 時,如果 newkey 已經存在,則不會進行任何操作,時間複雜度 O(1)
-
TYPE:傳回指定 key 的型別,string, list, set, zset, hash。時間複雜度 O(1)
-
CONFIG GET:獲得 Redis 某配置項的當前值,可以使用 * 萬用字元,時間複雜度 O(1)
-
CONFIG SET:為 Redis 某個配置項設定新值,時間複雜度 O(1)
-
CONFIG REWRITE:讓 Redis 重新載入 redis.conf 中的配置
●編號420,輸入編號直達本文
●輸入m獲取文章目錄
Web開發
更多推薦《18個技術類微信公眾號》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。