1. 概述
Redis 一個開源的基于鍵值對(Key-Value)NoSQL 資料庫,使用 ANSIC 語言撰寫、支持網路、基于記憶體但支持持久化,性能優秀,并提供多種語言的 API,
我們要首先理解一點,我們把 Redis 稱為 KV 資料庫,鍵值對資料庫,那就可以把 Redis 內部的存盤視為存在著一個巨大的 Map,對 Map 的操作無非就是get 和 put,然后通過 key 操作這個 key 所對應的 value,而這個 value 的型別可以多種多樣,也就是 Redis 為我們提供的那些資料結構,比如字串(String)、哈希(Hash)等等,
Redis 會將所有資料都存放在記憶體中,所以它的讀寫性能非常驚人,不僅如此,Redis 還可以將記憶體的資料利用快照和日志的形式保存到硬碟上,這樣在發生類似斷電或者機器故障的時候,記憶體中的資料不會丟失,
除了上述功能以外,Redis 還提供了鍵過期、發布訂閱、事務、流水線、Lua 腳本等附加功能,
1.1 應用場景
快取
快取機制幾乎在所有的大型網站都有使用,合理地使用快取不僅可以加快資料的訪問速度,而且能夠有效地降低后端資料源的壓力,Redis 提供了鍵值過期時間設定,并且也提供了靈活控制最大記憶體和記憶體溢位后的淘汰策略,可以這么說,一個合理的快取設計能夠為一個網站的穩定保駕護航,
排行榜系統
排行榜系統幾乎存在于所有的網站,例如按照熱度排名的排行榜,按照發布時間的排行榜,按照各種復雜維度計算出的排行榜,Redis 提供了串列和有序集合資料結構,合理地使用這些資料結構可以很方便地構建各種排行榜系統,
計數器應用
計數器在網站中的作用至關重要,例如視頻網站有播放數、電商網站有瀏覽數,為了保證資料的實時性,每一次播放和瀏覽都要做+1 的操作,如果并發量很大對于傳統關系型資料的性能是一種挑戰,Redis 天然支持計數功能而且計數的性能也非常好,可以說是計數器系統的重要選擇,
社交網路
贊/踩、粉絲、共同好友/喜好、推送、下拉重繪等是社交網站的必備功能,由于社交網站訪問量通常比較大,而且傳統的關系型資料不太適合保存這種型別的資料,Redis 提供的資料結構可以相對比較容易地實作這些功能,
訊息佇列系統
訊息佇列系統可以說是一個大型網站的必備基礎組件,因為其具有業務解耦、 非實時業務削峰等特性,Redis 提供了發布訂閱功能和阻塞佇列的功能,雖然和專業的訊息佇列比還不夠足夠強大,但是對于一般的訊息佇列功能基本可以滿足,(我上家公司就用過 Redis 做訊息佇列,雖然后面換了其他 MQ),
1.2 特性
速度快
正常情況下,Redis 執行命令的速度非常快,官方給出的數字是讀寫性能可以達到 10 萬/秒,
基于鍵值對的資料結構服務器
幾乎所有的編程語言都提供了類似字典的功能,例如 Java 里的 map,類似于這種組織資料的方式叫作基于鍵值的方式,與很多鍵值對資料庫不同的是,Redis 中的值不僅可以是字串,而且還可以是具體的資料結構,這樣不僅能便于在許多應用場景的開發,同時也能夠提高開發效率,
Redis 的全稱是 Remote Dictionary Server,它主要提供了 5 種資料結構:字串、哈希、串列、集合、有序集合,同時在字串的基礎之上演變出了位圖(Bitmaps)和 HyperLogLog 兩種資料結構,并且隨著 LBS (Location BasedService,基于位置服務)的不斷發展,Redis 中加入有關 GEO(地理資訊定位)的功能,
豐富的功能
除了 5 種資料結構,Redis 還提供了許多額外的功能:提供了鍵過期功能,可以用來實作快取,
提供了發布訂閱功能,可以用來實作訊息系統,支持 Lua 腳本功能,可以利用 Lua 創造出新的 Redis 命令,提供了簡單的事務功能,能在一定程度上保證事務特性,提供了流水線(Pipeline)功能,這樣客戶端能將一批命令一次性傳到 Redis,減少了網路的開銷,
簡單穩定
Redis 的簡單主要表現在三個方面,
首先,Redis 的原始碼很少,早期版本的代碼只有 2 萬行左右,3.0 版本以后由于添加了集群特性,代碼增至 5 萬行左右,
其次,Redis 使用單執行緒模型,這樣不僅使得 Redis 服務端處理模型變得簡單,而且也使得客戶端開發變得簡單,
最后,Redis 不需要依賴于作業系統中的類別庫,
Redis 雖然很簡單,但是不代表它不穩定,實際的運行中很少出現因為 Redis 自身 bug 而宕掉的情況,
客戶端語言多
Redis 提供了簡單的 TCP 通信協議,很多編程語言可以很方便地接人到 Redis,
持久化
通常看,將資料放在記憶體中是不安全的,一旦發生斷電或者機器故障,重要的資料可能就會丟失,因此Redis提供了兩種持久化方式:RDB 和 AOF,即可以用兩種策略將記憶體的資料保存到硬碟中,這樣就保證了資料的可持久性,
主從復制
Redis 提供了復制功能,實作了多個相同資料的 Redis 副本,復制功能是分布式Redis 的基礎,
高可用和分布式
Redis Sentinel,它能夠保證 Redis 節點的故障發現和故障自動轉移,Redis 從 3.0 版本正式提供了分布式實作 Redis Cluster,它是 Redis 真正的分布式實作,提供了高可用、讀寫和容量的擴展性,
2. 下載安裝
目前演示的安裝操作是基于 Centos7 下講解,
官方下載地址:https://redis.io/download
# 先新建一個目錄
mkdir /usr/local/redis
cd /usr/local/redis
# 下載
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
# 解壓
tar -xzvf redis-6.2.6.tar.gz
# 編譯
cd redis-6.2.6
make
2.1 啟動
Redis 有三種方法啟動 Redis:默認配置、帶引數啟動、組態檔啟動,
1?? 默認配置
進入安裝好的 Redis 的 src目錄下執行以下命令:
./redis-server

