日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Redis 缓存穿透、雪崩、缓存数据库不一致、持久化方式、分布式锁、过期策略

發(fā)布時間:2023/11/27 生活经验 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis 缓存穿透、雪崩、缓存数据库不一致、持久化方式、分布式锁、过期策略 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. Redis 緩存穿透

1.1 Redis 緩存穿透概念

訪問了不存在的 key,緩存未命中,請求會穿透到 DB,量大時可能會對 DB 造成壓力導(dǎo)致服務(wù)異常。

由于不恰當(dāng)?shù)臉I(yè)務(wù)功能實現(xiàn),或者外部惡意攻擊不斷地請求某些不存在的數(shù)據(jù)內(nèi)存,由于緩存中沒有保存該數(shù)據(jù),導(dǎo)致所有的請求都會落到數(shù)據(jù)庫上,對數(shù)據(jù)庫可能帶來一定的壓力,甚至崩潰。

1.2 Redis 緩存穿透解決方案

  • 針對這些不存在的 key,可以在 Redis 中保存對應(yīng)的 key 和空數(shù)據(jù),并設(shè)置較短的過期時間;
  • 或者使用 Redis Bitmap 來判斷數(shù)據(jù)是否存在以過濾無效請求;

2. Redis 緩存雪崩

2.1 Redis 緩存雪崩概念

緩存同時失效或緩存服務(wù)異常,瞬時大量請求直接到達 DB,對 DB 造成壓力導(dǎo)致服務(wù)異常,

2.2 Redis 緩存雪崩解決方案:

  • 保證緩存服務(wù)的高可用,采用集群,多主多從模式部署,并開啟 RDB 和 AOF 備份,在 Redis 服務(wù)出問題時能快速根據(jù)備份文件恢復(fù)緩存數(shù)據(jù);
  • 緩存過期時間的設(shè)置隨機化;
  • 調(diào)用緩存服務(wù)時增加熔斷模塊,類似 Hystrix;

總的來說,緩存穿透和雪崩帶來的影響都是緩存失效或未命中導(dǎo)致 DB 壓力大,從而可能拖垮服務(wù)。這些情況都是可能導(dǎo)致 DB 異常從而影響服務(wù)的可用性。

其實關(guān)鍵就是過濾無效的數(shù)據(jù),增加緩存命中率,并添加對應(yīng)的隔離措施以增加整個服務(wù)的可用性。

3. Redis 緩存和數(shù)據(jù)庫不一致問題

使用了緩存的話,就有雙寫問題。通常,涉及到雙寫問題,就會有數(shù)據(jù)不一致的情況。需要保存數(shù)據(jù)一致需要犧牲性能,不過實際場景中一般也不要求這么高的一致性。要求嚴(yán)格一致的話,可以將讀請求和寫請求串行化,串到一個內(nèi)存隊列里去,這樣就可以保證一定不會出現(xiàn)不一致的情況。

緩存模式:Cache Aside Pattern(先淘汰緩存,再寫數(shù)據(jù)庫):

  • 讀的時候,先讀緩存,緩存沒有的話,那么就讀數(shù)據(jù)庫,然后取出數(shù)據(jù)后放入緩存,同時返回響應(yīng)讀的時候;
  • 寫的時候,先更新數(shù)據(jù)庫,然后再刪除緩存。

先看一下數(shù)據(jù)的讀取過程,規(guī)則是“先讀 cache,再讀 db”,詳細(xì)步驟如下:

  1. 每次讀取數(shù)據(jù),都從 cache 里讀;

  2. 如果讀到了,則直接返回,稱作 cache hit;

  3. 如果讀不到 cache 的數(shù)據(jù),則從 db 里面撈一份,稱作 cache miss;

  4. 將讀取到的數(shù)據(jù)塞入到緩存中,下次讀取時,就可以直接命中。

再來看一下寫請求,規(guī)則是“先更新 db,再刪除緩存”,詳細(xì)步驟如下:

  1. 將變更寫入到數(shù)據(jù)庫中;

  2. 刪除緩存里對應(yīng)的數(shù)據(jù)。

3.1 并發(fā)情況下出現(xiàn)了數(shù)據(jù)不一致問題怎么辦?

eg. 有個寫請求,此時刪除了緩存中的數(shù)據(jù),但是還沒來得及寫數(shù)據(jù)庫;這個時候來了一個讀請求,又把數(shù)據(jù)庫中的舊數(shù)據(jù) load 到緩存中去了,然后上一個請求的寫數(shù)據(jù)庫操作完成了。這個時候,數(shù)據(jù)庫中的是最新的數(shù)據(jù),緩存中的卻是舊數(shù)據(jù)了.

