一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

最全面的緩存架構(gòu)設(shè)計(jì)(全是干貨)

 剩礦空錢 2018-06-05

最全面的緩存架構(gòu)設(shè)計(jì)(全是干貨)

1:緩存技術(shù)和框架的重要性

互聯(lián)網(wǎng)的一些高并發(fā),高性能的項(xiàng)目和系統(tǒng)中,緩存技術(shù)是起著功不可沒的作用。緩存不僅僅是key-value的簡(jiǎn)單存取,它在具體的業(yè)務(wù)場(chǎng)景中,還是很復(fù)雜的,需要很強(qiáng)的架構(gòu)設(shè)計(jì)能力。我曾經(jīng)就遇到過因?yàn)榫彺婕軜?gòu)設(shè)計(jì)不到位,導(dǎo)致了系統(tǒng)崩潰的案例。

2:緩存的技術(shù)方案分類

1)是做實(shí)時(shí)性比較高的那塊數(shù)據(jù),比如說庫存,銷量之類的這種數(shù)據(jù),我們采取的實(shí)時(shí)的緩存 數(shù)據(jù)庫雙寫的技術(shù)方案,雙寫一致性保障的方案。

2)是做實(shí)時(shí)性要求不高的數(shù)據(jù),比如說商品的基本信息,等等,我們采取的是三級(jí)緩存架構(gòu)的技術(shù)方案,就是說由一個(gè)專門的數(shù)據(jù)生產(chǎn)的服務(wù),去獲取整個(gè)商品詳情頁需要的各種數(shù)據(jù),經(jīng)過處理后,將數(shù)據(jù)放入各級(jí)緩存中。

3:高并發(fā)以及高可用的復(fù)雜系統(tǒng)中的緩存架構(gòu)都有哪些東西

1)在大型的緩存架構(gòu)中,redis是最最基礎(chǔ)的一層。高并發(fā),緩存架構(gòu)中除了redis,還有其他的組成部分,但是redis至關(guān)重要。

  • 如果你的數(shù)據(jù)量不大(10G以內(nèi)),單master就可以。redis持久化 備份方案 容災(zāi)方案 replication(主從 讀寫分離) sentinal(哨兵集群,3個(gè)節(jié)點(diǎn),高可用性)

  • 如果你的數(shù)據(jù)量很大(1T ),采用redis cluster。多master分布式存儲(chǔ)數(shù)據(jù),水平擴(kuò)容,自動(dòng)進(jìn)行master -> slave的主備切換。

2)最經(jīng)典的緩存 數(shù)據(jù)庫讀寫的模式,cache aside pattern。讀的時(shí)候,先讀緩存,緩存沒有的話,那么就讀數(shù)據(jù)庫。更新緩存分以下兩種方式:

  • 數(shù)據(jù)發(fā)生變化時(shí),先更新緩存,然后再更新數(shù)據(jù)庫。這種適用于緩存的值相對(duì)簡(jiǎn)單,和數(shù)據(jù)庫的值一一對(duì)應(yīng),這樣更新比較快。

  • 數(shù)據(jù)發(fā)生變化時(shí),先刪除緩存,然后再更新數(shù)據(jù)庫,讀數(shù)據(jù)的時(shí)候再設(shè)置緩存。這種適用于緩存的值比較復(fù)雜的場(chǎng)景。比如可能更新了某個(gè)表的一個(gè)字段,然后其對(duì)應(yīng)的緩存,是需要查詢另外兩個(gè)表的數(shù)據(jù),并進(jìn)行運(yùn)算,才能計(jì)算出緩存最新的值的。這樣更新緩存的代價(jià)是很高的。如果你頻繁修改一個(gè)緩存涉及的多個(gè)表,那么這個(gè)緩存會(huì)被頻繁的更新,頻繁的更新緩存代價(jià)很高。而且這個(gè)緩存的值如果不是被頻繁訪問,就得不償失了。

大部分情況下,建議適用刪除更新的方式。其實(shí)刪除緩存,而不是更新緩存,就是一個(gè)lazy計(jì)算的思想,不要每次都重新做復(fù)雜的計(jì)算,不管它會(huì)不會(huì)用到,而是讓它到需要被使用的時(shí)候再重新計(jì)算。

舉個(gè)例子,一個(gè)緩存涉及的表的字段,在1分鐘內(nèi)就修改了20次,或者是100次,那么緩存跟新20次,100次; 但是這個(gè)緩存在1分鐘內(nèi)就被讀取了1次,有大量的冷數(shù)據(jù)。28黃金法則,20%的數(shù)據(jù),占用了80%的訪問量。實(shí)際上,如果你只是刪除緩存的話,那么1分鐘內(nèi),這個(gè)緩存不過就重新計(jì)算一次而已,開銷大幅度降低。每次數(shù)據(jù)過來,就只是刪除緩存,然后修改數(shù)據(jù)庫,如果這個(gè)緩存,在1分鐘內(nèi)只是被訪問了1次,那么只有那1次,緩存是要被重新計(jì)算的。