可以看到直接使用 redis-server 啟動 Redis 后,會列印出一些日志,通過日志 可以看到一些資訊:
當前的 Redis 版本的是 64 位的 6.2.6,默認埠是 6379,Redis 建議使用組態檔來啟動,所以這種方式是不會在生產環境中使用的,
2?? 引數啟動
redis-server 加上要修改配置名和值(可以是多對),沒有設定的配置將使用默認配置,例如:如果要用 6380 作為埠啟動 Redis,那么可以執行:
./redis-server --port 6380

不過這種方式一般也用得比較少,
3?? 組態檔啟動
將配置寫到指定檔案里,并啟動,主要修改的是安裝目錄下的 redis.conf檔案,
./redis-server ../redis.conf

2.2 操作
Redis 服務啟動完成后,就可以使用 redis-cli 連接和操作 Redis 服務,

2.3 停止
Redis 提供了 shutdown 命令來停止 Redis 服務,例如我們目前已經啟動的 Redis 服務,可以執行:
./redis-cli -p 6379 shutdown
Redis 服務端將會顯示:
2853:M 15 Dec 2021 20:41:26.593 # User requested shutdown...
2853:M 15 Dec 2021 20:41:26.593 * Saving the final RDB snapshot before exiting.
2853:M 15 Dec 2021 20:41:26.594 * DB saved on disk
2853:M 15 Dec 2021 20:41:26.594 * Removing the pid file.
2853:M 15 Dec 2021 20:41:26.594 # Redis is now ready to exit, bye bye...
除了可以通過 shutdown 命令關閉 Redis 服務以外,還可以通過 kill 行程號的方式關閉掉 Redis,但是強烈不建議使用 kill -9 強制殺死 Redis 服務,不但不會做持久化操作,還會造成緩沖區等資源不能被優雅關閉,極端情況會造成 AOF 和復制丟失資料的情況,
shutdown 還有一個引數,代表是否在關閉 Redis 前,生成持久化檔案:
./redis-cli -p 6379 shutdown nosave/save
默認是 save,生成持久化檔案,如果是 nosave 則不生成持久化檔案,
3. 全域命令
在了解 Redis 的資料結構之前,先了解 Redis 的一些全域命令,
| 命令 | 說明 |
|---|---|
| keys * | 查看所有鍵,同時也支持通配符,如 keys n* |
| dbsize | 回傳當前資料庫中鍵的總數 |
| exists | 檢查鍵是否存在,存在回傳 1,不存在回傳 0,如 exists name |
| del | 洗掉鍵,無論值是什么資料結構型別,del 命令都可以將其洗掉,回傳洗掉鍵個數,洗掉不存在鍵回傳 0,同時 del 命令可以支持洗掉多個鍵,如 del name age |
| expire | Redis 支持對鍵添加過期時間,當超過過期時間后,會自動洗掉鍵,時間單位秒,如 expire name 10 |
| ttl | ttl 命令會回傳鍵的剩余過期時間,若回傳 -1 則表示鍵沒設定過期時間,-2 鍵不存在 |
| type | 回傳鍵的資料結構型別 |
| randomkey | 隨機回傳一個鍵 |
| rename | 鍵重命名,為了防止被強行 rename,Redis 提供了 renamenx 命令,確保只有 newKey 不存在時候才被覆寫,由于重命名鍵期間會執行 del 命令洗掉舊的鍵,如果鍵對應的值比較大,會存在阻塞 Redis 的可能性 |
注:
- dbsize 命令在計算鍵總數時不會遍歷所有鍵,而是直接獲取 Redis 內置的鍵總數變數,所以 dbsize 命令的時間復雜度是 O(1),而 keys 命令會遍歷所有鍵,所以它的時間復雜度是 o(n),當 Redis 保存了大量鍵時線上環境禁止使用 keys 命令;
- 除了 expire、ttl 命令以外,Redis 還提供了 expireat、pexpire,pexpireat、pttl、persist 等一系列命令,可自行查驗,
4. 基本資料結構
Redis 提供了一些資料結構供我們往 Redis 中存取資料,最常用的的有 5 種,字串(String)、哈希(Hash)、串列(list)、集合(set)、有序集合(ZSET),
4.1 String
字串型別是 Redis 最基礎的資料結構,首先鍵都是字串型別,而且其他幾種資料結構都是在字串型別基礎上構建的,所以字串型別能為其他四種資料結構的學習奠定基礎,字串型別的值實際可以是字串(簡單的字串、復 雜的字串(例如 JSON、XML))、數字(整數、浮點數),甚至是二進制(圖片、音頻、視頻),但是值最大不能超過 512 MB,
1?? 常用命令
設定值 set
set key value [ex seconds] [px milliseconds] [nxlxx]
ex seconds:為鍵設定秒級過期時間,px milliseconds:為鍵設定毫秒級過期時間,nx:鍵必須不存在,才可以設定成功,用于添加,xx:與 nx 相反,鍵必須存在,才可以設定成功,用于更新,
其中,ex 引數和 expire 命令基本一樣,還有一個需要特別注意的地方是如果一個字串已經設定了過期時間,然后你呼叫了 set 方法修改了它,它的過期時間會消失,
除了 set 選項,Redis 還提供了 setex 和 setnx 兩個命令:
setex key seconds valuesetnx key value
setex 和 setnx 的作用和 ex 和 nx 選項是一樣的,也就是,setex 為鍵設定秒級過期時間,setnx 設定時鍵必須不存在,才可以設定成功,
有什么應用場景嗎?
以 setnx 命令為例子,由于 Redis 的單執行緒命令處理機制,如果有多個客戶端同時執行 setnx key value,根據 setnx 的特性只有一個客戶端能設定成功,setnx 可以作為分布式鎖的一種實作方案,
獲取值 get
get key
如果要獲取的鍵不存在,則回傳 nil,
另外,除了單個設定和獲取鍵值,Redis 還支持批量操作,
批量設定值 mset
mset name ayue age 20 sex 男
批量獲取值 mget
mget name age sex