解決思路:部分請求串行化或采取補償操作。

  • 串行化:將數(shù)據(jù)庫與緩存更新與讀取操作進行異步串行化;將相同 id 的讀寫請求 hash 到同一臺服務(wù)處理,服務(wù)中使用隊列一個一個地執(zhí)行。如果發(fā)現(xiàn)隊列中有對應(yīng)資源的寫請求,那么就等待其執(zhí)行結(jié)束后再去取值返回(這里需要考慮等待時間過長的問題,還有該方案影響較大,較復(fù)雜)。
  • 補償操作:既然是延遲導(dǎo)致的數(shù)據(jù)不一致,那么根據(jù)數(shù)據(jù)庫實際的延遲時間,我們使用定時任務(wù)或者消息觸發(fā),如果有寫請求結(jié)束后,我們在指定的時間之后再刪除一次該緩存值,這樣即使有不一致的臟數(shù)據(jù),那也只會出現(xiàn)在延遲的這一段時間中。

4. 基于 Redis 的分布式鎖是怎么實現(xiàn)的?

分布式鎖實現(xiàn)要保證幾個基本點。

互斥性:任意時刻,只有一個資源能夠獲取到鎖。
容災(zāi)性:能夠在未成功釋放鎖的的情況下,一定時限內(nèi)能夠恢復(fù)鎖的正常功能。
統(tǒng)一性:加鎖和解鎖保證同一資源來進行操作。

示例:我們通過 SETNX 命令來實現(xiàn)的分布式鎖,設(shè)置了過期時間,不至于會出現(xiàn)線程異常導(dǎo)致鎖無法釋放的情況。

5. 為啥 Redis 單線程模型也能效率這么高?

Redis 基于 Reactor 模式開發(fā)了網(wǎng)絡(luò)事件處理器,這個處理器叫做文件事件處理器(File Event Handler)。這個文件事件處理器是單線程的,Redis 才叫做單線程的模型,采用 IO 多路復(fù)用機制同時監(jiān)聽多個 Socket,根據(jù) Socket 上的事件來選擇對應(yīng)的事件處理器來處理這個事件,為啥快呢:

  • 純內(nèi)存操作
  • 核心是基于非阻塞的 IO 多路復(fù)用機制
  • 單線程反而避免了多線程的頻繁上下文切換問題)
  • 內(nèi)部數(shù)據(jù)結(jié)構(gòu)設(shè)計,整個的結(jié)構(gòu)都類似于一個 map,查找效率賊高

Redis是單線程處理網(wǎng)絡(luò)指令請求,所以不需要考慮并發(fā)安全問題。所有的網(wǎng)絡(luò)請求都是一個線程處理。但不代表所有模塊都是單線程。

6. Redis 持久化方式及其區(qū)別

Redis 有持久化機制的,它支持 AOF 和 RDB 兩種持久化方式。

RDB:通過 fork 一個子進程保存當(dāng)前內(nèi)存的一個快照實現(xiàn)備份. 適合大規(guī)模的數(shù)據(jù)恢復(fù),但是數(shù)據(jù)的完整性和一致性不高,因為 RDB 可能在最后一次備份時宕機了。另外備份時會占用內(nèi)存,因為 Redis 在備份時會獨立創(chuàng)建一個子進程,將數(shù)據(jù)寫入到一個臨時文件(此時內(nèi)存中的數(shù)據(jù)是原來的兩倍哦),最后再將臨時文件替換之前的備份文件。配置方法如下:

    # save <指定時間間隔> <執(zhí)行指定次數(shù)更新操作>,滿足條件就將內(nèi)存中的數(shù)據(jù)同步到硬盤中save <seconds> <changes>  # 指定本地數(shù)據(jù)庫文件名,一般采用默認(rèn)的 dump.rdbdbfilename dump.rdb # 默認(rèn)開啟數(shù)據(jù)壓縮rdbcompression yes

AOF: 通過對每條寫入命令以 append-only 的模式寫入一個日志文件中,在 Redis 重啟的時候,可以通過回放 AOF 日志中的寫入指令來重新構(gòu)建整個數(shù)據(jù)集。 AOF 對數(shù)據(jù)數(shù)據(jù)的完整性和一致性支持更好,但是其備份日志文件一般會比 RDB 方式的備份文件更大,恢復(fù)也更慢,同時由于 fsync 的頻率方式,會影響 Redis 的性能。

     # 打開aofappendonly yes     # 日志文件appendfilename "appendonly.aof"  # 更新條件# appendfsync alwaysappendfsync everysec# appendfsync no# 觸發(fā)重寫的配置# 時間長了日志會特別大,此時需要觸發(fā)重寫# 重寫的原理:Redis 會fork出一條新進程,讀取內(nèi)存中的數(shù)據(jù),并重新寫到一個臨時文件中。#           最后替換舊的aof文件。auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb

后續(xù):Redis 4.0 之后,持久化增加了混合 RDB-AOF 持久化格式。具體可以參考

http://blog.huangz.me/diary/2016/redis-4-outline.html

7. Redis 如何實現(xiàn)分布式和高可用?

Redis 主從模式原理:

Redis 2.8 之前主從模式,主從之間的數(shù)據(jù)復(fù)制只有全復(fù)制機制,通過執(zhí)行命令 SLAVEOF ip port,使得其成為從服務(wù)器。全數(shù)據(jù)復(fù)制流程如下:

從服務(wù)器向主服務(wù)器發(fā)送 SYNC 命令。
主服務(wù)器收到 SYNC 請求后,執(zhí)行 BGSAVE 命令在后臺生成 RDB 文件,并使用一個緩沖區(qū)記錄從現(xiàn)在開始執(zhí)行的寫命令。
主服務(wù)器將生成的 RDB 文件發(fā)送給從服務(wù)器,從服務(wù)器根據(jù)RDB文件更新狀態(tài)。
主服務(wù)器將緩沖區(qū)中的寫命令發(fā)送給從服務(wù)器,從服務(wù)器執(zhí)行這些命令,最終和主服務(wù)器達到一致的狀態(tài)。

命令傳播

數(shù)據(jù)復(fù)制完成后,為了保持一致的狀態(tài),主服務(wù)的寫命令都需要傳播給其從服務(wù)器。

不足:上面的方式存在不足,即如果從服務(wù)器是和主服務(wù)器斷開后,又立馬重新連接上后。那么此時如果還執(zhí)行全同步的話,就十分浪費。因為全同步非常占用 CPU、IO 和帶寬等。

Redis 2.8 之后,支持了 PSYNC,即部分重同步機制。部分重同步機制主要依靠:

主從服務(wù)器的復(fù)制偏移量: 用于記錄主從服務(wù)器的狀態(tài)是否一致,以及數(shù)據(jù)復(fù)制時的偏移量
主服務(wù)器的復(fù)制積壓緩沖區(qū):固定大小的(默認(rèn) 1M)FIFO 隊列,用于記錄主服務(wù)器的寫命令
主服務(wù)器的 ID:用于判斷,從服務(wù)器斷開連接后重新連接到的主服務(wù)器還是不是原來那個

部分重同步流程:

主從服務(wù)器都有一個復(fù)制偏移量,當(dāng)執(zhí)行了寫命令時,復(fù)制偏移量對應(yīng)會增加。

從服務(wù)器請求同步,帶上當(dāng)前的 offset 和之前的主服務(wù)器 ID;
如果請求中的主服務(wù) ID 和當(dāng)前的主服務(wù)器ID不一致,或者其 offset 的值已經(jīng)不再復(fù)制積壓緩沖區(qū)內(nèi),那么需要執(zhí)行全同步,流程同上;
否則,執(zhí)行部分同步,主服務(wù)器將復(fù)制積壓緩沖區(qū)中 offset 之后的命令發(fā)送給從服務(wù)器;
從服務(wù)器執(zhí)行對應(yīng)寫命令,并修改 offset,達到和主服務(wù)器狀態(tài)一致。

8. Redis 的過期策略都有哪些?

8.1 定時刪除策略

在設(shè)置 key 的過期時間的同時,為該 key 創(chuàng)建一個定時器,讓定時器在 key 的過期時間來臨時,對 key 進行刪除。

  • 優(yōu)點:保證內(nèi)存盡快釋放。
  • 缺點:若 key 過多,刪除這些 key 會占用很多 CPU 時間, 而且每個 key 創(chuàng)建一個定時器,性能影響嚴(yán)重。

8.2 惰性刪除策略

key 過期的時候不刪除,每次從數(shù)據(jù)庫獲取 key 的時候去檢查是否過期,若過期,則刪除,返回 null。

  • 優(yōu)點:CPU 時間占用比較少。
  • 缺點:若 key 很長時間沒有被獲取, 將不會被刪除,可能造成內(nèi)存泄露

8.3 定期刪除策略

每隔一段時間執(zhí)行一次刪除(在 redis.conf 配置文件設(shè)置 hz,1s 刷新的頻率)過期 key 操作。

  • 優(yōu)點:可以控制刪除操作的時長和頻率,來減少 CPU 時間占用,可以避免惰性刪除時候內(nèi)存泄漏的問題。

  • 缺點:
    對內(nèi)存友好方面,不如定時策略
    對 CPU 友好方面,不如惰性策略

那如果執(zhí)行了上述的刪除操作后,Redis 的內(nèi)存空間還是不足怎么辦呢?

設(shè)置了過期時間的,到期后會被上述操作刪除掉;如果此時內(nèi)存還是不夠的話,Redis 會根據(jù)配置的策略來執(zhí)行對應(yīng)的操作,主要有 noeviction、allkeys-lru、allkeys-random、volatile-lru、volatile-random、volatile-ttl 這幾種,balabalabala…

  • noeviction:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報錯,這個一般沒人用吧,實在是太惡心了。
  • allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的 key(這個是最常用的)。
  • allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,隨機移除某個 key,這個一般沒人用吧,為啥要隨機,肯定是把最近最少使用的 key 給干掉啊。
  • volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,移除最近最少使用的 key(這個一般不太合適)。
  • volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,隨機移除某個 key。
  • volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,有更早過期時間的 key 優(yōu)先移除。

部分內(nèi)容參考以下鏈接

https://gitbook.cn/books/5d07228c2df51311ff3a6498/index.html

https://gitbook.cn/books/5c97654679ca930d56250d14/index.html

總結(jié)

以上是生活随笔為你收集整理的Redis 缓存穿透、雪崩、缓存数据库不一致、持久化方式、分布式锁、过期策略的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。