
一般分為兩種緩存和分布式鎖。緩存包含穿透、擊穿、雪崩、雙寫一致、持久化、數(shù)據(jù)過期、淘汰策略分布式鎖包含setnx、redisson一、緩存穿透緩存穿透概念查詢一個不存在的數(shù)據(jù)mysql查詢不到數(shù)據(jù)也不會直接寫入緩存就會導(dǎo)致每次請求都查數(shù)據(jù)庫這種情況下數(shù)據(jù)庫需要處理這個請求并返回結(jié)果。如果請求頻繁數(shù)據(jù)庫的負載就會增加甚至可能導(dǎo)致數(shù)據(jù)庫崩潰。解決方案一緩存空數(shù)據(jù)緩存空數(shù)據(jù) 查詢返回的數(shù)據(jù)為空仍把這個空結(jié)果進行緩存優(yōu)點簡單缺點消耗內(nèi)存可能會發(fā)生不一致得問題如果數(shù)據(jù)庫中有值了但redis中沒有就會不一致解決方案二布隆過濾器布隆過濾器:在我們進行緩存預(yù)熱的時候需要給布隆過濾器中添加數(shù)據(jù)若有請求時先請求布隆過濾器判斷請求得id或其他 是否存在若存在去查redis若不存在直接返回不存在。bitmap(位圖)相當于是一個以bit位為單位得數(shù)組數(shù)組中每個單元只能存儲二進制數(shù)0或1布隆過濾器作用可以用于檢索一個元素是否在一個集合中優(yōu)點內(nèi)存占用較少沒有多余得key缺點實現(xiàn)復(fù)雜也可能存在誤判緩存穿透原因1.緩存未命中當請求的數(shù)據(jù)不存在于緩存中時緩存系統(tǒng)無法提供響應(yīng)導(dǎo)致請求直接訪問數(shù)據(jù)庫。2.緩存失效緩存中的數(shù)據(jù)過期或被清除導(dǎo)致后續(xù)請求無法命中緩存直接訪問數(shù)據(jù)庫。3.緩存雪崩大量緩存同時失效導(dǎo)致請求全部訪問數(shù)據(jù)庫形成緩存穿透。緩存穿透影響1.增加數(shù)據(jù)庫壓力緩存穿透會導(dǎo)致數(shù)據(jù)庫訪問量激增增加數(shù)據(jù)庫負載甚至可能導(dǎo)致數(shù)據(jù)庫崩潰。2.降低系統(tǒng)性能頻繁的數(shù)據(jù)庫訪問會導(dǎo)致系統(tǒng)響應(yīng)時間延長降低系統(tǒng)性能。3.增加運維成本緩存穿透需要額外的數(shù)據(jù)庫維護和優(yōu)化增加運維成本。緩存穿透預(yù)防措施1.限制查詢頻率對查詢操作進行頻率限制避免惡意攻擊。2.使用緩存預(yù)熱在系統(tǒng)啟動時將熱點數(shù)據(jù)加載到緩存中減少查詢數(shù)據(jù)庫的次數(shù)。緩存穿透的檢測方法監(jiān)控數(shù)據(jù)庫訪問量通過監(jiān)控數(shù)據(jù)庫訪問量發(fā)現(xiàn)異常情況。分析日志分析系統(tǒng)日志發(fā)現(xiàn)緩存穿透的請求。緩存穿透的優(yōu)化策略使用分布式緩存將緩存部署在多個節(jié)點上提高緩存系統(tǒng)的可用性和性能。使用緩存集群將緩存集群部署在多個服務(wù)器上提高緩存系統(tǒng)的擴展性和性能。面試題面試官:什么是緩存穿透?怎么解決?緩存穿透是指查詢一個一定不存在的數(shù)據(jù)。如果從存儲層查不到數(shù)據(jù)則不寫入緩存這將導(dǎo)致這個不存在的數(shù)據(jù)每次請求都要到DB去查詢可能導(dǎo)致DB掛掉。這種情況大概率是遭到了攻擊。解決方案的話我們通常都會用布隆過濾器來解決它面試官:你能介紹一下布隆過濾器嗎?是這樣~布隆過濾器主要是用于檢索一個元素是否在一個集合中。我們當時使用的是redisson實現(xiàn)的布隆過濾它的底層主要是先去初始化一個比較大數(shù)組里面存放的二進制0或1。在一開始都是0當一個key來了之后經(jīng)過3次hash計算模于數(shù)組長度找到數(shù)據(jù)的下標然后把數(shù)組中原來的0改為1這樣的話三個數(shù)組的位置就能標明一個key的存在。查找的過程也是一樣的。當然是有缺點的布隆過濾器有可能會產(chǎn)生一定的誤判。我們一般可以設(shè)置這個誤判率大概不會超過5%其實這個誤判是必然存在的要不就得增加數(shù)組的長度其實已經(jīng)算是很劃分了5%以內(nèi)的誤判率一般項目也能接受不至于高并發(fā)下壓倒數(shù)據(jù)庫。二、緩存擊穿緩存擊穿概念給某一個key設(shè)置了過期時間當key過期的時候恰好這時間點對這個key有大量得并發(fā)請求過來這些并發(fā)請求會瞬間把數(shù)據(jù)庫DB壓垮。解決方案一互斥鎖(能保證數(shù)據(jù)的強一致性性能差)解決方案二邏輯過期(有限保證高可用性能優(yōu)不能保證數(shù)據(jù)絕對一致)面試問題面試官:什么是緩存擊穿?怎么解決?候選人:緩存擊穿的意思是對于設(shè)置了過期時間的key緩存在某個時間點過期的時候恰好這時間點對這個Key有大量的并發(fā)請求過來。這些請求發(fā)現(xiàn)緩存過期一般都會從后端DB加載數(shù)據(jù)并回設(shè)到緩存這個時候大并發(fā)的請求可能會瞬間把DB壓垮。解決方案有兩種方式:第一可以使用互斥鎖:當緩存失效時不立即去load db先使用如Redis 的setnx去設(shè)置一個互斥鎖.當操作成功返回時再進行l(wèi)oaddb的操作并回設(shè)緩存否則重試get緩存的方法第二種方案可以設(shè)置當前key邏輯過期。大概是思路如下:1.在設(shè)置key的時候設(shè)置一個過期時間字段一塊存入緩存中不給當前key設(shè)置過期時間2.當查詢的時候。從redis取出數(shù)據(jù)后判斷時間是否過期3.如果過期則開通另外一個線程進行數(shù)據(jù)同步當前線程正常返回數(shù)據(jù)這個數(shù)據(jù)不是最新當然兩種方案各有利弊:如果選擇數(shù)據(jù)的強一致性。建議使用分布式鎖的方案性能上可能沒那么高鎖需要等也有可能產(chǎn)生死鎖的問題。如果選擇key的邏輯刪除則優(yōu)先考慮的高可用性性能比較高但是數(shù)據(jù)同步這塊做不到強一致。三、緩存雪崩緩存雪崩概念是指在同一時段大量的緩存key同時失效或者redis服務(wù)宕機導(dǎo)致大量請求到達數(shù)據(jù)庫帶來巨大壓力解決方案1.給不同的key的TTL添加隨機值2.利用redis集群提高服務(wù)的可用性哨兵模式、集群模式redis宕機方案3.給緩存業(yè)務(wù)添加降級限流策略nginx或spring cloud gateway降級策略可作為系統(tǒng)的保底策略適用于穿透、擊穿、雪崩4.給業(yè)務(wù)添加多級緩存Guava或Caffeine面試問題面試官:什么是緩存雪崩?怎么解決?候選人:緩存雪崩意思是設(shè)置緩存時采用了相同的過期時間導(dǎo)致緩存在某一時刻同時失效請求全部轉(zhuǎn)發(fā)到DBDB瞬時壓力過重雪崩。與緩存擊穿的區(qū)別:雪崩是很多key擊穿是某一個key緩存。解決方案主要是可以將緩存失效時間分散開比如可以在原有的失效時間基礎(chǔ)上增加一個隨機值比如1-5分鐘隨機這樣每一個緩存的過期時間的重復(fù)率就會降低就很難引發(fā)集體失效的事件。方便記憶的打油詩《緩存三兄弟》穿透無中生有key布隆過濾nul隔離。緩存擊穿過期key鎖與非期解難題。雪崩大量過期key過期時間要隨機。面試必考三兄弟可用限流來保底。四、緩存雙寫一致性redis作為緩存mysql的數(shù)據(jù)如何與redis進行同步呢雙寫一致性概念 當修改了數(shù)據(jù)庫的數(shù)據(jù)也要同時更新緩存的數(shù)據(jù)緩存和數(shù)據(jù)可的數(shù)據(jù)要保持一致如果需要實時的進行數(shù)據(jù)同步為了保證數(shù)據(jù)的情義值性采用redisson提供的讀寫鎖來保證數(shù)據(jù)的同步如果實時要求性并沒有那么高可以用異步的方案同步數(shù)據(jù)為了保證強一致性使用讀寫操作讀操作讀數(shù)據(jù)操作緩存命中直接返回緩存未命中查詢數(shù)據(jù)庫寫入緩存設(shè)定超時時間寫操作寫數(shù)據(jù)操作延遲雙刪異步通知保證數(shù)據(jù)的最終一致性面試問題面試官:redis做為緩存mysql的數(shù)據(jù)如何與redis進行同步呢?(雙寫一致性)候選人:嗯!就說我最近做的這個項目里面有xxx(根據(jù)自己的簡歷上寫)的功能需要讓數(shù)據(jù)庫與redis高度保持一致因為要求時效性比較高我們當時采用的讀寫鎖保證的強一致性。我們采用的是redisson實現(xiàn)的讀寫鎖在讀的時候添加共享鎖可以保證讀讀不互斥讀寫互斥。當我們更新數(shù)據(jù)的時候添加排他鎖它是讀寫讀讀都互斥這樣就能保證在寫數(shù)據(jù)的問時是不會讓其他線程讀數(shù)據(jù)的避免了臟數(shù)據(jù)。這里面需要注意的是讀方法和寫方法上需要使用同一把鎖才行。面試官:那這個排他鎖是如何保證讀寫、讀讀互斥的呢?候選人:其實排他鎖底層使用也是setnx保證了同時只能有一個線程操作鎖住的方法面試官:你聽說過延時雙刪嗎?為什么不用它呢?候選人:延遲雙刪如果是寫操作我們先把緩存中的數(shù)據(jù)刪除然后更新數(shù)據(jù)庫最后再延時刪除緩存中的數(shù)據(jù)其中這個延時多久不太好確定在延時的過程中可能會出現(xiàn)臟數(shù)據(jù)并不能保證強一致性所以沒有采用它。|面試官:redis做為緩存mysql的數(shù)據(jù)如何與redis進行同步呢?(雙寫一致性)候選人:嗯!就說我最近做的這個項目里面有xxxX(根據(jù)自己的簡歷上寫)的功能數(shù)據(jù)回步可以有一定的延時《符合大部分業(yè)務(wù))我們當時采用的阿里的canal組件實現(xiàn)數(shù)據(jù)網(wǎng)步:不需要更改業(yè)務(wù)代碼部署一個canal服務(wù)。canal服務(wù)把自己偽裝成mysql的一個從節(jié)點當mysql數(shù)據(jù)更新以后canal會讀取binlog數(shù)據(jù)然后在通過canal的客戶端獲取到數(shù)據(jù)更新緩存即可。五、redis緩存的持久化分為兩個RDB和AOFRDB全稱Redis Database Backup file(Redis數(shù)據(jù)備份文件)也被叫做Redis數(shù)據(jù)快照。簡單來說就是把內(nèi)存中的所有數(shù)據(jù)都記錄到磁盤中。當Redis實例故障重啟后從磁盤讀取快照文件恢復(fù)數(shù)據(jù)RDB執(zhí)行原理bgsave開始時會fork克隆主進程得到子進程子進程共享主進程的內(nèi)存數(shù)據(jù)。完成fork后讀取內(nèi)存數(shù)據(jù)并寫入RDB文件。fork采用的是copy-on-write技術(shù):當主進程執(zhí)行讀操作時訪問共享內(nèi)存;當主進程執(zhí)行寫操作時則會拷貝一份數(shù)據(jù)執(zhí)行寫操作。AOF全稱為Append Only File追加文件。redis處理每一個寫命令都會記錄在AOF文件可以看作是命令日志文件AOF默認是關(guān)閉的需要修改redis.conf配置文件來開啟AOFAOF的命令記錄的頻率也可以通過redis.conf文件配置因為是記錄命令A(yù)OF文件會比RDB文件大的多。而且AOF會記錄對同一個key的多次寫操作但只有最后一次寫操作才有意義。通過執(zhí)行bgrewriteaof命令可以讓AOF文件執(zhí)行重寫功能用最少的命令達到相同效果。redis也會在觸發(fā)閾值時自動去重寫AOF文件。閾值也可以在redis.conf中配置RDB與AOF對比各有優(yōu)缺點如果對數(shù)據(jù)安全性要求較高在實際開發(fā)中往往會結(jié)合兩者來使用面試問題面試官:redis做為緩存數(shù)據(jù)的持久化是怎么做的?候選人:在Redis中提供了兩種數(shù)據(jù)持久化的方式:1、RDB 2、AOF面試官:這兩種持久化方式有什么區(qū)別呢?候選人:RDB是一個快照文件它是把redis內(nèi)存存儲的數(shù)據(jù)寫到磁盤上當redis實例宕機恢復(fù)數(shù)據(jù)的時候方便從RDB的快照文件中恢復(fù)數(shù)據(jù)。AOF的含義是追加文件當redis操作寫命令的時候都會存儲這個文件中當redis實例宕機恢復(fù)數(shù)據(jù)的時候會從這個文件中再次執(zhí)行一遍命令來恢復(fù)數(shù)據(jù)面試官:這兩種方式哪種恢復(fù)的比較快呢?候選人:RDB因為是二進制文件在保存的時候體積也是比較小的它恢復(fù)的比較快但是它有可能會丟數(shù)據(jù)我們通常在項目中也會使用AOF來恢復(fù)數(shù)據(jù)雖然AOF恢復(fù)的速度慢一些但是它丟數(shù)據(jù)的風險要小很多在AOF文件中可以設(shè)置刷盤策略我們當時設(shè)置的就是每秒批量寫入一次命令六、數(shù)據(jù)過期策略redis的key過期后會立即刪除嗎數(shù)據(jù)過期策略概念Redis對數(shù)據(jù)設(shè)置數(shù)據(jù)的有效時間數(shù)據(jù)過期以后就需要將數(shù)據(jù)從內(nèi)存中刪除掉??梢园凑詹煌囊?guī)則進行刪除這種刪除規(guī)則就被稱之為數(shù)據(jù)的刪除策略。Redis的過期刪除策略:惰性刪除定期刪除兩種策略進行配合使用兩種策略1.惰性刪除2.定期刪除惰性刪除:設(shè)置該key過期時間后我們不去管它當需要該key時我們在檢查其是否過期如果過期我們就刪掉它反之返回該key優(yōu)點:對CPU友好只會在使用該key時才會進行過期檢查對于很多用不到的key不用浪費時間進行過期檢查缺點:對內(nèi)存不友好如果一個key已經(jīng)過期但是一直沒有使用那么該key就會一直存在內(nèi)存中內(nèi)存永遠不會釋放定期刪除:每隔一段時間我們就對一些key進行檢查刪除里面過期的key(從一定數(shù)量的數(shù)據(jù)庫中取出一定數(shù)量的隨機key進行檢查并刪除其中的過期key)。定期清理有兩種模式:SLOW模式是定時任務(wù)執(zhí)行頻率默認為10hz每次不超過25ms,以通過修改配置文件redis.conf 的hz選項來調(diào)整這個次數(shù)FAST模式執(zhí)行頻率不固定但兩次間隔不低于2ms每次耗時不超過1ms優(yōu)點:可以通過限制刪除操作執(zhí)行的時長和頻率來減少刪除操作對CPU的影響。另外定期刪除也能有效釋放過期鍵占用的內(nèi)存。缺點:難以確定刪除操作執(zhí)行的時長和頻率。面試問題面試官:Redis的數(shù)據(jù)過期策略有哪些?候選人:在redis中提供了兩種數(shù)據(jù)過期刪除策略第一種是惰性刪除在設(shè)置該key過期時間后我們不去管它當需要該key時我們在檢查其是否過期如果過期我們就刪掉它反之返回該key。第二種是定期刪除就是說每隔一段時間我們就對一些key進行檢查刪除里面過期的key定期清理的兩種模式:SLOW模式是定時任務(wù)執(zhí)行頻率默認為10hz每次不超過25ms以通過修改配置文件redis.confFAST模式執(zhí)行頻率不固定每次事件循環(huán)會嘗試執(zhí)行但兩次間隔不低于2ms每次耗時不超過lms的hz選項來調(diào)整這個次數(shù)Redis的過期刪除策略:惰性刪除定期刪除兩種策略進行配合使用七、數(shù)據(jù)淘汰策略緩存過多內(nèi)存有限內(nèi)存被占滿了怎么辦數(shù)據(jù)的淘汰策略:當Redis中的內(nèi)存不夠用時此時在向Redis中添加新的key那么Redis就會按照某一種規(guī)則將內(nèi)存中的數(shù)據(jù)刪除掉這種數(shù)據(jù)的刪除規(guī)則被稱之為內(nèi)存的淘汰策略。LRU(Least Recently Used)最近最少使用。用當前時間減去最后一次訪問時間這個值越大則淘汰優(yōu)先級越高。LFU(Least Frequently Used)最少頻率使用。會統(tǒng)計每個key的訪問頻率值越小淘汰優(yōu)先級越高。Redis支持8種不同策略來選擇要刪除的key:noeviction:不淘汰任何key但是內(nèi)存滿時不允許寫入新數(shù)據(jù)默認就是這種策略。volatile-ttl:對設(shè)置了TTL的key比較key的剩余TTL值TTL越小越先被淘汰allkeys-random:對全體key隨機進行淘汰。volatile-random:對設(shè)置了TTL的key隨機進行淘汰。allkeys-Iru:對全體key基于LRU算法進行淘汰volatile-Iru:對設(shè)置了TTL的key基于LRU算法進行淘汰allkeys-Ifu:對全體key基于LFU算法進行淘汰volatile-Ifu:對設(shè)置了TTL的key基于LFU算法進行淘汰使用建議1.優(yōu)先使用allkeys-Iru策略。充分利用LRU算法的優(yōu)勢把最近最常訪問的數(shù)據(jù)留在緩存中。如果業(yè)務(wù)有明顯的冷熱數(shù)據(jù)區(qū)分建議使用。2.如果業(yè)務(wù)中數(shù)據(jù)訪問頻率差別不大沒有明顯冷熱數(shù)據(jù)區(qū)分建議使用allkeys-random隨機選擇淘汰。3.如果業(yè)務(wù)中有置頂?shù)男枨罂梢允褂胿olatile-Iru策略同時置頂數(shù)據(jù)不設(shè)置過期時間這些數(shù)據(jù)就一直不被刪除會淘汰其他設(shè)置過期時間的數(shù)據(jù)。4.如果業(yè)務(wù)中有短時高頻訪問的數(shù)據(jù)可以使用allkeys-Ifu或volatile-Ifu策略。面試問題面試官:Redis的數(shù)據(jù)淘汰策略有哪些?候選人:這個在redis中提供了很多種默認是noeviction不刪除任何數(shù)據(jù)內(nèi)部不足直接報錯是可以在redis的配置文件中進行設(shè)置的里面有兩個非常重要的概念一個是LRU另外一個是LFULRU的意思就是最少最近使用用當前時間減去最后一次訪問時間這個值越大則淘汰優(yōu)先級越高。LFU的意思是最少頻率使用。會統(tǒng)計每個key的訪問頻率值越小淘汰優(yōu)先級越高我們在項目設(shè)置的是allkeys-Iru挑選最近最少使用的數(shù)據(jù)淘汰把一些經(jīng)常訪問的key留在redis中面試官:數(shù)據(jù)庫有1000萬數(shù)據(jù),Redis只能緩存20w數(shù)據(jù),如何保證Redis中的數(shù)據(jù)都是熱點數(shù)據(jù)?候選人:可以使用alkeys-Iru(挑選最近最少使用的數(shù)據(jù)淘汰)淘汰策略那留下來的都是經(jīng)常訪問的熱點數(shù)據(jù)面試官:Redis的內(nèi)存用完了會發(fā)生什么?主要看數(shù)據(jù)淘汰策略是什么?如果是默認的配置(noeviction)會直接報錯