如果有些鍵不存在,那么它的值為 nil,結果是按照傳入鍵的順序回傳,
批量操作命令可以有效提高效率,假如沒有 mget 這樣的命令,要執行 n 次 get 命令具體耗時如下:
n 次 get 時間 = n 次網路時間 + n 次命令時間
使用 mget 命令后,要執行 n 次 get 命令操作具體耗時如下:
n 次 get 時間 = 1 次網路時間 + n 次命令時間
Redis 可以支撐每秒數萬的讀寫操作,但是這指的是 Redis 服務端的處理能力,對于客戶端來說,一次命令除了命令時間還是有網路時間,假設網路時間為 1 毫秒,命令時間為 0.1 毫秒(按照每秒處理 1 萬條命令算),那么執行 1000 次 get 命令需要 1.1 秒(1000*1+1000*0.1=1100ms),1 次 mget 命令的需要 0.101 秒 (1*1+1000*0.1=101ms),
數字運算 incr
incr 命令用于對值做自增操作,回傳結果分為三種情況:
- 值不是整數,回傳錯誤;
- 值是整數,回傳自增后的結果;
- 鍵不存在,按照值為 0 自增,回傳結果為 1,
incr key

除了 incr 命令,Redis 提供了 decr(自減)、 incrby(自增指定數字)、decrby(自減指定數字)、incrbyfloat(自增浮點數),
追加指令 append
append 可以向字串尾部追加值,
append key value

