【本人禿頂程序員】Redis的n種妙用,不單單是緩存

←←←←←←←←←←←← 快,點關注!redis

介紹

redis是鍵值對的數據庫,經常使用的五種數據類型爲字符串類型(string),散列類型(hash),列表類型(list),集合類型(set),有序集合類型(zset)數據庫

Redis用做緩存,主要兩個用途:高性能,高併發,由於內存自然支持高併發瀏覽器

應用場景

分佈式鎖(string)

setnx key value,當key不存在時,將 key 的值設爲 value ,返回1。若給定的 key 已經存在,則setnx不作任何動做,返回0。緩存

當setnx返回1時,表示獲取鎖,作完操做之後del key,表示釋放鎖,若是setnx返回0表示獲取鎖失敗,總體思路大概就是這樣,細節仍是比較多的,有時間單開一篇來說解服務器

計數器(string)

如知乎每一個問題的被瀏覽器次數併發

set key 0
incr key // incr readcount::{帖子id} 每閱讀一次
get key // get readcount::{帖子id} 獲取閱讀量

分佈式全局惟一id(string) 分佈式全局惟一id的實現方式有不少,這裏只介紹用redis實現dom

每次獲取userId的時候,對userId加1再獲取,能夠改進爲以下形式分佈式

直接獲取一段userId的最大值,緩存到本地慢慢累加,快到了userId的最大值時,再去獲取一段,一個用戶服務宕機了,也頂多一小段userId沒有用到高併發

set userId 0
incr usrId //返回1
incrby userId 1000 //返回10001
消息隊列(list)

在list裏面一邊進,一邊出便可性能

# 實現方式一
# 一直往list左邊放
lpush key value 
# key這個list有元素時,直接彈出,沒有元素被阻塞,直到等待超時或發現可彈出元素爲止,上面例子超時時間爲10s
brpop key value 10 

# 實現方式二
rpush key value
blpop key value 10

過時策略

按期刪除

redis 會將每一個設置了過時時間的 key 放入到一個獨立的字典中,之後會按期遍歷這個字典來刪除到期的 key。

按期刪除策略

Redis 默認會每秒進行十次過時掃描(100ms一次),過時掃描不會遍歷過時字典中全部的 key,而是採用了一種簡單的貪心策略。

從過時字典中隨機 20 個 key; 刪除這 20 個 key 中已通過期的 key; 若是過時的 key 比率超過 1/4,那就重複步驟 1;

惰性刪除

除了按期遍歷以外,它還會使用惰性策略來刪除過時的 key,所謂惰性策略就是在客戶端訪問這個 key 的時候,redis 對 key 的過時時間進行檢查,若是過時了就當即刪除,不會給你返回任何東西。

按期刪除是集中處理,惰性刪除是零散處理。

爲何要採用按期刪除+惰性刪除2種策略呢?

若是過時就刪除。假設redis裏放了10萬個key,都設置了過時時間,你每隔幾百毫秒,就檢查10萬個key,那redis基本上就死了,cpu負載會很高的,消耗在你的檢查過時key上了

可是問題是,按期刪除可能會致使不少過時key到了時間並無被刪除掉,那咋整呢?因此就是惰性刪除了。這就是說,在你獲取某個key的時候,redis會檢查一下 ,這個key若是設置了過時時間那麼是否過時了?若是過時了此時就會刪除,不會給你返回任何東西。

並非key到時間就被刪除掉,而是你查詢這個key的時候,redis再懶惰的檢查一下

經過上述兩種手段結合起來,保證過時的key必定會被幹掉。

因此說用了上述2種策略後,下面這種現象就不難解釋了:數據明明都過時了,可是還佔有着內存

內存淘汰策略

這個問題可能有小夥伴們遇到過,放到Redis中的數據怎麼沒了?

由於Redis將數據放到內存中,內存是有限的,好比redis就只能用10個G,你要是往裏面寫了20個G的數據,會咋辦?固然會幹掉10個G的數據,而後就保留10個G的數據了。那幹掉哪些數據?保留哪些數據?固然是幹掉不經常使用的數據,保留經常使用的數據了

