摘要:當(dāng)緩存空間滿了,同步失敗,網(wǎng)絡(luò)阻塞,緩存寫失敗等原因,會(huì)出現(xiàn)緩存服務(wù)器上并沒(méi)有這個(gè)。這種問(wèn)題,以前有過(guò)實(shí)踐,修改數(shù)據(jù)庫(kù)成功,而修改緩存失敗的情況,最主要就是緩存服務(wù)器掛了。而緩存服務(wù)器掛了,請(qǐng)求首先自然也就無(wú)法到達(dá),從而直接訪問(wèn)到數(shù)據(jù)庫(kù)。
原文摘自:
緩存穿透、并發(fā)和失效,來(lái)自一線架構(gòu)師的解決方案
https://community.qingcloud.com/topic/463
在我們的實(shí)踐中,原文中有部分解決方案已經(jīng)過(guò)時(shí),在原文的基礎(chǔ)上,添加了幾個(gè)我們常用的方案。
http://www.4wei.cn/archives/1002621
我們?cè)谟镁彺娴臅r(shí)候,不管是Redis或者M(jìn)emcached,基本上會(huì)通用遇到以下三個(gè)問(wèn)題:
緩存穿透
緩存并發(fā)
緩存失效
同步、復(fù)制中斷
緩存穿透注:上面三個(gè)圖會(huì)有什么問(wèn)題呢?
我們?cè)陧?xiàng)目中使用緩存通常都是先檢查緩存中是否存在,如果存在直接返回緩存內(nèi)容,如果不存在就直接查詢數(shù)據(jù)庫(kù)然后再緩存查詢結(jié)果返回。
這個(gè)時(shí)候如果我們查詢的某一個(gè)數(shù)據(jù)在緩存中一直不存在,就會(huì)造成每一次請(qǐng)求都查詢DB,這樣緩存就失去了意義,在流量大時(shí),可能DB就掛掉了。
那這種問(wèn)題有什么好辦法解決呢?
要是有人利用不存在的key頻繁攻擊我們的應(yīng)用,這就是漏洞。有一個(gè)比較巧妙的作法是,可以將這個(gè)不存在的key預(yù)先設(shè)定一個(gè)值。比如,"key" , “&&”。
在返回這個(gè)&&值的時(shí)候,我們的應(yīng)用就可以認(rèn)為這是不存在的key,那我們的應(yīng)用就可以決定是否繼續(xù)等待繼續(xù)訪問(wèn),還是放棄掉這次操作。如果繼續(xù)等待訪問(wèn),過(guò)一個(gè)時(shí)間輪詢點(diǎn)后,再次請(qǐng)求這個(gè)key,如果取到的值不再是&&,則可以認(rèn)為這時(shí)候key有值了,從而避免了透?jìng)鞯綌?shù)據(jù)庫(kù),從而把大量的類似請(qǐng)求擋在了緩存之中。
你應(yīng)該注意,這里緩存未命中的原因,更值得我們關(guān)注。
當(dāng)緩存空間滿了,同步失敗,網(wǎng)絡(luò)阻塞,緩存寫失敗等原因,會(huì)出現(xiàn)緩存服務(wù)器上并沒(méi)有這個(gè)key。
或者因?yàn)橥街袛啵谥鲝募軜?gòu)中,寫到主卻未同步到從的悲劇,就會(huì)出現(xiàn)請(qǐng)求穿透到DB層的情況。
出現(xiàn)這樣的情況,一定不能直接將請(qǐng)求穿透到DB層,避免DB當(dāng)機(jī)影響其它業(yè)務(wù)。
我們的解決方案可以參考。
當(dāng)業(yè)務(wù)中請(qǐng)求量特別高,緩存未命中的情況,應(yīng)該在建立DB保護(hù)的基礎(chǔ)上,放棄一定比例的請(qǐng)求,直接返回空
可以隨機(jī)釋放一些請(qǐng)求到DB,控制好流量的話,能保證緩存重建且DB不受極端壓力
后端異步定時(shí)檢查緩存,主動(dòng)建立這些緩存
部分頁(yè)面可緩存永不過(guò)期,后端異步定時(shí)檢查緩存,主動(dòng)更新、重建緩存,后端失效也可實(shí)現(xiàn)業(yè)務(wù)降級(jí)
通過(guò)建立二級(jí)緩存,把之前成功獲取的緩存數(shù)據(jù)放到本機(jī)緩存,文件也好,共享內(nèi)存也好,接受一些過(guò)期數(shù)據(jù)
緩存并發(fā)有時(shí)候如果網(wǎng)站并發(fā)訪問(wèn)高,一個(gè)緩存如果失效,可能出現(xiàn)多個(gè)進(jìn)程同時(shí)查詢DB,同時(shí)設(shè)置緩存的情況,如果并發(fā)確實(shí)很大,這也可能造成DB壓力過(guò)大,還有緩存頻繁更新的問(wèn)題。
我現(xiàn)在的想法是對(duì)緩存查詢加鎖,如果KEY不存在,就加鎖,然后查DB入緩存,然后解鎖;其他進(jìn)程如果發(fā)現(xiàn)有鎖就等待,然后等解鎖后返回?cái)?shù)據(jù)或者進(jìn)入DB查詢。
這種情況和剛才說(shuō)的預(yù)先設(shè)定值問(wèn)題有些類似,只不過(guò)利用鎖的方式,會(huì)造成部分請(qǐng)求等待。
緩存失效引起這個(gè)問(wèn)題的主要原因還是高并發(fā)的時(shí)候,平時(shí)我們?cè)O(shè)定一個(gè)緩存的過(guò)期時(shí)間時(shí),可能有一些會(huì)設(shè)置1分鐘啊,5分鐘這些,并發(fā)很高時(shí)可能會(huì)出在某一個(gè)時(shí)間同時(shí)生成了很多的緩存,并且過(guò)期時(shí)間都一樣,這個(gè)時(shí)候就可能引發(fā)一當(dāng)過(guò)期時(shí)間到后,這些緩存同時(shí)失效,請(qǐng)求全部轉(zhuǎn)發(fā)到DB,DB可能會(huì)壓力過(guò)重。
那如何解決這些問(wèn)題呢?
其中的一個(gè)簡(jiǎn)單方案就時(shí)講緩存失效時(shí)間分散開(kāi),比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過(guò)期時(shí)間的重復(fù)率就會(huì)降低,就很難引發(fā)集體失效的事件。
我們討論的第二個(gè)問(wèn)題時(shí)針對(duì)同一個(gè)緩存,第三個(gè)問(wèn)題時(shí)針對(duì)很多緩存。
接下來(lái)我們將發(fā)表一些自己的緩存高可用實(shí)踐,如《基于云平臺(tái)的緩存集群高可用實(shí)踐》,歡迎關(guān)注。
總結(jié)
1、緩存穿透:查詢一個(gè)必然不存在的數(shù)據(jù)。比如文章表,查詢一個(gè)不存在的id,每次都會(huì)訪問(wèn)DB,如果有人惡意破壞,很可能直接對(duì)DB造成影響。
2、緩存失效:如果緩存集中在一段時(shí)間內(nèi)失效,DB的壓力凸顯。這個(gè)沒(méi)有完美解決辦法,但可以分析用戶行為,盡量讓失效時(shí)間點(diǎn)均勻分布。
當(dāng)發(fā)生大量的緩存穿透,例如對(duì)某個(gè)失效的緩存的大并發(fā)訪問(wèn)就造成了緩存雪崩。
精彩問(wèn)答
問(wèn)題:如何解決DB和緩存一致性問(wèn)題?
當(dāng)修改了數(shù)據(jù)庫(kù)后,有沒(méi)有及時(shí)修改緩存。這種問(wèn)題,以前有過(guò)實(shí)踐,修改數(shù)據(jù)庫(kù)成功,而修改緩存失敗的情況,最主要就是緩存服務(wù)器掛了。而因?yàn)榫W(wǎng)絡(luò)問(wèn)題引起的沒(méi)有及時(shí)更新,可以通過(guò)重試機(jī)制來(lái)解決。而緩存服務(wù)器掛了,請(qǐng)求首先自然也就無(wú)法到達(dá),從而直接訪問(wèn)到數(shù)據(jù)庫(kù)。那么我們?cè)谛薷臄?shù)據(jù)庫(kù)后,無(wú)法修改緩存,這時(shí)候可以將這條數(shù)據(jù)放到數(shù)據(jù)庫(kù)中,同時(shí)啟動(dòng)一個(gè)異步任務(wù)定時(shí)去檢測(cè)緩存服務(wù)器是否連接成功,一旦連接成功則從數(shù)據(jù)庫(kù)中按順序取出修改數(shù)據(jù),依次進(jìn)行緩存最新值的修改。
問(wèn)題:?jiǎn)栂戮彺娲┩改菈K!例如,一個(gè)用戶查詢文章,通過(guò)ID查詢,按照之前說(shuō)的,是將緩存的KEY預(yù)先設(shè)置一個(gè)值,,如果通過(guò)ID插過(guò)來(lái),發(fā)現(xiàn)是預(yù)先設(shè)定的一個(gè)值,比如說(shuō)是“&&”,那之后的繼續(xù)等待訪問(wèn)是什么意思,這個(gè)ID什么時(shí)候會(huì)真正被附上用戶所需要的值呢?
我剛說(shuō)的主要是咱們常用的后面配置,前臺(tái)獲取的場(chǎng)景。前臺(tái)無(wú)法獲取相應(yīng)的key,則等待,或者放棄。當(dāng)在后臺(tái)配置界面上配置了相關(guān)key和value之后,那么以前的key &&也自然會(huì)被替換掉。你說(shuō)的那種情況,自然也應(yīng)該會(huì)有一個(gè)進(jìn)程會(huì)在某一個(gè)時(shí)刻,在緩存中設(shè)置這個(gè)ID,再有新的請(qǐng)求到達(dá)的時(shí)候,就會(huì)獲取到最新的ID和value。
問(wèn)題:其實(shí)用Redis的話,那天看到一個(gè)不錯(cuò)的例子,雙key,有一個(gè)當(dāng)時(shí)生成的一個(gè)附屬key來(lái)標(biāo)識(shí)數(shù)據(jù)修改到期時(shí)間,然后快到的時(shí)候去重新加載數(shù)據(jù),如果覺(jué)得key多可以把結(jié)束時(shí)間放到主key中,附屬key起到鎖的功能。
這種方案,之前我們實(shí)踐過(guò)。這種方案會(huì)產(chǎn)生雙份數(shù)據(jù),而且需要同時(shí)控制附屬key與key之間的關(guān)系,操作上有一定復(fù)雜度。
問(wèn)題:多級(jí)緩存是什么概念呢?
多級(jí)緩存就像我今天之前給大家發(fā)的文章里面提到了,將Ehcache與Redis做二級(jí)緩存,就像我之前寫的文章 http://www.jianshu.com/p/2cd6ad416a5a 提到過(guò)的。但同樣會(huì)存在一致性問(wèn)題,如果我們需要強(qiáng)一致性的話,緩存與數(shù)據(jù)庫(kù)同步是會(huì)存在時(shí)間差的,所以我們?cè)诰唧w開(kāi)發(fā)的過(guò)程中,一定要根據(jù)場(chǎng)景來(lái)具體分析,二級(jí)緩存更多的解決是,緩存穿透與程序的健壯性,當(dāng)集中式緩存出現(xiàn)問(wèn)題的時(shí)候,我們的應(yīng)用能夠繼續(xù)運(yùn)行。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64905.html
摘要:當(dāng)緩存空間滿了,同步失敗,網(wǎng)絡(luò)阻塞,緩存寫失敗等原因,會(huì)出現(xiàn)緩存服務(wù)器上并沒(méi)有這個(gè)。這種問(wèn)題,以前有過(guò)實(shí)踐,修改數(shù)據(jù)庫(kù)成功,而修改緩存失敗的情況,最主要就是緩存服務(wù)器掛了。而緩存服務(wù)器掛了,請(qǐng)求首先自然也就無(wú)法到達(dá),從而直接訪問(wèn)到數(shù)據(jù)庫(kù)。 原文摘自: 緩存穿透、并發(fā)和失效,來(lái)自一線架構(gòu)師的解決方案https://community.qingcloud.com/topic/463 在我們...
摘要:當(dāng)緩存空間滿了,同步失敗,網(wǎng)絡(luò)阻塞,緩存寫失敗等原因,會(huì)出現(xiàn)緩存服務(wù)器上并沒(méi)有這個(gè)。這種問(wèn)題,以前有過(guò)實(shí)踐,修改數(shù)據(jù)庫(kù)成功,而修改緩存失敗的情況,最主要就是緩存服務(wù)器掛了。而緩存服務(wù)器掛了,請(qǐng)求首先自然也就無(wú)法到達(dá),從而直接訪問(wèn)到數(shù)據(jù)庫(kù)。 原文摘自: 緩存穿透、并發(fā)和失效,來(lái)自一線架構(gòu)師的解決方案https://community.qingcloud.com/topic/463 在我們...
摘要:方案二布隆過(guò)濾器攔截布隆過(guò)濾器介紹概念布隆過(guò)濾器英語(yǔ)是年由布隆提出的。這就是布隆過(guò)濾器的基本思想。防緩存穿透的布隆過(guò)濾器判斷是否為合法非法則不允許繼續(xù)查庫(kù)從緩存中獲取數(shù)據(jù)緩存為空從數(shù)據(jù)庫(kù)中獲取緩存空對(duì)象參考書(shū)籍開(kāi)發(fā)與運(yùn)維 上周在工作中遇到了一個(gè)問(wèn)題場(chǎng)景,即查詢商品的配件信息時(shí)(商品:配件為1:N的關(guān)系),如若商品并未配置配件信息,則查數(shù)據(jù)庫(kù)為空,且不會(huì)加入緩存,這就會(huì)導(dǎo)致,下次在查詢同...
閱讀 2179·2021-11-24 09:39
閱讀 2792·2021-07-29 13:49
閱讀 2327·2019-08-29 14:15
閱讀 2239·2019-08-29 12:40
閱讀 3318·2019-08-26 13:42
閱讀 638·2019-08-26 12:13
閱讀 2072·2019-08-26 11:41
閱讀 3351·2019-08-23 18:32