簡介
Redis 的全稱是 Remote Dictionary Server,是一個使用 C 語言撰寫的、開源的(BSD 許可)高性能非關系型(NoSQL)的鍵值對資料庫,
Redis 的資料是存盤在記憶體中的,所以讀寫速度非常快,被廣泛應用于快取方向,當然也有持久化資料庫的用法,
優缺點
優點
- 讀寫性能優異, Redis 能讀的速度是 110000 次/s,寫的速度是 81000 次/s
- 資料型別豐富,有 String、List、Hash、Set、SortedSet 等
- 單執行緒原子性,Redis 所有的操作都是原子性的,也支持多個操作合并后的原子執行
- 豐富的特性,Redis 支持發布訂閱、通知、key 過期等功能
- 支持持久化,Redis 支持 RDB、AOF 等持久化方式
- 高可用性,Redis 支持主從復制、哨兵模式、Cluster 等高可用方式
缺點
- 資料庫容量受物理記憶體的限制,不能用作海量資料的讀寫
- Redis 難以支持在線擴容,修改組態檔之后重啟 Redis,恢復磁盤上的資料耗費時間較久
使用場景
資料快取
Redis 是高性能的記憶體資料庫,因此,快取是 Redis 最常用的場景,Redis 作為快取使用的時候,一般是采用先更新資料庫,再洗掉快取的 Cache Aside Pattern 策略,
整體的邏輯是:業務從 Redis 中讀取資料,如果 Redis 中訪問不到資料,然后讀取資料庫中的資料,將資料庫中的資料快取到 Redis 中;業務更新資料,直接修改資料庫中的資料,然后將 Redis 中的快取洗掉,
這種方案需要注意的就是:避免快取擊穿,資料的實時性相對較低,
限時業務
Redis 支持給 key 設定過期時間,客戶端無法訪問到過期的 key,利用這一特性可以運用在限時的優惠活動、手機驗證碼等業務場景,
計數器
Redis 的 INCRBY 命令可以實作原子性的遞增,可以直接作為計數器存盤和遞增,尤其是,該命令在鍵不存在時會直接初始化值再執行 INCRBY 命令,執行成功后會直接回傳計算增量之后的數值,
高并發的秒殺活動、分布式序列號的生成、限制手機發送短信次數、介面限制訪問次數等需要計數的功能,都涉及到計數器的概念,尤其是分布式系統會涉及到分布式計數器,
分布式鎖
先使用 SETNX 命令來爭搶鎖,結果回傳 1 表示設定成功,搶到之后再用 EXPIRE 命令給鎖加一個過期時間防止忘記釋放鎖,
從 Redis 的 2.6.12 版本開始,可以通過 SET 命令的復雜引數,將 SETNX 命令和 EXPIRE 命令合并成一條命令來使用:
EX second: 設定鍵的過期時間為 second 秒,使用EX選項效果等同于SETEX命令,PX millisecond: 設定鍵的過期時間為 millisecond 毫秒,使用PX選項效果等同于PSETEX命令,NX: 只在鍵不存在時,才對鍵進行設定操作,使用NX選項效果等同于SETNX命令,XX: 只在鍵已經存在時,才對鍵進行設定操作,
同樣的,使用 SET 命令操作成功之后會回傳 OK,這樣才表示搶到了鎖,
為了避免分布式鎖被誤刪,加鎖時可以設定執行緒 ID 作為 value 值,洗掉時需要執行緒的執行緒 ID 和 Redis 存盤的值一致才能夠洗掉分布式鎖,否則只能等待鎖自動過期,整個洗掉程序使用事務的方式保證原子性,
排行榜功能
通過 Redis 的 SortedSet 可以實作排行榜功能,
比如說需要展示點贊排行榜,可以將用戶 ID 作為 SortedSet 的 value 值,將用戶的點贊數作為 SortedSet 的 score 值,SortedSet 提供的 ZRANGEBYSCORE 命令可以快速回傳已排序的點贊排行榜,
延時佇列
延時佇列其實就是一個帶有延遲功能的訊息佇列,Redis 可以通過 SortedSet 實作延時佇列,
具體的實作如下:
- 將訊息內容序列化成一個字串作為 SortedSet 的 value 值,這個訊息的到期處理時間作為 score,生產者呼叫
ZADD命令生產訊息,消費者可以使用ZRANGEBYSCORE命令獲取一段時間之前的資料輪詢處理; - 通常使用多個執行緒輪詢 SortedSet 獲取到期的任務進行處理,多個執行緒是為了保障可用性,萬一掛了一個執行緒還有其他執行緒可以繼續處理;
- 因為有多個執行緒,所以需要考慮并發爭搶任務,確保任務不能被多次執行,Redis 的
ZREM命令是多執行緒爭搶任務的關鍵,ZREM命令會回傳被成功移除的成員數量,可以通過ZREM命令來決定任務的唯一屬主; - 同時也要注意一定要進行例外捕獲,避免因為個別任務處理問題導致回圈例外退出,同一個任務可能會被多個行程取到之后再使用
ZREM命令進行爭搶,那些沒搶到的行程都是白取了一次任務,這是浪費; - 通常可以使用 Lua 腳本的方式,將
ZRANGEBYSCORE命令和ZREM命令一同挪到服務器端進行原子化操作,這樣多個行程之間爭搶任務時就不會出現這種浪費了,
異步佇列
第一種方案 是使用 List 結構作為異步佇列,RPUSH 命令生產訊息,LPOP 命令消費訊息,當使用 LPOP 命令沒有得到訊息的時候,需要適當 sleep 一會再重試,在這里 sleep 會導致訊息的處理延遲增加,
如果不做 sleep 重試,改進的 第二種方案 是,使用 LPOP 命令的阻塞版本 BLPOP 命令,在 List 佇列中沒有訊息的時候,它會阻塞直到訊息到來,一旦資料到來,則立刻醒過來,訊息的延遲幾乎為零,但是如果執行緒一直阻塞,Redis 的客戶端連接就成了閑置連接,閑置過久,服務器一般會主動斷開連接,減少閑置資源占用,這個時候 BLPOP 命令會拋出例外來,代碼中需要處理這樣的例外,
除了 List 佇列之外,第三種方案 是使用 Pub/Sub 訂閱者模式實作一對多的訊息佇列,但是 Redis 的發布訂閱功能是無狀態的,對于發布者來說,無法知道發布的訊息是否被訂閱者接收到,在消費者下線的情況下,生產的訊息會丟失,
首發于「程式員翔仔」,點擊查看更多,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/542746.html
標籤:其他
