摘要:總結(jié)允許的緩存寫場景大部分情況,修改成本會高于增加一次,因此應(yīng)該淘汰緩存如果還在糾結(jié),總是淘汰緩存,問題也不大先操作數(shù)據(jù)庫,還是先操作緩存這里分了兩種觀點,的觀點沈老師的觀點。這里我覺得沈老師可能忽略了并發(fā)的問題,比如說以下情況一個寫請求
緩存誤用
緩存,是互聯(lián)網(wǎng)分層架構(gòu)中,非常重要的一個部分,通常用它來降低數(shù)據(jù)庫壓力,提升系統(tǒng)整體性能,縮短訪問時間。
有架構(gòu)師說“緩存是萬金油,哪里有問題,加個緩存,就能優(yōu)化”,緩存的濫用,可能會導(dǎo)致一些錯誤用法。
緩存,你真的用對了么?
誤用一:把緩存作為服務(wù)與服務(wù)之間傳遞數(shù)據(jù)的媒介
如上圖:
服務(wù)1和服務(wù)2約定好key和value,通過緩存?zhèn)鬟f數(shù)據(jù)
服務(wù)1將數(shù)據(jù)寫入緩存,服務(wù)2從緩存讀取數(shù)據(jù),達(dá)到兩個服務(wù)通信的目的
該方案存在的問題是:
1、數(shù)據(jù)管道,數(shù)據(jù)通知場景,MQ更加適合
(1)MQ是互聯(lián)網(wǎng)常見的邏輯解耦,物理解耦組件,支持1對1,1對多各種模式,非常成熟的數(shù)據(jù)通道,而cache反而會將service-A/B/C/D耦合在一起,大家要彼此協(xié)同約定key的格式,ip地址等
(2)MQ能夠支持push,而cache只能拉取,不實時,有時延
(3)MQ天然支持集群,支持高可用,而cache未必
(4)MQ能支持?jǐn)?shù)據(jù)落地,cache具備將數(shù)據(jù)存在內(nèi)存里,具有“易失”性,當(dāng)然,有些cache支持落地,但互聯(lián)網(wǎng)技術(shù)選型的原則是,讓專業(yè)的軟件干專業(yè)的事情:nginx做反向代理,db做固化,cache做緩存,mq做通道
2、多個服務(wù)關(guān)聯(lián)同一個緩存實例,會導(dǎo)致服務(wù)耦合
(1)大家要彼此協(xié)同約定key的格式,ip地址等,耦合
(2)約定好同一個key,可能會產(chǎn)生數(shù)據(jù)覆蓋,導(dǎo)致數(shù)據(jù)不一致
(3)不同服務(wù)業(yè)務(wù)模式,數(shù)據(jù)量,并發(fā)量不一樣,會因為一個cache相互影響,例如service-A數(shù)據(jù)量大,占用了cache的絕大部分內(nèi)存,會導(dǎo)致service-B的熱數(shù)據(jù)全部被擠出cache,導(dǎo)致cache失效;又例如service-A并發(fā)量高,占用了cache的絕大部分連接,會導(dǎo)致service-B拿不到cache的連接,從而服務(wù)異常
誤用二:使用緩存未考慮雪崩
常規(guī)的緩存玩法,如上圖:
服務(wù)先讀緩存,緩存命中則返回
緩存不命中,再讀數(shù)據(jù)庫
什么時候會產(chǎn)生雪崩?
答:如果緩存掛掉,所有的請求會壓到數(shù)據(jù)庫,如果未提前做容量預(yù)估,可能會把數(shù)據(jù)庫壓垮(在緩存恢復(fù)之前,數(shù)據(jù)庫可能一直都起不來),導(dǎo)致系統(tǒng)整體不可服務(wù)。
如何應(yīng)對潛在的雪崩?
答:提前做容量預(yù)估,如果緩存掛掉,數(shù)據(jù)庫仍能扛住,才能執(zhí)行上述方案。
否則,就要進(jìn)一步設(shè)計。
常見方案一:高可用緩存
如上圖:使用高可用緩存集群,一個緩存實例掛掉后,能夠自動做故障轉(zhuǎn)移。
常見方案二:緩存水平切分
如上圖:使用緩存水平切分(推薦使用一致性哈希算法進(jìn)行切分),一個緩存實例掛掉后,不至于所有的流量都壓到數(shù)據(jù)庫上。
誤用三:調(diào)用方緩存數(shù)據(jù)
如上圖:
服務(wù)提供方緩存,向調(diào)用方屏蔽數(shù)據(jù)獲取的復(fù)雜性(這個沒問題)
服務(wù)調(diào)用方,也緩存一份數(shù)據(jù),先讀自己的緩存,再決定是否調(diào)用服務(wù)(這個有問題)
該方案存在的問題是:
1、調(diào)用方需要關(guān)注數(shù)據(jù)獲取的復(fù)雜性(耦合問題)
2、更嚴(yán)重的,服務(wù)修改db里的數(shù)據(jù),淘汰了服務(wù)cache之后,難以通知調(diào)用方淘汰其cache里的數(shù)據(jù),從而導(dǎo)致數(shù)據(jù)不一致(帶入一致性問題)
3、有人說,服務(wù)可以通過MQ通知調(diào)用方淘汰數(shù)據(jù),額,難道下游的服務(wù)要依賴上游的調(diào)用方,分層架構(gòu)設(shè)計不是這么玩的(反向依賴問題)
誤用四:多服務(wù)共用緩存實例
如上圖:服務(wù)A和服務(wù)B共用一個緩存實例(不是通過這個緩存實例交互數(shù)據(jù))
該方案存在的問題是:
1、可能導(dǎo)致key沖突,彼此沖掉對方的數(shù)據(jù)
畫外音:可能需要服務(wù)A和服務(wù)B提前約定好了key,以確保不沖突,常見的約定方式是使用namespace:key的方式來做key。
2、不同服務(wù)對應(yīng)的數(shù)據(jù)量,吞吐量不一樣,共用一個實例容易導(dǎo)致一個服務(wù)把另一個服務(wù)的熱數(shù)據(jù)擠出去
3、共用一個實例,會導(dǎo)致服務(wù)之間的耦合,與微服務(wù)架構(gòu)的“數(shù)據(jù)庫,緩存私有”的設(shè)計原則是相悖的
建議的玩法是
如上圖:各個服務(wù)私有化自己的數(shù)據(jù)存儲,對上游屏蔽底層的復(fù)雜性。
總結(jié)
1、服務(wù)與服務(wù)之間不要通過緩存?zhèn)鬟f數(shù)據(jù)
2、如果緩存掛掉,可能導(dǎo)致雪崩,此時要做高可用緩存,或者水平切分
3、調(diào)用方不宜再多帶帶使用緩存存儲服務(wù)底層的數(shù)據(jù),容易出現(xiàn)數(shù)據(jù)不一致,以及反向依賴
4、不同服務(wù),緩存實例要做垂直拆分
緩存,究竟是淘汰,還是修改?KV緩存都緩存了一些什么數(shù)據(jù)?
答:
(1)樸素類型的數(shù)據(jù),例如:int
(2)序列化后的對象,例如:User實體,本質(zhì)是binary
(3)文本數(shù)據(jù),例如:json或者h(yuǎn)tml
(4)...
淘汰緩存中的這些數(shù)據(jù),修改緩存中的這些數(shù)據(jù),有什么差別?
答:
(1)淘汰某個key,操作簡單,直接將key置為無效,但下一次該key的訪問會cache miss
(2)修改某個key的內(nèi)容,邏輯相對復(fù)雜,但下一次該key的訪問仍會cache hit
可以看到,差異僅僅在于一次cache miss。
緩存中的value數(shù)據(jù)一般是怎么修改的?
答:
(1)樸素類型的數(shù)據(jù),直接set修改后的值即可
(2)序列化后的對象:一般需要先get數(shù)據(jù),反序列化成對象,修改其中的成員,再序列化為binary,再set數(shù)據(jù)
(3)json或者h(yuǎn)tml數(shù)據(jù):一般也需要先get文本,parse成dom樹對象,修改相關(guān)元素,序列化為文本,再set數(shù)據(jù)
結(jié)論:對于對象類型,或者文本類型,修改緩存value的成本較高,一般選擇直接淘汰緩存。
問:對于樸素類型的數(shù)據(jù),究竟應(yīng)該修改緩存,還是淘汰緩存?
答:仍然視情況而定。
案例1:
假設(shè),緩存里存了某一個用戶uid=123的余額是money=100元,業(yè)務(wù)場景是,購買了一個商品pid=456。
分析:如果修改緩存,可能需要:
(1)去db查詢pid的價格是50元
(2)去db查詢活動的折扣是8折(商品實際價格是40元)
(3)去db查詢用戶的優(yōu)惠券是10元(用戶實際要支付30元)
(4)從cache查詢get用戶的余額是100元
(5)計算出剩余余額是100 - 30 = 70
(6)到cache設(shè)置set用戶的余額是70
為了避免一次cache miss,需要額外增加若干次db與cache的交互,得不償失。
結(jié)論:此時,應(yīng)該淘汰緩存,而不是修改緩存。
案例2:
假設(shè),緩存里存了某一個用戶uid=123的余額是money=100元,業(yè)務(wù)場景是,需要扣減30元。
分析:如果修改緩存,需要:
(1)從cache查詢get用戶的余額是100元
(2)計算出剩余余額是100 - 30 = 70
(3)到cache設(shè)置set用戶的余額是70
為了避免一次cache miss,需要額外增加若干次cache的交互,以及業(yè)務(wù)的計算,得不償失。
結(jié)論:此時,應(yīng)該淘汰緩存,而不是修改緩存。
案例3:
假設(shè),緩存里存了某一個用戶uid=123的余額是money=100元,業(yè)務(wù)場景是,余額要變?yōu)?0元。
分析:如果修改緩存,需要:
(1)到cache設(shè)置set用戶的余額是70
修改緩存成本很低。
結(jié)論:此時,可以選擇修改緩存。當(dāng)然,如果選擇淘汰緩存,只會額外增加一次cache miss,成本也不高。
總結(jié):
允許cache miss的KV緩存寫場景:
大部分情況,修改value成本會高于“增加一次cache miss”,因此應(yīng)該淘汰緩存
如果還在糾結(jié),總是淘汰緩存,問題也不大
這里分了兩種觀點,Cache Aside Pattern的觀點、沈老師的觀點。下面兩種觀點分析一下。
Cache Aside Pattern什么是“Cache Aside Pattern”?
答:旁路緩存方案的經(jīng)驗實踐,這個實踐又分讀實踐,寫實踐。
對于讀請求
先讀cache,再讀db
如果,cache hit,則直接返回數(shù)據(jù)
如果,cache miss,則訪問db,并將數(shù)據(jù)set回緩存
(1)先從cache中嘗試get數(shù)據(jù),結(jié)果miss了
(2)再從db中讀取數(shù)據(jù),從庫,讀寫分離
(3)最后把數(shù)據(jù)set回cache,方便下次讀命中
對于寫請求
先操作數(shù)據(jù)庫,再淘汰緩存(淘汰緩存,而不是更新緩存)
如上圖:
(1)第一步要操作數(shù)據(jù)庫,第二步操作緩存
(2)緩存,采用delete淘汰,而不是set更新
Cache Aside Pattern為什么建議淘汰緩存,而不是更新緩存?
答:如果更新緩存,在并發(fā)寫時,可能出現(xiàn)數(shù)據(jù)不一致。
如上圖所示,如果采用set緩存。
在1和2兩個并發(fā)寫發(fā)生時,由于無法保證時序,此時不管先操作緩存還是先操作數(shù)據(jù)庫,都可能出現(xiàn):
(1)請求1先操作數(shù)據(jù)庫,請求2后操作數(shù)據(jù)庫
(2)請求2先set了緩存,請求1后set了緩存
導(dǎo)致,數(shù)據(jù)庫與緩存之間的數(shù)據(jù)不一致。
所以,Cache Aside Pattern建議,delete緩存,而不是set緩存。
Cache Aside Pattern為什么建議先操作數(shù)據(jù)庫,再操作緩存?
答:如果先操作緩存,在讀寫并發(fā)時,可能出現(xiàn)數(shù)據(jù)不一致。
如上圖所示,如果先操作緩存。
在1和2并發(fā)讀寫發(fā)生時,由于無法保證時序,可能出現(xiàn):
(1)寫請求淘汰了緩存
(2)寫請求操作了數(shù)據(jù)庫(主從同步?jīng)]有完成)
(3)讀請求讀了緩存(cache miss)
(4)讀請求讀了從庫(讀了一個舊數(shù)據(jù))
(5)讀請求set回緩存(set了一個舊數(shù)據(jù))
(6)數(shù)據(jù)庫主從同步完成
導(dǎo)致,數(shù)據(jù)庫與緩存的數(shù)據(jù)不一致。
所以,Cache Aside Pattern建議,先操作數(shù)據(jù)庫,再操作緩存。
Cache Aside Pattern方案存在什么問題?
答:如果先操作數(shù)據(jù)庫,再淘汰緩存,在原子性被破壞時:
(1)修改數(shù)據(jù)庫成功了
(2)淘汰緩存失敗了
導(dǎo)致,數(shù)據(jù)庫與緩存的數(shù)據(jù)不一致。
個人見解:這里個人覺得可以使用重試的方法,在淘汰緩存的時候,如果失敗,則重試一定的次數(shù)。如果失敗一定次數(shù)還不行,那就是其他原因了。比如說redis故障、內(nèi)網(wǎng)出了問題。
關(guān)于這個問題,沈老師的解決方案是,使用先操作緩存(delete),再操作數(shù)據(jù)庫。假如刪除緩存成功,更新數(shù)據(jù)庫失敗了。緩存里沒有數(shù)據(jù),數(shù)據(jù)庫里是之前的數(shù)據(jù),數(shù)據(jù)沒有不一致,對業(yè)務(wù)無影響。只是下一次讀取,會多一次cache miss。這里我覺得沈老師可能忽略了并發(fā)的問題,比如說以下情況:
一個寫請求過來,刪除了緩存,準(zhǔn)備更新數(shù)據(jù)庫(還沒更新完成)。
然后一個讀請求過來,緩存未命中,從數(shù)據(jù)庫讀取舊數(shù)據(jù),再次放到緩存中,這時候,數(shù)據(jù)庫更新完成了。此時的情況是,緩存中是舊數(shù)據(jù),數(shù)據(jù)庫里面是新數(shù)據(jù),同樣存在數(shù)據(jù)不一致的問題。
如圖:
答:發(fā)生寫請求后(不管是先操作DB,還是先淘汰Cache),在主從數(shù)據(jù)庫同步完成之前,如果有讀請求,都可能發(fā)生讀Cache Miss,讀從庫把舊數(shù)據(jù)存入緩存的情況。此時怎么辦呢?
數(shù)據(jù)庫主從不一致
先回顧下,無緩存時,數(shù)據(jù)庫主從不一致問題。
如上圖,發(fā)生的場景是,寫后立刻讀:
(1)主庫一個寫請求(主從沒同步完成)
(2)從庫接著一個讀請求,讀到了舊數(shù)據(jù)
(3)最后,主從同步完成
導(dǎo)致的結(jié)果是:主動同步完成之前,會讀取到舊數(shù)據(jù)。
可以看到,主從不一致的影響時間很短,在主從同步完成后,就會讀到新數(shù)據(jù)。
二、緩存與數(shù)據(jù)庫不一致
再看,引入緩存后,緩存和數(shù)據(jù)庫不一致問題。
如上圖,發(fā)生的場景也是,寫后立刻讀:
(1+2)先一個寫請求,淘汰緩存,寫數(shù)據(jù)庫
(3+4+5)接著立刻一個讀請求,讀緩存,cache miss,讀從庫,寫緩存放入數(shù)據(jù),以便后續(xù)的讀能夠cache hit(主從同步?jīng)]有完成,緩存中放入了舊數(shù)據(jù))
(6)最后,主從同步完成
導(dǎo)致的結(jié)果是:舊數(shù)據(jù)放入緩存,即使主從同步完成,后續(xù)仍然會從緩存一直讀取到舊數(shù)據(jù)。
可以看到,加入緩存后,導(dǎo)致的不一致影響時間會很長,并且最終也不會達(dá)到一致。
三、問題分析
可以看到,這里提到的緩存與數(shù)據(jù)庫數(shù)據(jù)不一致,根本上是由數(shù)據(jù)庫主從不一致引起的。當(dāng)主庫上發(fā)生寫操作之后,從庫binlog同步的時間間隔內(nèi),讀請求,可能導(dǎo)致有舊數(shù)據(jù)入緩存。
思路:那能不能寫操作記錄下來,在主從時延的時間段內(nèi),讀取修改過的數(shù)據(jù)的話,強(qiáng)制讀主,并且更新緩存,這樣子緩存內(nèi)的數(shù)據(jù)就是最新。在主從時延過后,這部分?jǐn)?shù)據(jù)繼續(xù)讀從庫,從而繼續(xù)利用從庫提高讀取能力。
三、不一致解決方案
選擇性讀主
可以利用一個緩存記錄必須讀主的數(shù)據(jù)。
如上圖,當(dāng)寫請求發(fā)生時:
(1)寫主庫
(2)將哪個庫,哪個表,哪個主鍵三個信息拼裝一個key設(shè)置到cache里,這條記錄的超時時間,設(shè)置為“主從同步時延”
PS:key的格式為“db:table:PK”,假設(shè)主從延時為1s,這個key的cache超時時間也為1s。
如上圖,當(dāng)讀請求發(fā)生時:
這是要讀哪個庫,哪個表,哪個主鍵的數(shù)據(jù)呢,也將這三個信息拼裝一個key,到cache里去查詢,如果,
(1)cache里有這個key,說明1s內(nèi)剛發(fā)生過寫請求,數(shù)據(jù)庫主從同步可能還沒有完成,此時就應(yīng)該去主庫查詢。并且把主庫的數(shù)據(jù)set到緩存中,防止下一次cahce miss。
(2)cache里沒有這個key,說明最近沒有發(fā)生過寫請求,此時就可以去從庫查詢
以此,保證讀到的一定不是不一致的臟數(shù)據(jù)。
PS:如果系統(tǒng)可以接收短時間的不一致,建議建議定時更新緩存就可以了。避免系統(tǒng)過于復(fù)雜。
進(jìn)程內(nèi)緩存除了常見的redis/memcache等進(jìn)程外緩存服務(wù),緩存還有一種常見的玩法,進(jìn)程內(nèi)緩存。
什么是進(jìn)程內(nèi)緩存?
答:將一些數(shù)據(jù)緩存在站點,或者服務(wù)的進(jìn)程內(nèi),這就是進(jìn)程內(nèi)緩存。
進(jìn)程內(nèi)緩存的實現(xiàn)載體,最簡單的,可以是一個帶鎖的Map。又或者,可以使用第三方庫,例如leveldb、guave本地緩存
進(jìn)程內(nèi)緩存能存儲啥?
答:redis/memcache等進(jìn)程外緩存服務(wù)能存什么,進(jìn)程內(nèi)緩存就能存什么。
如上圖,可以存儲json數(shù)據(jù),可以存儲html頁面,可以存儲對象。
進(jìn)程內(nèi)緩存有什么好處?
答:與沒有緩存相比,進(jìn)程內(nèi)緩存的好處是,數(shù)據(jù)讀取不再需要訪問后端,例如數(shù)據(jù)庫。
如上圖,整個訪問流程要經(jīng)過1,2,3,4四個步驟。
如果引入進(jìn)程內(nèi)緩存,
如上圖,整個訪問流程只要經(jīng)過1,2兩個步驟。
與進(jìn)程外緩存相比(例如redis/memcache),進(jìn)程內(nèi)緩存省去了網(wǎng)絡(luò)開銷,所以一來節(jié)省了內(nèi)網(wǎng)帶寬,二來響應(yīng)時延會更低。
進(jìn)程內(nèi)緩存有什么缺點?
答:統(tǒng)一緩存服務(wù)雖然多一次網(wǎng)絡(luò)交互,但仍是統(tǒng)一存儲。
如上圖,站點和服務(wù)中的多個節(jié)點訪問統(tǒng)一的緩存服務(wù),數(shù)據(jù)統(tǒng)一存儲,容易保證數(shù)據(jù)的一致性。
而進(jìn)程內(nèi)緩存,如上圖,如果數(shù)據(jù)緩存在站點和服務(wù)的多個節(jié)點內(nèi),數(shù)據(jù)存了多份,一致性比較難保障。
如何保證進(jìn)程內(nèi)緩存的數(shù)據(jù)一致性?
答:保障進(jìn)程內(nèi)緩存一致性,有三種方案。
第一種方案
可以通過單節(jié)點通知其他節(jié)點。如上圖:寫請求發(fā)生在server1,在修改完自己內(nèi)存數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)之后,可以主動通知其他server節(jié)點,也修改內(nèi)存的數(shù)據(jù)。如下圖:
這種方案的缺點是:同一功能的一個集群的多個節(jié)點,相互耦合在一起,特別是節(jié)點較多時,網(wǎng)狀連接關(guān)系極其復(fù)雜。
第二種方案
可以通過MQ通知其他節(jié)點。如上圖,寫請求發(fā)生在server1,在修改完自己內(nèi)存數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)之后,給MQ發(fā)布數(shù)據(jù)變化通知,其他server節(jié)點訂閱MQ消息,也修改內(nèi)存數(shù)據(jù)。
這種方案雖然解除了節(jié)點之間的耦合,但引入了MQ,使得系統(tǒng)更加復(fù)雜。
前兩種方案,節(jié)點數(shù)量越多,數(shù)據(jù)冗余份數(shù)越多,數(shù)據(jù)同時更新的原子性越難保證,一致性也就越難保證。
第三種方案
為了避免耦合,降低復(fù)雜性,干脆放棄了“實時一致性”,每個節(jié)點啟動一個timer,定時從后端拉取最新的數(shù)據(jù),更新內(nèi)存緩存。在有節(jié)點更新后端數(shù)據(jù),而其他節(jié)點通過timer更新數(shù)據(jù)之間,會讀到臟數(shù)據(jù)。
為什么不能頻繁使用進(jìn)程內(nèi)緩存?
答:分層架構(gòu)設(shè)計,有一條準(zhǔn)則:站點層、服務(wù)層要做到無數(shù)據(jù)無狀態(tài),這樣才能任意的加節(jié)點水平擴(kuò)展,數(shù)據(jù)和狀態(tài)盡量存儲到后端的數(shù)據(jù)存儲服務(wù),例如數(shù)據(jù)庫服務(wù)或者緩存服務(wù)。
可以看到,站點與服務(wù)的進(jìn)程內(nèi)緩存,實際上違背了分層架構(gòu)設(shè)計的無狀態(tài)準(zhǔn)則,故一般不推薦使用。
什么時候可以使用進(jìn)程內(nèi)緩存?
答:以下情況,可以考慮使用進(jìn)程內(nèi)緩存。
情況一
只讀數(shù)據(jù),可以考慮在進(jìn)程啟動時加載到內(nèi)存。
畫外音:此時也可以把數(shù)據(jù)加載到redis / memcache,進(jìn)程外緩存服務(wù)也能解決這類問題。
情況二
極其高并發(fā)的,如果透傳后端壓力極大的場景,可以考慮使用進(jìn)程內(nèi)緩存。
例如,秒殺業(yè)務(wù),并發(fā)量極高,需要站點層擋住流量,可以使用內(nèi)存緩存。
情況三
一定程度上允許數(shù)據(jù)不一致業(yè)務(wù)。
例如,有一些計數(shù)場景,運營場景,頁面對數(shù)據(jù)一致性要求較低,可以考慮使用進(jìn)程內(nèi)頁面緩存。
再次強(qiáng)調(diào),進(jìn)程內(nèi)緩存的適用場景并不如redis/memcache廣泛,不要為了炫技而使用。更多的時候,還是老老實實使用redis/mc吧。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76531.html
摘要:總結(jié)允許的緩存寫場景大部分情況,修改成本會高于增加一次,因此應(yīng)該淘汰緩存如果還在糾結(jié),總是淘汰緩存,問題也不大先操作數(shù)據(jù)庫,還是先操作緩存這里分了兩種觀點,的觀點沈老師的觀點。這里我覺得沈老師可能忽略了并發(fā)的問題,比如說以下情況一個寫請求 緩存誤用 緩存,是互聯(lián)網(wǎng)分層架構(gòu)中,非常重要的一個部分,通常用它來降低數(shù)據(jù)庫壓力,提升系統(tǒng)整體性能,縮短訪問時間。 有架構(gòu)師說緩存是萬金油,哪里有問...
摘要:先更新數(shù)據(jù)庫,再更新緩存這套方案,大家是普遍反對的。采用這種同步淘汰策略,吞吐量降低怎么辦,那就將第二次刪除作為異步的。比如一個寫數(shù)據(jù)請求,然后寫入數(shù)據(jù)庫了,刪緩存失敗了,這會就出現(xiàn)不一致的情況了。 引言 為什么寫這篇文章? 首先,緩存由于其高并發(fā)和高性能的特性,已經(jīng)在項目中被廣泛使用。在讀取緩存方面,大家沒啥疑問,都是按照下圖的流程來進(jìn)行業(yè)務(wù)操作。 showImg(https://s...
摘要:本文會先闡述在并發(fā)編程中解決的問題多線程可見性,然后再詳細(xì)講解原則本身。所以與內(nèi)存之間的高速緩存就是導(dǎo)致線程可見性問題的一個原因。原則上面討論了中多線程共享變量的可見性問題及產(chǎn)生這種問題的原因。 Happens-Before是一個非常抽象的概念,然而它又是學(xué)習(xí)Java并發(fā)編程不可跨域的部分。本文會先闡述Happens-Before在并發(fā)編程中解決的問題——多線程可見性,然后再詳細(xì)講解H...
摘要:當(dāng)緩存空間滿了,同步失敗,網(wǎng)絡(luò)阻塞,緩存寫失敗等原因,會出現(xiàn)緩存服務(wù)器上并沒有這個。這種問題,以前有過實踐,修改數(shù)據(jù)庫成功,而修改緩存失敗的情況,最主要就是緩存服務(wù)器掛了。而緩存服務(wù)器掛了,請求首先自然也就無法到達(dá),從而直接訪問到數(shù)據(jù)庫。 原文摘自: 緩存穿透、并發(fā)和失效,來自一線架構(gòu)師的解決方案https://community.qingcloud.com/topic/463 在我們...
閱讀 2228·2021-09-30 09:47
閱讀 990·2021-08-27 13:01
閱讀 2973·2019-08-30 15:54
閱讀 3699·2019-08-30 15:53
閱讀 839·2019-08-29 14:07
閱讀 727·2019-08-28 18:16
閱讀 815·2019-08-26 18:37
閱讀 1422·2019-08-26 13:27