Redis提供的內存淘汰策略有以下幾種:
  • noeviction 不會繼續服務寫請求 (DEL 請求能夠繼續服務),讀請求能夠繼續進行。這樣能夠保證不會丟失數據,可是會讓線上的業務不能持續進行。這是默認的淘汰策略。
  • volatile-lru 嘗試淘汰設置了過時時間的 key,最少使用的 key 優先被淘汰。沒有設置過時時間的 key 不會被淘汰,這樣能夠保證須要持久化的數據不會忽然丟失。(這個是使用最多的)
  • volatile-ttl 跟上面同樣,除了淘汰的策略不是 LRU,而是 key 的剩餘壽命 ttl 的值,ttl 越小越優先被淘汰。
  • volatile-random 跟上面同樣,不過淘汰的 key 是過時 key 集合中隨機的 key。
  • allkeys-lru 區別於 volatile-lru,這個策略要淘汰的 key 對象是全體的 key 集合,而不僅是過時的 key 集合。這意味着沒有設置過時時間的 key 也會被淘汰。
  • allkeys-random 跟上面同樣,不過淘汰的策略是隨機的 key。allkeys-random 跟上面同樣,不過淘汰的策略是隨機的 key。

持久化策略

Redis的數據是存在內存中的,若是Redis發生宕機,那麼數據會所有丟失,所以必須提供持久化機制。

Redis 的持久化機制有兩種,第一種是快照(RDB),第二種是 AOF 日誌。快照是一次全量備份,AOF 日誌是連續的增量備份。快照是內存數據的二進制序列化形式,在存儲上很是緊湊,而 AOF 日誌記錄的是內存數據修改的指令記錄文本。AOF 日誌在長期的運行過程當中會變的無比龐大,數據庫重啓時須要加載 AOF 日誌進行指令重放,這個時間就會無比漫長。因此須要按期進行 AOF 重寫,給 AOF 日誌進行瘦身。

RDB是經過Redis主進程fork子進程,讓子進程執行磁盤 IO 操做來進行 RDB 持久化,AOF 日誌存儲的是 Redis 服務器的順序指令序列,AOF 日誌只記錄對內存進行修改的指令記錄。即RDB記錄的是數據,AOF記錄的是指令

RDB和AOF到底該如何選擇?
  • 不要僅僅使用 RDB,由於那樣會致使你丟失不少數據,由於RDB是隔一段時間來備份數據
  • 也不要僅僅使用 AOF,由於那樣有兩個問題,第一,經過 AOF 作冷備沒有RDB恢復速度快; 第二,RDB 每次簡單粗暴生成數據快照,更加健壯,能夠避免 AOF 這種複雜的備份和恢復機制的 bug
  • 用RDB恢復內存狀態會丟失不少數據,重放AOP日誌又很慢。Redis4.0推出了混合持久化來解決這個問題。將 rdb 文件的內容和增量的 AOF 日誌文件存在一塊兒。這裏的 AOF 日誌再也不是全量的日誌,而是自持久化開始到持久化結束的這段時間發生的增量 AOF 日誌,一般這部分 AOF 日誌很小。因而在 Redis 重啓的時候,能夠先加載 rdb 的內容,而後再重放增量 AOF 日誌就能夠徹底替代以前的 AOF 全量文件重放,重啓效率所以大幅獲得提高。

緩存雪崩和緩存穿透

緩存雪崩是什麼?

假設有以下一個系統,高峯期請求爲5000次/秒,4000次走了緩存,只有1000次落到了數據庫上,數據庫每秒1000的併發是一個正常的指標,徹底能夠正常工做,但若是緩存宕機了,每秒5000次的請求會所有落到數據庫上,數據庫立馬就死掉了,由於數據庫一秒最多抗2000個請求,若是DBA重啓數據庫,立馬又會被新的請求打死了,這就是緩存雪崩。

如何解決緩存雪崩

事前:redis高可用,主從+哨兵,redis cluster,避免全盤崩潰 事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL被打死 過後:redis持久化,快速恢復緩存數據

緩存穿透是什麼?

假如客戶端每秒發送5000個請求,其中4000個爲黑客的惡意攻擊,即在數據庫中也查不到。舉個例子,用戶id爲正數,黑客構造的用戶id爲負數,

若是黑客每秒一直髮送這4000個請求,緩存就不起做用,數據庫也很快被打死。

如何解決緩存穿透

查詢不到的數據也放到緩存,value爲空,如set -999 「」

總而言之,緩存雪崩就是緩存失效,請求所有所有打到數據庫,數據庫瞬間被打死。緩存穿透就是查詢了一個必定不存在的數據,而且從存儲層查不到的數據沒有寫入緩存,這將致使這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。

原文:https://blog.csdn.net/weixin_44175121/article/details/86300688

相關文章
相關標籤/搜索