Redis-緩存相關(guān)QA

1. 為什么Redis性能這么強(qiáng)

支持?jǐn)?shù)十萬的并發(fā)(32G可以Set操作達(dá)到30W的QPS, Get操作40W的QPS),pipline則更高x2

  • 內(nèi)存存儲(chǔ):Redis是使用內(nèi)存(in-memeroy)存儲(chǔ),沒有磁盤IO上的開銷

  • 單線程實(shí)現(xiàn):Redis使用單個(gè)線程處理請求,避免了多個(gè)線程之間線程切換和鎖資源爭用的開銷

  • 非阻塞IO:Redis使用多路復(fù)用IO技術(shù),在poll,epolll,kqueue選擇最優(yōu)IO實(shí)現(xiàn)(參考netty篇章)

  • 優(yōu)化的數(shù)據(jù)結(jié)構(gòu):Redis有諸多可以直接應(yīng)用的優(yōu)化數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),應(yīng)用層可以直接使用原生的數(shù)據(jù)結(jié)構(gòu)提升性能

2. 為什么用Redis

高性能:mysql數(shù)據(jù)存儲(chǔ)磁盤,訪問較慢。 redis存內(nèi)存,訪問快。50ms,10ms

大并發(fā):mysql并發(fā)能力有限(8C32G的mysql,8000的最大連接數(shù),可以達(dá)到3W的QPS,1.5K的TPS),在大并發(fā)情況下需要引入redis來緩沖數(shù)據(jù)訪問(4 50W的QPS),避免擊穿mysql。

3. Redis數(shù)據(jù)結(jié)構(gòu)

  • String

  • List

  • Hash

  • Set

  • Sorted Set

  • Bitmap

    boomfilter

Redis為什么單線程

https://draveness.me/whys-the-design-redis-single-thread/

單線程模型,基于多路復(fù)用IO模型監(jiān)聽多個(gè)連接。

  1. 使用單線程模型能帶來更好的可維護(hù)性,方便開發(fā)和調(diào)試;

    不需要引入鎖之類機(jī)制來控制同步。(比如變量被并發(fā)讀寫了,那么需要加鎖之類,不然訪問結(jié)果無法確定)

  2. 使用單線程模型也能并發(fā)的處理客戶端的請求;

    多路復(fù)用IO也能同時(shí)監(jiān)聽多個(gè)FD,當(dāng)監(jiān)聽到有相關(guān)事件發(fā)生時(shí)就調(diào)用相應(yīng)的事件處理器進(jìn)行處理。https://draveness.me/redis-io-multiplexing/

  3. Redis 服務(wù)中運(yùn)行的絕大多數(shù)操作的性能瓶頸都不是 CPU;

    Redis 并不是 CPU 密集型的服務(wù),如果不開啟 AOF 備份,所有 Redis 的操作都會(huì)在內(nèi)存中完成不會(huì)涉及任何的 I/O 操作,這些數(shù)據(jù)的讀寫由于只發(fā)生在內(nèi)存中,所以處理速度是非??斓?。

    整個(gè)服務(wù)的瓶頸在于網(wǎng)絡(luò)傳輸帶來的延遲和等待客戶端的數(shù)據(jù)傳輸,也就是網(wǎng)絡(luò) I/O。

    在普通的linux上,redis也可以在1S內(nèi)處理100W的請求。 如果這種還不夠的話就做集群。

Redis引入多線程

redis4.0之后引入了一些命令,例如 UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC 等非阻塞的刪除操作,這些命令會(huì)使用主線程外的線程執(zhí)行。

刪除操作如果刪除的KV對占用比較小,那么同步也沒什么問題。但是如果是幾十幾百M(fèi)B的那么會(huì)消耗較多時(shí)間,不能在幾MS內(nèi)處理完,影響Redis的可用性。UNLINK命令將鍵從元數(shù)據(jù)中刪除,無法再被訪問到,真正的刪除操作會(huì)在后臺(tái)異步執(zhí)行。

Redis持久化機(jī)制

RDB 快照持久化

創(chuàng)建快照后獲得某個(gè)時(shí)間點(diǎn)上完整的數(shù)據(jù)副本,快照可以用來復(fù)制到其他Redis從服務(wù)器來創(chuàng)建相同數(shù)據(jù),或者用來重啟服務(wù)時(shí)候進(jìn)行恢復(fù)數(shù)據(jù)。

快照持久化是 Redis 默認(rèn)采用的持久化方式,在 Redis.conf 配置文件中默認(rèn)有此下配置:

save 900 1           #在900秒(15分鐘)之后,如果至少有1個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
save 300 10          #在300秒(5分鐘)之后,如果至少有10個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
save 60 10000        #在60秒(1分鐘)之后,如果至少有10000個(gè)key發(fā)生變化,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
AOF(append-only file)持久化

AOF模式實(shí)時(shí)性更強(qiáng),默認(rèn)沒有開啟,需要配置appendonly yes來開啟。每執(zhí)行一條修改數(shù)據(jù)的命令都會(huì)將命令寫入硬盤的AOF文件。

