Redis 的 key 的設置規範
- redis 的 key 要求全大寫,命令規範是 系統前綴 : 業務標識,其中系統前綴爲,領域縮寫_系統簡稱_子系統名,業務標識爲,下劃線分隔的業務特徵字符串,要求在保證可讀性的前提下,key 的長度儘可能短,value 小於10K;
緩存雪崩,擊穿和穿透
-
緩存雪崩是指,大量 key 同時失效,導致請求都進入存儲層,給存儲層造成壓力,甚至宕機;
-
緩存雪崩的解決方案是,設置 key 失效時間時添加一個隨機值;
-
緩存擊穿是指,非常熱點的 key 失效,導致大量請求都進入存儲層來重建緩存,給存儲層造成壓力;
-
緩存擊穿的解決方案是,在同步代碼塊中重建緩存,保證 key 失效後,只有一個線程請求到數據庫來重建緩存,或者設置 key 爲不失效,依賴定時任務去刷新緩存;
-
緩存穿透是指,大量請求訪問緩存和數據庫不存在的結果,導致每次請求都到達存儲層,給存儲層造成壓力;
-
緩存穿透的解決方案,一種是將數據庫查詢爲 null 也存放到緩存中,如果出現大量查詢 null 的請求,可能會佔滿緩存,導致有用緩存被淘汰,另一種方案,是在緩存和數據庫之間加入一個布隆過濾器,過濾掉數據庫不存在的請求,減少數據庫壓力;
redis 4.0 之後就引入了布隆過濾器,通過 bf.add,bf.exists 來使用
更多參考:https://www.zhihu.com/search?type=content&q=redis%20%E6%95%96%E4%B8%99
布隆過濾器
-
類似 HashMap 的結構,底層是數組,數組元素是 bit,put 元素時,將元素值經過多次哈希,得到多個數組下標值,將這些數組下標值都設置爲 1,這樣判斷元素是否存在時,只需要同樣多次哈希,判斷各個下標元素的與運算是否是 1;
-
布隆過濾器,使用多次哈希,是爲降低哈希衝突的概率,不同的元素,多次哈希得到的下標都相同的概率,比只一次哈希相同的概率要低,構造布隆過濾器時,參數有數據類型,插入值的個數和期望的誤判率(默認是3%),誤判率和存儲空間,查找時間相關;
-
布隆過濾器用於檢索元素是否在海量集合中,優點是節省空間,查找效率高,但有一定的誤判率和刪除比較困難,集合中存在的元素,一定返回存在,集合中不存在的元素,可能因爲與其他元素哈希衝突,會返回存在;
-
在緩存擊穿上的應用,將數據庫表中的主鍵或唯一字段,放入布隆過濾器中,每次請求在緩存查找不存在時,首先在布隆過濾器中判斷是否存在,如果存在才向數據庫發送請求,否則直接返回結果不存在;
-
布隆過濾器還可以用在垃圾郵箱過濾等海量數據查重的場景上;
Redis 構造分佈式鎖
-
加鎖,setnx(key, value),只有 key 不存在才能設置成功,且是原子操作,所以只有一個線程能設置成功,表示加鎖成功,通常加鎖給 key 設置一個過期時間,來保證鎖能被釋放,不會因爲業務節點問題,導致死鎖;
-
釋放鎖,刪除掉 key 即可,del key;
-
如何解決過期時間到了,但是同步操作還未執行完,還想繼續持有鎖的問題,通過加鎖線程,同時啓動一個守護線程,每間隔一定時間檢查下,如果仍持有鎖,就延長 key 的過期時間,這樣能保證同步操作未完成,能繼續持有鎖,並且不會無限延期,因爲鎖釋放,會顯示關閉守護線程,節點宕機,守護線程也會自動終止;
-
如果要實現可重入鎖,在設置 value 的時候,將加鎖的線程的唯一 id 放入,這樣下次加鎖判斷一下節點 id 是否是自身,來決定是否加鎖成功,
-
真實生產應用場景,通常使用 Redisson 的開源框架來實現,並且 zookeeper 來實現分佈式鎖更容易;
更多參考:https://cloud.tencent.com/developer/article/1349732
https://blog.csdn.net/belongtocode/article/details/102511520
Redis 隊列
-
redis 隊列,使用 list 結構,生產者 rpush,消費者 lpop,可使用 blpop 來阻塞獲取消息,如果要實現 1:N 的廣播,可以使用 pub/sub 的訂閱模式,這種模式當沒有消費者時,消息會丟失,如果要保證消息不丟失,需要使用其他專業 mq;
-
構造延遲隊列,sortedset 結構,生產者 zadd myqueue score value 時,value 爲消息內容,score 爲時間戳,消費者通過 zrangebyscore 來獲取 N 秒之前的消息,比如消息延時 20s 後可以被消費,那麼生產者 zadd,score 爲當前時間戳,而消費者每次獲取消息通過 zrangebyscore myqueue 0 當前時間-20s 來獲取消息,就只會獲取 20s 之前生產的消息,起到延遲消費的作用;
Redis 持久化
-
有 RDB 和 AOF 兩種方式,RDB 是全量持久化,持久化 redis 的全量數據,單次耗時時間長,AOF 是增量持久化,只持久化操作命令,單次耗時時間短;
-
每次 RDB,客戶端會暫停幾毫秒到幾秒的時間,且兩次 RDB 之間,如果發生 Redis 重啓,會丟失該時間間隔的操作數據;
-
AOF 可以設置爲按照時間間隔進行持久化,或者每次執行命令都進行持久化,前者可能發生數據丟失,後者不會丟失數據,但影響性能,並且 AOF 會定期重寫,來壓縮命令空間,如果有誤操作,需要立即關閉重寫,刪除 aof 中的命令,然後通過 rdb 恢復備份,從備份時間點來重放 AOF 來恢復數據;
-
通常兩者結合使用,RDB 間隔時間長,進行全量備份,而 AOF 設置爲 1s 進行一次備份,這樣最多隻丟失 2s 的數據;
Redis 主從同步,從從同步
-
觸發同步時,主節點執行一次 bgsave,生成 rdb 備份,這個過程中主節點接收的操作,都在內存 buffer 中記錄,等待 rdb 備份被髮送到從節點,從節點加載完數據後,主節點再將內存 buffer 的操作發送到從節點;
-
之後,主從節點依賴通過 AOF 日誌,進行同步;
Redis 的內存淘汰機制
-
定期刪除,redis 如果設置了 key 的過期時間,並不是到期馬上刪除,而是 redis 會將所有有過期時間的 key 集中存放,然後每隔一段時間(默認100ms),隨機選擇 20 個 key,判斷是否過期,來進行刪除,並且如果需要刪除的 key 比例超過 1/4,會重複選擇刪除的過程;
-
惰性刪除,是當應用主動獲取某個 key 時,redis 會判斷是否過期,如果過期,直接刪除,不返回給應用;
-
內存淘汰策略,是指當 redis 所佔內存超過設置值時,redis 需要對內存中的一些 key 進行淘汰;
noeviction:不淘汰任何key,返回錯誤
allkeys-lru:針對所有 key,通過 LRU 算法淘汰最久沒有使用的 key
volatile-lru:針對有過期時間的 key,通過 LRU 算法淘汰最久沒有使用的 key
allkeys-random:針對所有 key,隨機刪除
volatile-random:針對有過期時間的 key,隨機刪除
volatile-ttl:針對有過期時間的 key,刪除馬上要過期的 key
volatile-lfu:針對有過期時間的 key,刪除使用頻率最少的 key
allkeys-lfu:針對所有 key,刪除使用頻率最少的 key