3)數(shù)據(jù)庫與緩存雙寫不一致問題的解決方案

問題:并發(fā)請(qǐng)求的時(shí)候,數(shù)據(jù)發(fā)生了變更,先刪除了緩存,然后要去修改數(shù)據(jù)庫,此時(shí)還沒修改。另一個(gè)請(qǐng)求過來,去讀緩存,發(fā)現(xiàn)緩存空了,去查詢數(shù)據(jù)庫,查到了修改前的舊數(shù)據(jù),放到了緩存中。

方案:數(shù)據(jù)庫與緩存更新與讀取操作進(jìn)行異步串行化。(引入隊(duì)列)

更新數(shù)據(jù)的時(shí)候,將相應(yīng)操作發(fā)送到一個(gè)jvm內(nèi)部的隊(duì)列中。讀取數(shù)據(jù)的時(shí)候,如果發(fā)現(xiàn)數(shù)據(jù)不在緩存中,那么將重新讀取數(shù)據(jù)的操作也發(fā)送到同一個(gè)jvm內(nèi)部的隊(duì)列中。隊(duì)列消費(fèi)者串行拿到對(duì)應(yīng)的操作,然后一條一條的執(zhí)行。這樣的話,一個(gè)數(shù)據(jù)變更的操作,先執(zhí)行刪除緩存,然后再去更新數(shù)據(jù)庫,但是還沒完成更新。此時(shí)如果一個(gè)讀請(qǐng)求過來,讀到了空的緩存,那么可以先將緩存更新的請(qǐng)求發(fā)送到隊(duì)列中,此時(shí)會(huì)在隊(duì)列中積壓,然后同步等待緩存更新完成。

這里有兩個(gè)可以優(yōu)化的點(diǎn):

  • 一個(gè)隊(duì)列中,其實(shí)多個(gè)讀緩存,更新緩存的請(qǐng)求串在一起是沒意義的,而且如果讀同一緩存的大量請(qǐng)求到來時(shí),會(huì)依次進(jìn)入隊(duì)列等待,這樣會(huì)導(dǎo)致隊(duì)列最后一個(gè)的請(qǐng)求響應(yīng)時(shí)間超時(shí)。因此可以做過濾,如果發(fā)現(xiàn)隊(duì)列中已經(jīng)有一個(gè)讀緩存,更新緩存的請(qǐng)求了,那么就不用再放個(gè)新請(qǐng)求操作進(jìn)去了,直接等待前面的更新操作請(qǐng)求完成即可。如果請(qǐng)求還在等待時(shí)間范圍內(nèi),不斷輪詢發(fā)現(xiàn)可以取到值了,那么就直接返回; 如果請(qǐng)求等待的時(shí)間超過一定時(shí)長(zhǎng),那么這一次直接從數(shù)據(jù)庫中讀取當(dāng)前的舊值。

  • 如果請(qǐng)求量特別大的時(shí)候,可以用多個(gè)隊(duì)列,每個(gè)隊(duì)列對(duì)應(yīng)一個(gè)線程。每個(gè)請(qǐng)求來時(shí)可以根據(jù)請(qǐng)求的標(biāo)識(shí)id進(jìn)行hash路由進(jìn)入到不同的隊(duì)列。

最后,一定要做根據(jù)實(shí)際業(yè)務(wù)系統(tǒng)的運(yùn)行情況,去進(jìn)行一些壓力測(cè)試,和模擬線上環(huán)境,去看看最繁忙的時(shí)候,內(nèi)存隊(duì)列可能會(huì)擠壓多少更新操作,可能會(huì)導(dǎo)致最后一個(gè)更新操作對(duì)應(yīng)的讀請(qǐng)求,會(huì)hang多少時(shí)間,如果讀請(qǐng)求在200ms返回,如果你計(jì)算過后,哪怕是最繁忙的時(shí)候,積壓10個(gè)更新操作,最多等待200ms,那還可以的。如果一個(gè)內(nèi)存隊(duì)列可能積壓的更新操作特別多,那么你就要加機(jī)器,讓每個(gè)機(jī)器上部署的服務(wù)實(shí)例處理更少的數(shù)據(jù),那么每個(gè)內(nèi)存隊(duì)列中積壓的更新操作就會(huì)越少。其實(shí)根據(jù)之前的項(xiàng)目經(jīng)驗(yàn),一般來說數(shù)據(jù)的寫頻率是很低的,因此實(shí)際上正常來說,在隊(duì)列中積壓的更新操作應(yīng)該是很少的。

