(聲明:本文部分內(nèi)容摘自網(wǎng)絡(luò)優(yōu)秀文章,版權(quán)歸原作者所有)
一腹忽、緩存方式
1 進(jìn)程內(nèi)緩存
直接在jvm虛擬機(jī)中緩存(堆、直接內(nèi)存砚作、磁盤3級(jí)緩存)窘奏,速度快,效率高葫录;但是緩存共享麻煩着裹。
2 獨(dú)立緩存服務(wù)
redis、memcache均為緩存服務(wù)米同。
3 分布式緩存
指在每個(gè)程序中都有一個(gè)相同的緩存,同步更新有延時(shí)的骇扇。如ehcache集群,緩存共享復(fù)雜面粮,維護(hù)不方便少孝,所以不常用。
二熬苍、緩存的訪問(wèn)模式
使用緩存時(shí)有幾種常見(jiàn)的訪問(wèn)模式:
1 預(yù)留緩存(Cache-Aside)
應(yīng)用程序 在訪問(wèn)數(shù)據(jù)庫(kù)之前必須要先訪問(wèn)緩存稍走,如果緩存中包含了該數(shù)據(jù)則直接返回,不用再經(jīng)過(guò)數(shù)據(jù)庫(kù)柴底,否則應(yīng)用程序必須要從先數(shù)據(jù)庫(kù)中取回?cái)?shù)據(jù)婿脸,存儲(chǔ)在緩存中并且將數(shù)據(jù)返回,當(dāng)有數(shù)據(jù)要寫入的時(shí)候柄驻,緩存內(nèi)容必須要和數(shù)據(jù)庫(kù)內(nèi)容保持一致狐树。
這種方式是將數(shù)據(jù)庫(kù)與緩存通過(guò)客戶端應(yīng)用程序主動(dòng)管理來(lái)進(jìn)行同步,這不是很好的使用方式凿歼。
2 Read-Through模式
相比上面的由客戶端應(yīng)用程序來(lái)管理數(shù)據(jù)庫(kù)和緩存同步的方式褪迟,這種模式緩存會(huì)配有一個(gè)緩存中間件冗恨,該中間件來(lái)負(fù)責(zé)數(shù)據(jù)庫(kù)數(shù)據(jù)和緩存之間的同步問(wèn)題答憔。當(dāng)我們應(yīng)用要獲取緩存數(shù)據(jù)時(shí),這個(gè)緩存中間件要確認(rèn)緩存中是否有該數(shù)據(jù)掀抹,如果沒(méi)有虐拓,從數(shù)據(jù)庫(kù)加載,然后放入緩存傲武,下次以后再訪問(wèn)就可以直接從緩存中獲得蓉驹。(緩存和數(shù)據(jù)庫(kù) 通常是一對(duì)一的關(guān)系城榛,中間件需要維護(hù)這種業(yè)務(wù)關(guān)系)
3 Write-Through模式
這種模式就是緩存能夠感知數(shù)據(jù)的變化。也就是說(shuō)在更新數(shù)據(jù)庫(kù)的同時(shí)也要更新緩存态兴,該模式其實(shí)也是弱一致性狠持,當(dāng)數(shù)據(jù)庫(kù)更新數(shù)據(jù)失敗的時(shí)候,緩存不能繼續(xù)更新數(shù)據(jù)瞻润,要保持?jǐn)?shù)據(jù)庫(kù)和緩存的最終一致性喘垂。
4 Write-behind模式
該模式是以緩存為優(yōu)先,將緩存更新的數(shù)據(jù)存放隊(duì)列中绍撞,然后數(shù)據(jù)庫(kù)定時(shí)批量從隊(duì)列中取出數(shù)據(jù)更新數(shù)據(jù)庫(kù)正勒。(Cassandra是否是該中模式,待確認(rèn))
三、緩存問(wèn)題及解決方案
1 緩存穿透
1.1傻铣、 場(chǎng)景
應(yīng)用程序 通常先檢查緩存中是否存在章贞,如果存在直接返回緩存內(nèi)容,如果不存在就直接查詢數(shù)據(jù)庫(kù)非洲,然后再緩存查詢結(jié)果返回鸭限。這個(gè)時(shí)候如果查詢的某一個(gè)數(shù)據(jù)在緩存中一直不存在(1 數(shù)據(jù)庫(kù)中也不存在,如利用不存在的key頻繁攻擊怪蔑;2 未加載至緩存或者緩存失效)里覆,就會(huì)造成每一次請(qǐng)求都查詢DB,這樣緩存就失去了意義缆瓣,在流量大時(shí)喧枷,可能DB就掛掉了。
1.2弓坞、解決方案
可以在封裝的緩存SET和GET部分增加個(gè)步驟隧甚,如果查詢一個(gè)KEY不存在,就以這個(gè)KEY為前綴設(shè)定一個(gè)標(biāo)識(shí)KEY渡冻;以后再查詢?cè)揔EY的時(shí)候戚扳,先查詢標(biāo)識(shí)KEY,如果標(biāo)識(shí)KEY存在族吻,就返回一個(gè)協(xié)定好的非FALSH或者NULL值帽借,然后應(yīng)用程序 做相應(yīng)的處理,這樣緩存層就不會(huì)被穿透超歌。當(dāng)然這個(gè)KEY的失效時(shí)間不能太長(zhǎng)砍艾。
2 緩存并發(fā)
2.1、 場(chǎng)景
有時(shí)候如果網(wǎng)站并發(fā)訪問(wèn)高巍举,一個(gè)緩存如果失效脆荷,可能出現(xiàn)多個(gè)進(jìn)程同時(shí)查詢DB,同時(shí)設(shè)置緩存的情況,如果并發(fā)確實(shí)很大蜓谋,這也可能造成DB壓力過(guò)大梦皮,還有緩存頻繁更新的問(wèn)題。
2.2桃焕、 解決方案
對(duì)緩存查詢加鎖剑肯,如果KEY不存在,就加鎖(如果是分布式观堂,需要加分布式鎖)退子,然后查DB入緩存,然后解鎖型将;其他進(jìn)程如果發(fā)現(xiàn)有鎖就等待寂祥,然后等解鎖后返回?cái)?shù)據(jù)或者進(jìn)入DB查詢。
3 緩存失效
3.1七兜、 場(chǎng)景
引起這個(gè)問(wèn)題的主要原因還是高并發(fā)的時(shí)候丸凭,平時(shí)我們?cè)O(shè)定一個(gè)緩存的過(guò)期時(shí)間時(shí),可能有一些會(huì)設(shè)置5分鐘啊腕铸,10分鐘這些惜犀;并發(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ò)重莉御。
3.2、 解決方案
將緩存失效時(shí)間分散開俗冻,比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值礁叔,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過(guò)期時(shí)間的重復(fù)率就會(huì)降低迄薄,就很難引發(fā)集體失效的事件琅关。
四、二級(jí)緩存
1 使用二級(jí)緩存好處
1.1 進(jìn)程內(nèi)緩存讥蔽,無(wú)需IO和序列化涣易,速度更快。適合小數(shù)量的熱點(diǎn)數(shù)據(jù)冶伞。
1.2 減少緩存數(shù)據(jù)的網(wǎng)絡(luò)傳輸開銷新症。
1.3 當(dāng)集中式緩存出現(xiàn)故障的時(shí)候;Ehcache等本地緩存依然能夠支撐應(yīng)用程序正常使用碰缔,增加了程序的健壯性账劲。
1.4 使用二級(jí)緩存策略可以在一定程度上阻止緩存穿透問(wèn)題戳护。
2 使用二級(jí)緩存金抡,注意點(diǎn)
2.1 堆內(nèi)緩存瀑焦,涉及GC。只能緩存少量熱點(diǎn)數(shù)據(jù)梗肝。
2.2 分布式環(huán)境中榛瓮,各個(gè)應(yīng)用中本地緩存的同步問(wèn)題。
3 二級(jí)緩存方案
3.1 結(jié)構(gòu)圖如下:

1巫击、 redis做共享緩存禀晓,ehcache做本地緩存。
2坝锰、 本地緩存的 熱點(diǎn)數(shù)據(jù)key 集合粹懒,定期放入 redis 共享緩存中。
3顷级、 程序重啟時(shí)凫乖,從共享緩存中獲取數(shù)據(jù)本地緩存。
3.2 實(shí)現(xiàn)集群環(huán)境中的本地緩存變更同步
(一)MQ廣播模式弓颈,實(shí)現(xiàn)分布式系統(tǒng)中的本地緩存同步
需消息持久化帽芽,以保證緩存程序宕機(jī)后,能接收到消息翔冀。
(二)基于zookeeper的watcher機(jī)制导街,
1)建立持久化節(jié)點(diǎn)/localCacheChange,本地緩存程序watch /localCacheChange節(jié)點(diǎn)的數(shù)據(jù)變更纤子。
2)當(dāng)緩存發(fā)生變化時(shí)搬瑰,設(shè)置/localCacheChange節(jié)點(diǎn)數(shù)據(jù)為變更數(shù)據(jù)。
3)本地緩存程序控硼,watch到/localCacheChange節(jié)點(diǎn)數(shù)據(jù)變更跌捆,將本地緩存更新。
(問(wèn)題:以上方案象颖,如果緩存程序宕機(jī)佩厚,無(wú)法watch到節(jié)點(diǎn)數(shù)據(jù)的變化。)