strlen
回傳字串長度,
strlen key
截取字串 getrange
getrange 截取字串中的一部分,形成一個子串,需要指明開始和結束的偏移量,截取的范圍是個閉區間,

| 命令 | 說明 | 時間復雜度 |
|---|---|---|
| get key | 獲取值 | O(1) |
| del key [key ...] | 洗掉key | O(N)(N是鍵的個數) |
| mset key [key value ...] | 批量設定值 | O(N)(N是鍵的個數) |
| mget key [key ...] | 批量獲取值 | O(N)(N是鍵的個數) |
| incr key | 將 key 中儲存的數字值增一 | O(1) |
| decr key | 將 key 中儲存的數字值減一 | O(1) |
| incrby key increment | 將 key 所儲存的值加上給定的增量值(increment) | O(1) |
| decrby key increment | key 所儲存的值減去給定的減量值(decrement) | O(1) |
| incrbyfloat key increment | 將 key 所儲存的值加上給定的浮點增量值(increment) | O(1) |
| append key value | 如果 key 已經存在并且是一個字串, APPEND 命令將指定的 value 追加到該 key 原來值(value)的末尾 | O(1) |
| strlen key | 回傳 key 所儲存的字串值的長度, | O(1) |
| setrange key offset value | 用 value 引數覆寫給定 key 所儲存的字串值,從偏移量 offset 開始 | O(1) |
| getrange key start end | 回傳 key 中字串值的子字符 | O(N)(N是字串的長度) |
2?? 命令的時間復雜度
字串這些命令中,除了 del 、mset、 mget 支持多個鍵的批量操作,時間復雜度和鍵的個數相關,為 O(n),getrange 和字串長度相關,也是 O(n),其余的命令基本上都是 O(1)的時間復雜度,在速度上是非常快的,
3?? 使用場景
字串型別的使用場景很廣泛,如下:
1、快取功能
Redis 作為快取層,MySQL 作為存盤層,絕大部分請求的資料都是從 Redis 中獲取,由于 Redis 具有支撐高并發的特性,所以快取通常能起到加速讀寫和降低 后端壓力的作用,
2、計數
使用 Redis 作為計數的基礎工具,它可以實作快速計數、查詢快取的功能,同時資料可以異步落地到其他資料源,
3、共享 Session
一個分布式 Web 服務將用戶的 Session 資訊(例如用戶登錄資訊)保存在各 自服務器中,這樣會造成一個問題,出于負載均衡的考慮,分布式服務會將用戶的訪問均衡到不同服務器上,用戶重繪一次訪問可能會發現需要重新登錄,這個問題是用戶無法容忍的,
為了解決這個問題, 可以使用 Redis 將用戶的 Session 進行集中管理,在這種模式下只要保證 Redis 是高可用和擴展性的,每次用戶更新或者查詢登錄資訊都直接從 Redis 中集中獲取,
4、限時
很多應用出于安全的考慮,會在每次進行登錄時,讓用戶輸入手機驗證碼,從而確定是否是用戶本人,但是為了短信介面不被頻繁訪問,會限制用戶每分鐘獲取驗證碼的頻率,例如一分鐘不能超過 5 次,一些網站限制一個 IP 地址不能在一秒鐘之內訪問超過 n 次,或者同一 IP 在短時間內多次瀏覽謀篇文章瀏覽次數不會一直增加,點贊次數在短時間內不能重復點贊,
4.2 Hash
Redis hash 是一個 string 型別的 field(欄位) 和 value(值) 的映射表,hash 特別適合用于存盤物件,
Redis 中每個 hash 可以存盤 232 - 1 鍵值對(40多億),
1?? 常用命令
基本上,哈希的操作命令和字串的操作命令很類似,很多命令在字串型別的命令前面加上了 h 字母,代表是操作哈希型別,同時還要指明要操作的 field 的值,
hset
hset key field value
如果設定成功會回傳 1,反之會回傳 0,此外 Redis 提供了 hsetnx 命令,它們的關系就像 set 和 setnx 命令一樣,只不過作用域由鍵變為 field,
127.0.0.1:6379> hset hash:test name ayue
(integer) 1
127.0.0.1:6379>
hget
hget key field
獲取值
127.0.0.1:6379> hget hash:test name
"ayue"
127.0.0.1:6379>
其他命令:
| 命令 | 說明 | 時間復雜度 |
|---|---|---|
| HDEL key field [field] | 洗掉一個或多個Hash的field | O(N) N是被洗掉的欄位數量 |
| HEXISTS key field | 判斷field是否存在于Hash中 | O(1) |
| HGET key field | 獲取Hash中field的值 | O(1) |
| HGETALL key | 從Hash中讀取全部的域和值 | O(N) N是Hash的長度 |
| HINCRBY key field increment | 將Hash中指定域的值增加給定的數字 | O(1) |
| HINCRBYFLOAT key field increment | 將Hash中指定域的值增加給定的浮點數 | O(1) |
| HKEYS key | 獲取Hash的所有欄位 | O(N) N是Hash的長度 |
| HLEN key | 獲取Hash里所有欄位的數量 | O(1) |
| HMGET key field field | 獲取Hash里面指定欄位的值 | O(N) N是請求的欄位數 |
| HMSET key field value [field value ...] | 批量設定Hash欄位值 | O(N) N是設定的欄位數 |
| HSET key field value | 設定Hash里面一個欄位的值 | O(1) |
| HSETNX key field value | 設定Hash的一個欄位,只有當這個欄位不存在時有效 | O(1) |
| HSTRLEN key field | 獲取Hash里面指定field的長度 | O(1) |
| HVALS key | 獲得 Hash 的所有值 | O(N) N是Hash的長度 |
| HSCAN key cursor [MATCH pattern] [COUNT count] | 迭代 Hash 里面的元素 |
2?? 命令的時間復雜度
哈希型別的操作命令中,hdel,hmget,hmset 的時間復雜度和命令所帶的 field 的個數相關 O(k),hkeys,hgetall,hvals 和存盤的 field 的總數相關,O(N),其余的命令時間復雜度都是 O(1),
3?? 使用場景
1、存盤物件
Redis哈希物件常常用來快取一些物件資訊,如用戶資訊、商品資訊、配置資訊等,
我們以用戶資訊為例,它在關系型資料庫中的結構是這樣的:
| id | name | age |
|---|---|---|
| 1 | Tom | 15 |
| 2 | Jerry | 13 |
而使用Redis Hash存盤其結構如下圖:

hmset user:1 name Tom age 15
hmset user:2 name Jerry age 13
相比較于使用Redis字串存盤,其有以下幾個優缺點:
-
原生字串每個屬性一個鍵,
set user:1:name Tom set user:1:age 15優點:簡單直觀,每個屬性都支持更新操作,
缺點:占用過多的鍵,記憶體占用量較大,同時用戶資訊內聚性比較差,所以此種方案一般不會在生產環境使用, -
序列化字串后,將用戶資訊序列化后用一個鍵保存
set user:1 serialize(userInfo)優點:簡化編程,如果合理的使用序列化可以提高記憶體的使用效率,
缺點:序列化和反序列化有一定的開銷,同時每次更新屬性都需要把全部資料取出進行反序列化,更新后再序列化到Redis中, -
序列化字串后,將用戶資訊序列化后用一個鍵保存
hmset user:1 name Tom age 15優點:簡單直觀,如果使用合理可以減少記憶體空間的使用,
缺點:要控制哈希在ziplist和hashtable兩種內部編碼的轉換,hashtable會消耗更多記憶體,
2、購物車
購物車主要功能是臨時存放欲購買的商品,然后在結算或下訂單時,把購物里面的資料全部移除,其資料結構主要包含的欄位有:用戶ID、商品ID、商品數量等等,通常我們需要實作以下幾個功能:
- 全選功能,獲取所有該用戶的所有購物車商品;
- 商品數量,購物車圖示上要顯示購物車里商品的總數;
- 洗掉,要能移除購物車里某個商品;
- 增加或減少某個商品的數量,

在之前很多電商網站通過 cookie 實作購物車功能,也就是將整個購物車都存盤到 cookie里面,
- 優點:無須對資料庫進行寫入就可以實作購物車功能,這種方式大大提高了購物車的性能,
- 缺點:程式需要重新決議和驗證( validate) cookie,確保 cookie 的格式正確,并且包含的商品都是真正可購買的商品,另外,因為瀏覽器每次發送請求都會連 cookie 一起發送,所以如果購物車 cookie 的體積比較大,那么請求發送和處理的速度可能會有所降低,
而通過 Redis 定義購物車非常簡單:當前登錄用戶 ID 號做為key,商品 ID 號為 field,加入購物車數量為 value,如下:
hmset cart:001 prod:01 1 prod:02 1
| | |
| | |
| | |
key field value
而對于上述功能,可以通過 Hash 的相關命令來操作,
4.3 List
串列( list)型別是用來存盤多個有序的字串,a、b、c、d、e 五個元素從左到右組成了一個有序的串列,串列中的每個字串稱為元素(element),一個串列最多可以存盤 2-1 個元素,
在 Redis 中,可以對串列兩端插入( push)和彈出(pop),還可以獲取指定范圍的元素串列、獲取指定索引下標的元素等,
串列是一種比較靈活的資料結構,它可以充當堆疊和佇列的角色,在實際開發上有很多應用場景,

