1.緩存雪崩
緩存雪崩是指緩存同一時(shí)間大面積的失效润讥,所以转锈,后面的請(qǐng)求都會(huì)落到數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉楚殿。
解決方案:
緩存數(shù)據(jù)的過期時(shí)間設(shè)置隨機(jī)撮慨,防止同一時(shí)間大量數(shù)據(jù)過期現(xiàn)象發(fā)生。
一般并發(fā)量不是特別多的時(shí)候脆粥,使用最多的解決方案是加鎖排隊(duì)砌溺。
給每一個(gè)緩存數(shù)據(jù)增加相應(yīng)的緩存標(biāo)記,記錄緩存的是否失效变隔,如果緩存標(biāo)記失效规伐,則更新數(shù)據(jù)緩存。
2.緩存穿透
緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù)匣缘,導(dǎo)致所有的請(qǐng)求都落到數(shù)據(jù)庫上猖闪,造成數(shù)據(jù)庫短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉
解決方案:
接口層增加校驗(yàn)鲜棠,如用戶鑒權(quán)校驗(yàn),id做基礎(chǔ)校驗(yàn)萧朝,id<=0的直接攔截岔留;
從緩存取不到的數(shù)據(jù),在數(shù)據(jù)庫中也沒有取到检柬,這時(shí)也可以將key-value對(duì)寫為key-null献联,緩存有效時(shí)間可以設(shè)置短點(diǎn),如30秒(設(shè)置太長會(huì)導(dǎo)致正常情況也沒法使用)何址。這樣可以防止攻擊用戶反復(fù)用同一個(gè)id暴力攻擊
采用布隆過濾器里逆,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的 bitmap 中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè) bitmap 攔截掉用爪,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力
3.緩存擊穿
緩存擊穿是指緩存中沒有但數(shù)據(jù)庫中有的數(shù)據(jù)(一般是緩存時(shí)間到期)原押,這時(shí)由于并發(fā)用戶特別多,同時(shí)讀緩存沒讀到數(shù)據(jù)偎血,又同時(shí)去數(shù)據(jù)庫去取數(shù)據(jù)诸衔,引起數(shù)據(jù)庫壓力瞬間增大,造成過大壓力颇玷。和緩存雪崩不同的是笨农,緩存擊穿指并發(fā)查同一條數(shù)據(jù),緩存雪崩是不同數(shù)據(jù)都過期了帖渠,很多數(shù)據(jù)都查不到從而查數(shù)據(jù)庫谒亦。
解決方案:
設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期。
加互斥鎖空郊,互斥鎖
4.緩存預(yù)熱
緩存預(yù)熱就是系統(tǒng)上線后份招,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶請(qǐng)求的時(shí)候狞甚,先查詢數(shù)據(jù)庫锁摔,然后再將數(shù)據(jù)緩存的問題!用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)哼审!
解決方案:
直接寫個(gè)緩存刷新頁面谐腰,上線時(shí)手工操作一下;
數(shù)據(jù)量不大棺蛛,可以在項(xiàng)目啟動(dòng)的時(shí)候自動(dòng)進(jìn)行加載怔蚌;
定時(shí)刷新緩存;
5.如何保證緩存與數(shù)據(jù)庫雙寫時(shí)的數(shù)據(jù)一致性
你只要用緩存旁赊,就可能會(huì)涉及到緩存與數(shù)據(jù)庫雙存儲(chǔ)雙寫桦踊,你只要是雙寫,就一定會(huì)有數(shù)據(jù)一致性的問題终畅,那么你如何解決一致性問題籍胯?
解決方案:
1.一般來說竟闪,就是如果你的系統(tǒng)不是嚴(yán)格要求緩存+數(shù)據(jù)庫必須一致性的話,緩存可以稍微的跟數(shù)據(jù)庫偶爾有不一致的情況杖狼,最好不要做這個(gè)方案炼蛤,讀請(qǐng)求和寫請(qǐng)求串行化,串到一個(gè)內(nèi)存隊(duì)列里去蝶涩,這樣就可以保證一定不會(huì)出現(xiàn)不一致的情況
2.串行化之后理朋,就會(huì)導(dǎo)致系統(tǒng)的吞吐量會(huì)大幅度的降低,用比正常情況下多幾倍的機(jī)器去支撐線上的一個(gè)請(qǐng)求绿聘。
3.還有一種方式就是可能會(huì)暫時(shí)產(chǎn)生不一致的情況嗽上,但是發(fā)生的幾率特別小,就是先更新數(shù)據(jù)庫熄攘,然后再刪除緩存兽愤。
6.Redis key指令
Redis里面有1億個(gè)key,其中有10w個(gè)key是以某個(gè)固定的已知的前綴開頭的挪圾,如果將它們?nèi)空页鰜恚?/p>
使用keys指令可以掃出指定模式的key列表浅萧。
如果這個(gè)redis正在給線上的業(yè)務(wù)提供服務(wù),那使用keys指令會(huì)有什么問題哲思?
redis關(guān)鍵的一個(gè)特性:redis的單線程的洼畅。keys指令會(huì)導(dǎo)致線程阻塞一段時(shí)間,線上服務(wù)會(huì)停頓也殖,直到指令執(zhí)行完畢土思,服務(wù)才能恢復(fù)务热。這個(gè)時(shí)候可以使用scan指令忆嗜,scan指令可以無阻塞的提取出指定模式的key列表,但是會(huì)有一定的重復(fù)概率崎岂,在客戶端做一次去重就可以了捆毫,但是整體所花費(fèi)的時(shí)間會(huì)比直接用keys指令長。
7.Redis異步隊(duì)列
使用list類型保存數(shù)據(jù)信息冲甘,rpush生產(chǎn)消息绩卤,lpop消費(fèi)消息,當(dāng)lpop沒有消息時(shí)江醇,可以sleep一段時(shí)間濒憋,然后再檢查有沒有信息,如果不想sleep的話陶夜,可以使用blpop, 在沒有信息的時(shí)候凛驮,會(huì)一直阻塞,直到信息的到來条辟。
redis可以通過pub/sub主題訂閱模式實(shí)現(xiàn)一個(gè)生產(chǎn)者黔夭,多個(gè)消費(fèi)者宏胯,當(dāng)然也存在一定的缺點(diǎn),當(dāng)消費(fèi)者下線時(shí)本姥,生產(chǎn)的消息會(huì)丟失肩袍。
8.Redis如何實(shí)現(xiàn)延時(shí)隊(duì)列
使用sortedset,使用時(shí)間戳做score, 消息內(nèi)容作為key,調(diào)用zadd來生產(chǎn)消息婚惫,
消費(fèi)者使用zrangbyscore獲取n秒之前的數(shù)據(jù)做輪詢處理氛赐。
9.Redis回收進(jìn)程
一個(gè)客戶端運(yùn)行了新的命令,添加了新的數(shù)據(jù)先舷。
Redis檢查內(nèi)存使用情況鹰祸,如果大于maxmemory的限制, 則根據(jù)設(shè)定好的策略進(jìn)行回收密浑。
一個(gè)新的命令被執(zhí)行蛙婴,等等。
所以我們不斷地穿越內(nèi)存限制的邊界尔破,通過不斷達(dá)到邊界然后不斷地回收回到邊界以下街图。
如果一個(gè)命令的結(jié)果導(dǎo)致大量?jī)?nèi)存被使用(例如很大的集合的交集保存到一個(gè)新的鍵),不用多久內(nèi)存限制就會(huì)被這個(gè)內(nèi)存使用量超越懒构。
10.redis是單線程的餐济,為什么6.0版本還要引入多線程呢?
為什么redis是設(shè)計(jì)為單線程
其一是因?yàn)閞edis的設(shè)計(jì)是io多路復(fù)用,即使連接網(wǎng)絡(luò)處理多io多路復(fù)用也可以在內(nèi)存處理中被忽略
其二多線程模型雖然快但他不可保證執(zhí)行順序,并帶來了并發(fā)讀寫的問題,
三是redis是基于內(nèi)存的,多線程的是為了充分利用cpu資源.但對(duì)redis來說除了進(jìn)行備份基本不會(huì)涉及到io操作數(shù)據(jù)讀寫,讀寫只發(fā)生在內(nèi)存中,處理速度很快,所以使用多線程技術(shù)會(huì)很雞肋
為什么要引入多線程
read/write系統(tǒng)調(diào)用在執(zhí)行期間占用了大量的cpu時(shí)間,將其網(wǎng)絡(luò)讀寫總成多線程的方式會(huì)有很大性能提升,在其最新的幾個(gè)版本中也加入了被其他線程異步處理的刪除操作,因?yàn)閞edis的del命令刪除元素特別大在短時(shí)間內(nèi)不可完成,所以引入多線程來進(jìn)行異步操作
11.redis集群是如何訪問的
客戶端是先往集群中的一個(gè)節(jié)點(diǎn)發(fā)胆剧,如果命中直接返回絮姆,如果不命中,會(huì)返回moved指令秩霍,然后告知key所在的是哪個(gè)節(jié)點(diǎn)篙悯。
12.redis 的hash擴(kuò)容過程
字典有兩個(gè)表,平時(shí)用一個(gè)铃绒,當(dāng)擴(kuò)容的時(shí)候在每次添加刪除的時(shí)候順帶移一個(gè)槽去新的表鸽照,
直到擴(kuò)容完畢。在查找的時(shí)候先去老的找颠悬,找不到去新的找矮燎。