舉個(gè)例子:一秒就100個(gè)寫操作。單臺(tái)機(jī)器,20個(gè)內(nèi)存隊(duì)列,每個(gè)內(nèi)存隊(duì)列,可能就積壓5個(gè)寫操作,每個(gè)寫操作性能測(cè)試后,一般在20ms左右就完成,那么針對(duì)每個(gè)內(nèi)存隊(duì)列中的數(shù)據(jù)的讀請(qǐng)求,也就最多hang一會(huì)兒,200ms以內(nèi)肯定能返回了。如果把寫QPS擴(kuò)大10倍,但是經(jīng)過剛才的測(cè)算,就知道,單機(jī)支撐寫QPS幾百?zèng)]問題,那么就擴(kuò)容機(jī)器,擴(kuò)容10倍的機(jī)器,10臺(tái)機(jī)器,每個(gè)機(jī)器20個(gè)隊(duì)列,200個(gè)隊(duì)列。大部分的情況下,應(yīng)該是這樣的,大量的讀請(qǐng)求過來,都是直接走緩存取到數(shù)據(jù)的,少量情況下,可能遇到讀跟數(shù)據(jù)更新沖突的情況,如上所述,那么此時(shí)更新操作如果先入隊(duì)列,之后可能會(huì)瞬間來了對(duì)這個(gè)數(shù)據(jù)大量的讀請(qǐng)求,但是因?yàn)樽隽巳ブ氐膬?yōu)化,所以也就一個(gè)更新緩存的操作跟在它后面。

4)大型緩存全量更新問題的解決方案

問題:緩存數(shù)據(jù)很大時(shí),可能導(dǎo)致redis的吞吐量就會(huì)急劇下降,網(wǎng)絡(luò)耗費(fèi)的資源大。如果不維度化,就導(dǎo)致多個(gè)維度的數(shù)據(jù)混合在一個(gè)緩存value中。而且不同維度的數(shù)據(jù),可能更新的頻率都大不一樣。拿商品詳情頁來說,如果現(xiàn)在只是將1000個(gè)商品的分類批量調(diào)整了一下,但是如果商品分類的數(shù)據(jù)和商品本身的數(shù)據(jù)混雜在一起。那么可能導(dǎo)致需要將包括商品在內(nèi)的大緩存value取出來,進(jìn)行更新,再寫回去,就會(huì)很坑爹,耗費(fèi)大量的資源,redis壓力也很大

方案:緩存維度化。舉個(gè)例子:商品詳情頁分三個(gè)維度:商品維度,商品分類維度,商品店鋪維度。將每個(gè)維度的數(shù)據(jù)都存一份,比如說商品維度的數(shù)據(jù)存一份,商品分類的數(shù)據(jù)存一份,商品店鋪的數(shù)據(jù)存一份。那么在不同的維度數(shù)據(jù)更新的時(shí)候,只要去更新對(duì)應(yīng)的維度就可以了。大大減輕了redis的壓力。

5)通過多級(jí)緩存,達(dá)到高并發(fā)極致,同時(shí)給緩存架構(gòu)最后的安全保護(hù)層。具體可以參照上一篇文章【億級(jí)流量的商品詳情頁架構(gòu)分析】。

6)分布式并發(fā)緩存重建的沖突問題的解決方案

問題:假如數(shù)據(jù)在所有的緩存中都不存在了(LRU算法弄掉了),就需要重新查詢數(shù)據(jù)寫入緩存。對(duì)于分布式的重建緩存,在不同的機(jī)器上,不同的服務(wù)實(shí)例中,去做上面的事情,就會(huì)出現(xiàn)多個(gè)機(jī)器分布式重建去讀取相同的數(shù)據(jù),然后寫入緩存中。

方案:分布式鎖:如果你有多個(gè)機(jī)器在訪問同一個(gè)共享資源,那么這個(gè)時(shí)候,如果你需要加個(gè)鎖,讓多個(gè)分布式的機(jī)器在訪問共享資源的時(shí)候串行起來。分布式鎖當(dāng)然有很多種不同的實(shí)現(xiàn)方案,redis分布式鎖,zookeeper分布式鎖。

zookeeper分布式鎖的解決并發(fā)沖突的方案

  • (1)變更緩存重建以及空緩存請(qǐng)求重建,更新redis之前,都需要先獲取對(duì)應(yīng)商品id的分布式鎖

  • (2)拿到分布式鎖之后,需要根據(jù)時(shí)間版本去比較一下,如果自己的版本新于redis中的版本,那么就更新,否則就不更新

  • (3)如果拿不到分布式鎖,那么就等待,不斷輪詢等待,直到自己獲取到分布式的鎖