串列型別有兩個特點:
- 串列中的元素是有序的,這就意味著可以通過索引下標獲取某個元素或者某個范圍內的元素串列,
- 串列中的元素可以是重復的,
1?? 常用命令
Redis串列物件常用命令如下表(點擊命令可查看命令詳細說明):
| 命令 | 說明 | 時間復雜度 |
|---|---|---|
| BLPOP key [key ...] timeout | 洗掉,并獲得該串列中的第一元素,或阻塞,直到有一個可用 | O(1) |
| BRPOP key [key ...] timeout | 洗掉,并獲得該串列中的最后一個元素,或阻塞,直到有一個可用 | O(1) |
| BRPOPLPUSH source destination timeout | 彈出一個串列的值,將它推到另一個串列,并回傳它;或阻塞,直到有一個可用 | O(1) |
| LINDEX key index | 獲取一個元素,通過其索引串列 | O(N) |
| LINSERT key BEFORE | AFTER pivot value在串列中的另一個元素之前或之后插入一個元素 | O(N) |
| LLEN key | 獲得佇列(List)的長度 | O(1) |
| LPOP key | 從佇列的左邊出隊一個元素 | O(1) |
| LPUSH key value [value ...] | 從佇列的左邊入隊一個或多個元素 | O(1) |
| LPUSHX key value | 當佇列存在時,從隊到左邊入隊一個元素 | O(1) |
| LRANGE key start stop | 從串列中獲取指定回傳的元素 | O(S+N) |
| LREM key count value | 從串列中洗掉元素 | O(N) |
| LSET key index value | 設定佇列里面一個元素的值 | O(N) |
| LTRIM key start stop | 修剪到指定范圍內的清單 | O(N) |
| RPOP key | 從佇列的右邊出隊一個元 | O(1) |
| RPOPLPUSH source destination | 洗掉串列中的最后一個元素,將其追加到另一個串列 | O(1) |
| RPUSH key value [value ...] | 從佇列的右邊入隊一個元素 | O(1) |
| RPUSHX key value | 從佇列的右邊入隊一個元素,僅佇列存在時有效 | O(1) |
2?? 命令的時間復雜度
串列型別的操作命令中,llen,lpop,rpop,blpop 和 brpop 命令時間復雜度都是 O(1),其余的命令的時間復雜度都是 O(n),只不過 n 的值根據命令不同而不同,比如 lset,lindex 時間復雜度和命令后的索引值大小相關,rpush 和 lpush 和插入元素的個數相關等等,
3?? 使用場景
1、訊息佇列
但使用 Redis 做訊息佇列存在很多問題,如訊息確認 ACK,訊息丟失等,所以一般來說還是用比較專業的 MQ 中間件,
2、文章串列
如下面這樣的文章串列,當用戶和文章都越來越多時,為了加快程式的回應速度,我們可以把用戶自己的文章存入到 List 中,因為 List 是有序的結構,所以這樣又可以完美的實作分頁功能,從而加速了程式的回應速度,

