文章目錄
- Redis最新入門教程
- 1.安裝Redis
- 2.連接Redis
- 3.Redis環境變量配置
- 4.入門Redis
- 4.1 Redis的數據結構
- 4.2 Redis的Key
- 4.3 Redis-String
- 4.4 Redis-Hash
- 4.5 Redis-List
- 4.6 Redis-Set
- 4.7 Redis-Zset
- 5.在Java中使用Redis
- 6.緩存雪崩、擊穿、穿透
- 6.1 緩存雪崩
- 6.2 緩沖擊穿
- 6.3 緩沖穿透
- 6.4 業務可靠性處理
- 參考
Redis最新入門教程
Redis 是互聯網技術領域中使用最廣泛的存儲中間件,它是 Remote Dictionary Service 三個單詞中加粗字母的組合。它是一個存儲在磁盤上的內存數據庫。數據模型是鍵-值對,但支持許多不同類型的值:Strings, Lists, Sets, Sorted Sets, Hashes
。
1.安裝Redis
Redis 官方不建議在 windows 下使用 Redis,所以官網沒有 Windows 版本可以下載。但是官方給出了一個在 Windows 下使用Redis的方法:Install Redis on Windows,具體操作就是安裝 WSL,然后在電腦上運行 Ubuntu,大家也可以嘗試。
對于我們本地開發與學習,下載非官方的 Windows 版本就可以。這里推薦兩個 Windows 版本的 Redis 倉庫:
- 微軟的開源 Windows版本 --> 這個項目已經不再被維護了,最高版本為 3.2.100。
- redis-windows 項目 --> 借助 GitHub Actions 強大的自動化構建能力,實時編譯最新版本的 Redis for Windows 系統。版本和官方保持一致,推薦👍
note:建議使用 Windows 版本進行本地開發,并按照 Redis 官方指導將其部署在 Linux 上用于生產環境。
安裝流程:
-
下載 Redis Latest for Windows。
-
解壓,直接運行項目中的
start.bat
腳本,一鍵啟動。或者使用命令行啟動redis-server.exe redis.conf
。note:使用 Redis 時,這個窗口不可以關閉。若想要停止 Redis 服務,直接關閉窗口。
2.連接Redis
Redis 本身就自帶了一個命令行客戶端,可以直接通過 redis-cli
命令來連接 Redis 服務。如下所示,表明連接成功:
這里推薦兩款好用的 Redis 圖形化客戶端,大家可以根據自己喜好下載:
- AnotherRedisDesktopManager,github 已經有 32k+ 的 star 了。
- Redis Insight,官方 Redis 數據庫工具。
由于我個人喜歡使用官方版本,所以接下來介紹一下 Redis Insight 的安裝:進入官網 Redis Insight 下載安裝包,然后一直下一步即可安裝成功。第一次打開勾選上 I have read and understood the Terms 點擊 Submit 就好,其他選項(主要是隱私設置以及通知設置)不用勾選。這樣就可以開始使用 Redis Insight了。
3.Redis環境變量配置
每次連接 Redis 都必須到解壓后的目錄,才可以輸入啟動命令。所以通過配置環境變量,解決這一問題。
-
復制 Redis 的地址。
Example: D:\Redis\Redis-8.0.0-Windows-x64-cygwin
-
「環境變量」->「系統變量」->「path」->「編輯」->「新建」,粘貼 Redis 路徑。
這樣在任何位置,打開 cmd 就可以輸入 Redis 的命令了。
-
啟動 Redis:
redis-server
-
連接 Redis:
redis-cli
4.入門Redis
4.1 Redis的數據結構
Redis 有 5 種基礎數據結構,String、Hash、List、Set、SortedSet
。除此之外,還有 HyperLogLog、Geo、Pub/Sub
等高級數據結構。
- string(字符串): 基本的數據存儲單元,可以存儲字符串、整數或者浮點數。
- hash(哈希):一個鍵值對集合,可以存儲多個字段。
- list(列表):一個簡單的列表,可以存儲一系列的字符串元素。
- set(集合):一個無序集合,可以存儲不重復的字符串元素。
- zset(sorted set:有序集合): 類似于集合,但是每個元素都有一個分數(score)與之關聯。
- 位圖(Bitmaps):位數組,可以對字符串進行位操作。常用于實現布隆過濾器等位操作。
- 超日志(HyperLogLogs):用于基數統計,可以估算集合中的唯一元素數量。
- 地理空間(Geospatial):用于存儲地理位置信息,支持地理空間索引和半徑查詢。
- 發布/訂閱(Pub/Sub):一種消息通信模式,允許客戶端訂閱消息通道,并接收發布到該通道的消息。
- 流(Streams):用于消息隊列和日志存儲,支持消息的持久化和時間排序。
- 模塊(Modules):Redis 支持動態加載模塊,可以擴展 Redis 的功能。
4.2 Redis的Key
Redis 鍵命令用于管理 redis 的鍵。Redis 鍵命令的基本語法如下:
COMMAND KEY_NAME
127.0.0.1:6379> set name redis
OK
127.0.0.1:6379> del name
(integer) 1
- del 命令用來刪除一個鍵值對,
(integer) 1
表示執行成功,(integer) 0
表示執行失敗。- exists 命令用來測試一個鍵值對是否存在,
(integer) 1
表示存在,(integer) 0
表示不存在。
4.3 Redis-String
String 類型是 Redis 最基本的數據類型,string 類型的值最大能存儲 512MB。
常用命令:
SET key value
:設置鍵的值。GET key
:獲取鍵的值。INCR key
:將鍵的值加 1。DECR key
:將鍵的值減 1。APPEND key value
:將值追加到鍵的值之后。
127.0.0.1:6379> set name1 xiaoming
OK
127.0.0.1:6379> get name1
"xiaoming"
4.4 Redis-Hash
Hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用于存儲對象。每個 hash 最多可以存儲 2 32 ? 1 2^{32}-1 232?1 個鍵值對。
常用命令:
HSET key field value
:設置哈希表中字段的值。HGET key field
:獲取哈希表中字段的值。HGETALL key
:獲取哈希表中所有字段和值。HDEL key field
:刪除哈希表中的一個或多個字段。
127.0.0.1:6379> hset student id 1 name "zhangsan" gender "男"
(integer) 3
127.0.0.1:6379> hgetall student
1) "id"
2) "1"
3) "name"
4) "zhangsan"
5) "gender"
6) "\xe7\x94\xb7"
127.0.0.1:6379> hget student name
"zhangsan"
127.0.0.1:6379> hget student id
"1"
4.5 Redis-List
List 是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。列表最多可以存儲 2 32 ? 1 2^{32}-1 232?1 個元素。
常用命令:
LPUSH key value
:將值插入到列表頭部。RPUSH key value
:將值插入到列表尾部。LPOP key
:移出并獲取列表的第一個元素。RPOP key
:移出并獲取列表的最后一個元素。LRANGE key start stop
:獲取列表在指定范圍內的元素。
127.0.0.1:6379> lpush order first second
(integer) 2
127.0.0.1:6379> lrange order 0 1
1) "second"
2) "first"
127.0.0.1:6379> lpush order third
(integer) 3
127.0.0.1:6379> lrange order 0 3
1) "third"
2) "second"
3) "first"
127.0.0.1:6379> lrange order 0 2
1) "third"
2) "second"
3) "first"
127.0.0.1:6379> lrange order 0 1
1) "third"
2) "second"
4.6 Redis-Set
Set 是 string 類型的無序集合。集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是 O(1)。集合中最大的成員數為 2 32 ? 1 2^{32}-1 232?1。
常用命令:
SADD key value
:向集合添加一個或多個成員。SREM key value
:移除集合中的一個或多個成員。SMEMBERS key
:返回集合中的所有成員。SISMEMBER key value
:判斷值是否是集合的成員。
127.0.0.1:6379> sadd color red yellow blue
(integer) 3
127.0.0.1:6379> smembers color
1) "red"
2) "yellow"
3) "blue"
127.0.0.1:6379> srem color red
(integer) 1
127.0.0.1:6379> smembers color
1) "yellow"
2) "blue
4.7 Redis-Zset
zset 和 set 一樣也是 string 類型元素的集合,且不允許重復的成員。不同的是每個元素都會關聯一個 double 類型的分數。redis 正是通過分數來為集合中的成員進行從小到大的排序。zset 的成員是唯一的,但分數(score)卻可以重復。
常用命令:
ZADD key score value
:向有序集合添加一個或多個成員,或更新已存在成員的分數。ZRANGE key start stop [WITHSCORES]
:返回指定范圍內的成員。ZREM key value
:移除有序集合中的一個或多個成員。ZSCORE key value
:返回有序集合中,成員的分數值。
127.0.0.1:6379> zadd class 100 "one" 90 "two" 100 three
(integer) 3
127.0.0.1:6379> zrange class 0 2
1) "two"
2) "one"
3) "three"
127.0.0.1:6379> zscore class two
"90"
5.在Java中使用Redis
-
第一步,在項目中添加 Jedis(Java 和 Redis 的混拼)依賴:
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>8.0.0</version> </dependency>
-
第二步,新建 UserInfo(用戶信息)類:
package org.example;public class UserInfo {private String name;private int age;public UserInfo() {}public UserInfo(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "UserInfo{" +"name='" + name + '\'' +", age=" + age +'}';} }
-
第三步,在項目中添加 Gson(用于序列化和反序列化用戶信息)依賴:
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version><scope>compile</scope> </dependency>
-
第四步,新建測試類 RedisTest:
public class RedisTest {// 定義 Redis 中存儲用戶信息的鍵private static final String REDIS_KEY = "user";public static void main(String[] args) {// 創建 Jedis 實例,連接到本地 Redis 服務器,端口為 6379Jedis jedis = new Jedis("localhost", 6379);// 創建 Gson 實例,用于 Java 對象和 JSON 字符串之間的轉換Gson gson = new Gson();// 創建 UserInfo 對象,存儲用戶信息UserInfo userInfo = new UserInfo("魚兒也有煩惱", 18);// 將 UserInfo 對象轉換為 JSON 字符串,并存儲到 Redis 中jedis.set(REDIS_KEY, gson.toJson(userInfo));// 從 Redis 中獲取 JSON 字符串,并轉換為 UserInfo 對象UserInfo getUserInfoFromRedis = gson.fromJson(jedis.get(REDIS_KEY), UserInfo.class);// 打印從 Redis 中獲取的用戶信息System.out.println("get:" + getUserInfoFromRedis);// 打印指定鍵是否存在于 Redis 中System.out.println("exists:" + jedis.exists(REDIS_KEY));// 刪除 Redis 中指定鍵對應的值,并打印刪除的鍵的數量System.out.println("del:" + jedis.del(REDIS_KEY));// 嘗試獲取已刪除鍵的值,并打印結果System.out.println("get:" + jedis.get(REDIS_KEY));} }
-
輸出結果:
get:UserInfo{name='魚兒也有煩惱', age=18} exists:true del:1 get:null
6.緩存雪崩、擊穿、穿透
6.1 緩存雪崩
概念:即緩存同一時間大面積的失效,這個時候來了一大波請求,都懟到數據庫上,最后數據庫處理不過來崩了。
業務場景舉例:APP首頁放著很多熱門數據,大型活動期間,首頁數據得按不同時間更新。就像零點要換一批新數據,舊數據剛過期,新數據還沒完全加載好。偏偏零點又有個小活動啟動,一下子來了好多人打開APP,服務器收到海量請求。可新數據沒加載完,緩存里大多找不到對應內容,這些請求全跑到數據庫那兒去了。數據庫應付不過來這么多請求,最后直接癱瘓了。
解決方案:
- 給過期時間加個隨機時間。需要注意的是,這里設置的隨機過期時間并非短短幾秒,而是可以長達數分鐘。這是因為當數據量龐大時,再結合上述場景,考慮到Redis采用單線程處理數據的特性,僅僅幾秒的緩沖時間,根本無法確保所有新數據都能加載完畢。 因此,在設置過期時間時,寧長勿短。畢竟無論時間長短,數據最終都會過期,從最終效果來看并無差別。而且,適當擴大過期時間范圍,能讓Redis的key分布得更加分散。這樣一來,Redis在批量處理過期key時,阻塞時間也會相應縮短,有效提升系統運行效率。
- 加互斥鎖,但這個方案會導致吞吐量明顯下降。(上述例子不合適用)
- 熱點數據不設置過期。不過期的話,正常業務請求自然就不會打到數據庫了。
6.2 緩沖擊穿
概念:緩存擊穿是指一個熱點 key 過期或被刪除后,導致線上原本能命中該熱點 key 的請求,瞬間大量地打到數據庫上,最終導致數據庫被擊垮。
業務場景舉例:出現情況一般是誤操作,比如設置錯了過期時間、誤刪除導致的。
解決方案:
- 仔細檢查每一處代碼細節,確保沒有潛在問題。對于熱點數據,要明確制定清晰的過期策略:究竟需不需要設置過期時間?如果需要,具體在何時讓數據過期?這些都要有明確的規劃。
- 線上誤操作問題,需加強權限管理,特別是線上權限必須審核,防止誤操作。
6.3 緩沖穿透
概念:客戶端請求緩存和數據庫中不存在的數據,導致所有的請求都打到數據庫上。如果請求很多,數據庫依舊會掛掉。
業務場景舉例:
- 數據庫主鍵 id 都是正數,然后客戶端發起了
id = -1
的查詢。 - 一個查詢接口,有一個狀態字段 status,其實 0 表示開始、1 表示結束。結果有請求一直發
status=3
的請求過來。
解決方案:
- 做好參數校驗,對于不合理的參數要及時 return 結束。
- 對于查不到數據的 key,也將其短暫緩存起來。比如 30s。這樣能避免大量相同請求瞬間打到數據庫上,減輕壓力。
- 提供一個能迅速判斷請求是否有效的攔截機制,比如布隆過濾器,Redis 本身就具有這個功能。可以利用 Redis 維護所有合法的鍵(key),當有請求到來時,先通過布隆過濾器檢查請求參數中的鍵是否合法。若不合法,就直接返回響應結果;若合法,再從緩存或者數據庫里獲取所需數據。
6.4 業務可靠性處理
-
提高 Redis 可用性。
Redis 要么用集群架構,要么用主從 + 哨兵。保證 Redis 的可用性。
光搞主從架構,沒加哨兵的話,出問題根本不會自動切換。要是趕上業務高峰期或者搞活動的時候服務器掛了,等系統報警、排查問題、跟團隊溝通完,再等運維來修,黃花菜都涼了!
-
減少對緩存的依賴。
對于熱點數據,可以考慮加上本地緩存,比如:Guava、Ehcache,更簡單點,hashMap、List 等也可以。減少 Redis 壓力的同時,還能提高性能,一舉兩得。
-
業務降級。
從保護下游接口或者數據庫的方面來想,在碰到大流量的情況時,搞個限流措施挺有必要的。就算緩存突然崩了,也不至于讓下游直接全垮掉。還有,那些能降級的功能就降級。提前把降級開關和降級邏輯寫好,到了關鍵時候,全指望著它們來穩住局面呢。
🤗🤗🤗
參考
- Redis官方Commands查閱