7)緩存冷啟動(dòng)的問題的解決方案

問題:新系統(tǒng)第一次上線,此時(shí)在緩存里可能是沒有數(shù)據(jù)的?;蛘遰edis緩存全盤崩潰了,數(shù)據(jù)也丟了。導(dǎo)致所有請(qǐng)求打到了mysql。導(dǎo)致mysql直接掛掉。

方案:緩存預(yù)熱。

  • 提前給redis中灌入部分?jǐn)?shù)據(jù),再提供服務(wù)

  • 肯定不可能將所有數(shù)據(jù)都寫入redis,因?yàn)閿?shù)據(jù)量太大了,第一耗費(fèi)的時(shí)間太長(zhǎng)了,第二根本redis容納不下所有的數(shù)據(jù),需要根據(jù)當(dāng)天的具體訪問情況,實(shí)時(shí)統(tǒng)計(jì)出訪問頻率較高的熱數(shù)據(jù),然后將訪問頻率較高的熱數(shù)據(jù)寫入redis中,肯定是熱數(shù)據(jù)也比較多,我們也得多個(gè)服務(wù)并行讀取數(shù)據(jù)去寫,并行的分布式的緩存預(yù)熱。

8)恐怖的緩存雪崩問題的解決方案

問題:緩存服務(wù)大量的資源全部耗費(fèi)在訪問redis和源服務(wù)無果,最后自己被拖死,無法提供服務(wù)。

方案:相對(duì)來說,考慮的比較完善的一套方案,分為事前,事中,事后三個(gè)層次去思考怎么來應(yīng)對(duì)緩存雪崩的場(chǎng)景。

  • 事前:高可用架構(gòu)。主從架構(gòu),操作主節(jié)點(diǎn),讀寫,數(shù)據(jù)同步到從節(jié)點(diǎn),一旦主節(jié)點(diǎn)掛掉,從節(jié)點(diǎn)跟上。

  • 事中:多級(jí)緩存。redis cluster已經(jīng)徹底崩潰了,緩存服務(wù)實(shí)例的ehcache的緩存還能起到作用。

  • 事后:redis數(shù)據(jù)可以恢復(fù),做了備份,redis數(shù)據(jù)備份和恢復(fù),redis重新啟動(dòng)起來。

9)緩存穿透問題的解決方案

問題:緩存中沒有這樣的數(shù)據(jù),數(shù)據(jù)庫中也沒有這樣的數(shù)據(jù)。由于緩存是不命中時(shí)被動(dòng)寫的,并且出于容錯(cuò)考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢,失去了緩存的意義。在流量大時(shí),可能DB就掛掉了,要是有人利用不存在的key頻繁攻擊我們的應(yīng)用,這就是漏洞。

方案:有很多種方法可以有效地解決緩存穿透問題,最常見的則是采用布隆過濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被 這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力。另外也有一個(gè)更為簡(jiǎn)單粗暴的方法(我們采用的就是這種),如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存,但它的過期時(shí)間會(huì)很短,最長(zhǎng)不超過五分鐘。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    亚洲一区二区三区四区| 国产av一二三区在线观看| 狠狠亚洲丁香综合久久| 精品国产一区二区欧美| 免费在线播放一区二区| 中文字日产幕码三区国产| 不卡视频在线一区二区三区| 国产成人精品午夜福利| 九九热九九热九九热九九热| 国产成人精品国产成人亚洲| 国产户外勾引精品露出一区| 我想看亚洲一级黄色录像| 国产精品一区二区视频成人| 免费性欧美重口味黄色| 国产成人精品在线播放| 粉嫩一区二区三区粉嫩视频| 久久福利视频视频一区二区| 麻豆印象传媒在线观看| 五月综合婷婷在线伊人| 大伊香蕉一区二区三区| 国产精品一区二区视频| 日韩一级一片内射视频4k| 亚洲精品一区三区三区| 欧美六区视频在线观看| 日本午夜乱色视频在线观看| 五月婷婷六月丁香亚洲| 亚洲综合日韩精品欧美综合区| 亚洲av在线视频一区| 亚洲第一区欧美日韩在线| 国产成人精品99在线观看| 亚洲国产精品久久网午夜| 欧美极品欧美精品欧美| 亚洲综合天堂一二三区| 日韩欧美综合中文字幕| 中文字幕熟女人妻视频| 国产精品一区二区成人在线| 国产毛片对白精品看片| 午夜福利国产精品不卡| 人妻内射在线二区一区| 亚洲夫妻性生活免费视频| 精品少妇人妻一区二区三区|