上圖可表示為:
# 深圳衛健委發布一條訊息,訊息ID為 99
lpush mes:001 99
# 武漢本地寶發布一條訊息,訊息ID為 100
lpush mes:001 100
# 獲取訊息串列‘
lrange mes:001 0 5
4.4 Set
集合( set)型別也是用來保存多個的字串元素,但和串列型別不一樣的是,集合中不允許有重復元素,并且集合中的元素是無序的,不能通過索引下標獲取元素,
一個集合最多可以存盤 232 - 1 個元素,Redis 除了支持集合內的增刪改查,同時還支持多個集合取交集、并集、差集,合理地使用好集合型別,能在實際開發中解決很多實際問題,
1?? 常用命令
Redis Set 物件常用命令如下表(點擊命令可查看命令詳細說明):
| 命令 | 說明 | 時間復雜度 |
|---|---|---|
| SADD key member [member ...] | 添加一個或者多個元素到集合(set)里 | O(N) |
| SCARD key | 獲取集合里面的元素數量 | O(1) |
| SDIFF key [key ...] | 獲得佇列不存在的元素 | O(N) |
| SDIFFSTORE destination key [key ...] | 獲得佇列不存在的元素,并存盤在一個關鍵的結果集 | O(N) |
| SINTER key [key ...] | 獲得兩個集合的交集 | O(N*M) |
| SINTERSTORE destination key [key ...] | 獲得兩個集合的交集,并存盤在一個關鍵的結果集 | O(N*M) |
| SISMEMBER key member | 確定一個給定的值是一個集合的成員 | O(1) |
| SMEMBERS key | 獲取集合里面的所有元素 | O(N) |
| SMOVE source destination member | 移動集合里面的一個元素到另一個集合 | O(1) |
| SPOP key [count] | 洗掉并獲取一個集合里面的元素 | O(1) |
| SRANDMEMBER key [count] | 從集合里面隨機獲取一個元素 | |
| SREM key member [member ...] | 從集合里洗掉一個或多個元素 | O(N) |
| SUNION key [key ...] | 添加多個set元素 | O(N) |
| SUNIONSTORE destination key [key ...] | 合并set元素,并將結果存入新的set里面 | O(N) |
| [SSCAN key cursor MATCH pattern] [COUNT count] | 迭代set里面的元素 | O(1) |
2?? 命令的時間復雜度
scard,sismember 時間復雜度為 O(1),其余的命令時間復雜度為 O(n),其中 sadd,srem 和命令后所帶的元素個數相關,spop,srandmember 和命令后所帶 count 值相關,交集運算 O(m*k),k 是多個集合中元素最少的個數,m 是鍵個數,并集、差集和所有集合的元素個數和相關,
3?? 使用場景
1、抽獎活動
常見的抽獎活動,比如基于 Redis 實作抽獎功能,
SPOP(隨機移除并回傳集合中一個或多個元素) 和 SRANDMEMBER(隨機回傳集合中一個或多個元素) 命令可以幫助我們實作一個抽獎系統,如果允許重復中獎,可以使用SRANDMEMBER 命令,
活動 ID 為 001,則
# Tom userID:01 參加活動
sadd action:001 01
# Jerry userID:02 參加活動
sadd action:001 02
# 開始抽獎1名中獎者
srandmember action:001 1 或 spop action:001 1
# 查看有多少用戶參加了本次抽獎
smembers action:001
2、點贊功能
比如設計一個微信點贊功能,
# 張三用戶ID 為userId:01
# 張三對訊息 ID008點贊啦
sadd zan:008 userId:01
# 張三取消了對訊息008的點贊
srem zan:008 userId:01
# 檢查用戶是否點過贊
sismember zan:008 userId:01
# 獲取訊息ID008所有的點贊用戶串列
smembers zan:008
# 訊息ID008的點贊數計算
scard zan:008
3、關系設計
如我們要設計一個微博的共同關注,或者可能認識的人,設計如下:
① A 關注的人
sadd A:cares B C D E
② B 關注的人
sadd B:cares A C D F
③ C 關注的人
sadd C:cares A F
按照以上條件:
④ A 和 B 共同關注的人
# D,C
sinter A:cares B:cares
⑤ 我關注的人也關注他
# A 關注的 B 也關注了 F,回傳 1 否則回傳 0
sismember B:cares F
⑥ 可能認識的人
# C 可能認識的人 C,D
sdiff B:cares C:cares
4、集合操作
setA={A,B,C} setB={B, C}
① 集合與集合之間的交集
sinter setA setB-->得到集合{B,C}
② 集合與集合之間的并集
sunion setA setB -->得到集合{A,B,C}
③ 集合與集合之間的差集
sdiff setA setB-->得到集合{A}
127.0.0.1:6379> SADD setA A B C
(integer) 3
127.0.0.1:6379> SADD setB B C
(integer) 2
127.0.0.1:6379> SINTER setA setB
1) "C"
2) "B"
127.0.0.1:6379> SUNION setA setB
1) "A"
2) "B"
3) "C"
127.0.0.1:6379> SDIFF setA setB
1) "A"
127.0.0.1:6379>
4.5 ZSet
ZSet,有序集合,相對于哈希、串列、集合來說會有一點點陌生,但既然叫有序集合,那么它和集合必然有著聯系,它保留了集合不能有重復成員的特性,但不同的是,有序集合中的元素可以排序,但是它和串列使用索引下標作為排序依據不同的是,它給每個元素設定一個分數( score)作為排序的依據,
有序集合中的元素不能重復,但是 score 可以重復,就和一個班里的同學學號不能重復,但是考試成績可以相同,
有序集合提供了獲取指定分數和元素范圍查詢、計算成員排名等功能,合理的利用有序集合,能幫助我們在實際開發中解決很多問題,
1?? 常用命令
zadd
向有序集合 top:20211221 添加話題和點擊量,
zadd hot:20211220 10 薇婭逃稅
zadd 命令還有四個選項 nx、xx、ch、incr 四個選項:
- nx,member 必須不存在,才可以設定成功,用于添加;
- xx,member 必須存在,才可以設定成功,用于更新;
- ch,回傳此次操作后,有序集合元素和分數發生變化的個數;
- incr,對 score 做增加,相當于 zincrby ,
Redis串列物件常用命令如下表:
| 命令 | 說明 | 時間復雜度 |
|---|---|---|
| BZPOPMAX key [key ...] timeout | 從一個或多個排序集中洗掉并回傳得分最高的成員,或阻塞,直到其中一個可用為止 | O(log(N)) |
| BZPOPMIN key [key ...] timeout | 從一個或多個排序集中洗掉并回傳得分最低的成員,或阻塞,直到其中一個可用為止 | O(log(N)) |
| [ZADD key NXXX] [CH] [INCR] score member [score member ...] | 添加到有序set的一個或多個成員,或更新的分數,如果它已經存在 | O(log(N)) |
| ZCARD key | 獲取一個排序的集合中的成員數量 | O(1) |
| ZCOUNT key min max | 回傳分數范圍內的成員數量 | O(log(N)) |
| ZINCRBY key increment member | 增量的一名成員在排序設定的評分 | O(log(N)) |
| ZINTERSTORE | 相交多個排序集,導致排序的設定存盤在一個新的關鍵 | O(NK)+O(Mlog(M)) |
| ZLEXCOUNT key min max | 回傳成員之間的成員數量 | O(log(N)) |
| ZPOPMAX key [count] | 洗掉并回傳排序集中得分最高的成員 | O(log(N)*M) |
| ZPOPMIN key [count] | 洗掉并回傳排序集中得分最低的成員 | O(log(N)*M) |
| ZRANGE key start stop [WITHSCORES] | 根據指定的index回傳,回傳sorted set的成員串列 | O(log(N)+M) |
| ZRANGEBYLEX key min max [LIMIT offset count] | 回傳指定成員區間內的成員,按字典正序排列, 分數必須相同, | O(log(N)+M) |
| ZREVRANGEBYLEX key max min [LIMIT offset count] | 回傳指定成員區間內的成員,按字典倒序排列,分數必須相同 | O(log(N)+M) |
| ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | 回傳有序集合中指定分數區間內的成員,分數由低到高排序, | O(log(N)+M) |
| ZRANK key member | 確定在排序集合成員的索引 | O(log(N)) |
| ZREM key member [member ...] | 從排序的集合中洗掉一個或多個成員 | O(M*log(N)) |
| ZREMRANGEBYLEX key min max | 洗掉名稱按字典由低到高排序成員之間所有成員, | O(log(N)+M) |
| ZREMRANGEBYRANK key start stop | 在排序設定的所有成員在給定的索引中洗掉 | O(log(N)+M) |
| ZREMRANGEBYSCORE key min max | 洗掉一個排序的設定在給定的分數所有成員 | O(log(N)+M) |
| ZREVRANGE key start stop [WITHSCORES] | 在排序的設定回傳的成員范圍,通過索引,下令從分數高到低 | O(log(N)+M) |
| ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] | 回傳有序集合中指定分數區間內的成員,分數由高到低排序, | O(log(N)+M) |
| ZREVRANK key member | 確定指數在排序集的成員,下令從分數高到低 | O(log(N)) |
| ZSCORE key member | 獲取成員在排序設定相關的比分 | O(1) |
| ZUNIONSTORE | 添加多個排序集和導致排序的設定存盤在一個新的鍵 | O(N)+O(M log(M)) |
| ZSCAN key cursor [MATCH pattern] [COUNT count] | 迭代sorted sets里面的元素 | O(1) |
2?? 命令的時間復雜度
參考上表,
3?? 使用場景
有序集合比較典型的使用場景就是排行榜系統,例如視頻網站需要對用戶上傳的視頻做排行榜,榜單的維度可能是多個方面的:按照時間、按照播放數量、按斬訓得的贊數,

如上熱搜榜,以日期為 key :
① 點擊熱搜,每次加 1
zincrby hot:20211220 1 薇婭逃稅
② 右側排行實作,展示今日前 50 排名
# zrange 是從低到高回傳,zrevrange 反之
zrevrange hot:20211221 0 49 withscores
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/394922.html
標籤:Java
上一篇:火的一塌糊涂的Spring Cloud到底是什么?這篇文章帶你全面了解微服務
下一篇:zabbix 線路質量監控自定義python模塊(socket+deque版),集成ICMP/TCP/UDP探測,批量監控線路質量并自定義閾值聯動mtr保存線路故障日志