appendfsync always    #每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫入AOF文件,這樣會(huì)嚴(yán)重降低Redis的速度
appendfsync everysec  #每秒鐘同步一次,顯示地將多個(gè)寫命令同步到硬盤 推薦
appendfsync no        #讓操作系統(tǒng)決定何時(shí)進(jìn)行同步

AOF重寫:
執(zhí)行BGREWRITEAOF會(huì)創(chuàng)建一個(gè)子進(jìn)程進(jìn)行AOF重寫,但是其實(shí)不會(huì)讀取當(dāng)前的AOF文件,是通過讀取現(xiàn)在數(shù)據(jù)庫中KV數(shù)據(jù)生成新的AOF文件。新的AOF文件體積更加小。

Redis事務(wù)

Redis 過期機(jī)制

Redis集群模式

Redis pipeline、script、mass insertion

Redis配置修改

config set 可以不重啟redis,實(shí)時(shí)生效配置

CONFIG SET protected-mode no

緩存相關(guān)

https://mp.weixin.qq.com/s/TBCEwLVAXdsTszRVpXhVug

https://segmentfault.com/a/1190000008931971

緩存穿透

指查詢不存在的數(shù)據(jù),緩存層沒有命中,導(dǎo)致每次都查詢數(shù)據(jù)庫層,使得緩存層失去了保護(hù)存儲(chǔ)層的意義,產(chǎn)生原因可能如下:

  1. 業(yè)務(wù)自身代碼或者數(shù)據(jù)出現(xiàn)問題

  2. 一些惡意攻擊、爬蟲等造成大量空命中

可以進(jìn)行分析統(tǒng)計(jì)方法調(diào)用次數(shù),緩存命中次數(shù),儲(chǔ)存層命中次數(shù),判斷是否出現(xiàn)了緩存穿透的情況。

解決方案1. 緩存空對象

在存儲(chǔ)層也返回空時(shí),把空對象也保存到緩存,這樣下次查詢就會(huì)命中緩存。

問題:占用更多存儲(chǔ)空間,而且如果是惡意攻擊則會(huì)更加嚴(yán)重。

解決:

  1. 添加一個(gè)較小的TTL ,使其自動(dòng)過期刪除

2. 空對象緩存放到另外單獨(dú)的一個(gè)緩存服務(wù),避免空間不夠回收時(shí)LRU算法剔除了正常的KV而沒有過期空對象

問題: 數(shù)據(jù)不一致,如果緩存了空對象,然后業(yè)務(wù)操作導(dǎo)致存儲(chǔ)層有把數(shù)據(jù)添加上了,那么在空對象緩存過期之前兩邊數(shù)據(jù)產(chǎn)生了不一致。

解決:

1. 如果是redis緩存,則更新數(shù)據(jù)后直接刪除緩存

  1. 如果是本地緩存,則需要引入消息中間件之類通知機(jī)制,通知?jiǎng)h除
解決方案2. 布隆過濾器

在訪問緩存層之前,先訪問布隆過濾器,如果miss,那就是不存在直接返回空對象。如果命中再繼續(xù)查詢緩存和存儲(chǔ)層。

boomfilter命中可能誤判,但是不命中必定是真的不命中。

缺點(diǎn):需要額外維護(hù)boomfilter,刪除數(shù)據(jù)時(shí)候需要重建,添加數(shù)據(jù)時(shí)候需要通知插入。如果是本地緩存構(gòu)建的boomfilter那也還需要引入消息通知機(jī)制。如果是使用redis bitmap實(shí)現(xiàn)的那還簡單點(diǎn)。

緩存雪崩

緩存正常起著承擔(dān)大量請求,保護(hù)存儲(chǔ)層的作用,但是由于某些情況導(dǎo)致緩存層無法提供服務(wù),那么所有請求到達(dá)了存儲(chǔ)層,導(dǎo)致存儲(chǔ)層掛掉宕機(jī)。

產(chǎn)生的原因:

  1. 緩存層服務(wù)可用性不高,重啟,或者網(wǎng)絡(luò)等各種故障導(dǎo)致一段時(shí)間內(nèi)無法提供服務(wù)
  2. 熱點(diǎn)key,大量緩存同時(shí)失效過期

解決:

  1. 針對可用性問題可以構(gòu)建集群+主備來提高可用性
  2. 大量緩存同時(shí)失效問題可以在存儲(chǔ)層讀寫時(shí)候進(jìn)行隊(duì)列,加鎖,信號(hào)量等控制并發(fā)數(shù)量。(hystrix對訪問進(jìn)行熔斷限流)
  3. 大量緩存同時(shí)失效問題也可以對key設(shè)置分散的過期時(shí)間
  4. 針對熱點(diǎn)key過期,可以設(shè)置永不過期,然后異步單獨(dú)的線程來更新重建熱點(diǎn)key數(shù)據(jù)
  5. 針對熱點(diǎn)key過期,也可以在過期重建數(shù)據(jù)時(shí)候加鎖,只允許一個(gè)線程進(jìn)行重建,其他線程進(jìn)行等待重建完成。分布式環(huán)境下可以用redis setnx鎖。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容