一.無處不在的緩存

          緩存在計(jì)算機(jī)系統(tǒng)是無處不在,在CPU層面有L1-L3的Cache,在Linux中有TLB加速虛擬地址和物理地址的轉(zhuǎn)換,在應(yīng)用層有Redis等內(nèi)存數(shù)據(jù)庫緩存、在瀏覽器有本地緩存、手機(jī)有本地文件緩存等等。

          可見,緩存在計(jì)算機(jī)系統(tǒng)中有非常重要的地位,主要作用就是提高響應(yīng)速度、減少磁盤讀取等,本文主要討論在高并發(fā)系統(tǒng)中的緩存系統(tǒng)。一句話概括緩存系統(tǒng)在高并發(fā)系統(tǒng)中的地位的話,就是:

          如果高并發(fā)系統(tǒng)是烤羊肉串,那么緩存系統(tǒng)就是那一撮孜然......

          二.高并發(fā)系統(tǒng)中的緩存

          * 緩存系統(tǒng)的作用
          緩存系統(tǒng)在高并發(fā)系統(tǒng)的作用巨大,沒有緩存系統(tǒng)很難支撐C50K(或許這個(gè)值已經(jīng)非常樂觀了)以上的場景。
          基于機(jī)械磁盤或SSD的數(shù)據(jù)庫系統(tǒng),讀寫的速度遠(yuǎn)慢于內(nèi)存,因此單純磁盤介質(zhì)的數(shù)據(jù)庫無法支撐高并發(fā),你可以認(rèn)為緩存就是為了保護(hù)磁盤數(shù)據(jù)庫、是磁盤數(shù)據(jù)庫的屏障。

          * 緩存系統(tǒng)和數(shù)據(jù)庫系統(tǒng)的訪問


          以讀多寫少的場景為例(實(shí)際場景也是讀多寫少),看看請求是如何得到響應(yīng)的,簡單流程:請求到達(dá)之后,業(yè)務(wù)線程首先訪問緩存,如果緩存命中則返回,如果未命中則繼續(xù)請求磁盤數(shù)據(jù)庫系統(tǒng),并將結(jié)果回寫到緩存系統(tǒng)且增加老化時(shí)間,這樣在超時(shí)時(shí)間內(nèi)再有相同請求到達(dá)時(shí)則可以命中緩存。以上是高并發(fā)系統(tǒng)中緩存和磁盤數(shù)據(jù)庫系統(tǒng)、客戶端請求之間的交互過程,后續(xù)的問題分析,也是基于此過程展開的。

          三.緩存系統(tǒng)的三大問題
          網(wǎng)絡(luò)上對于緩存三大問題的文章很多,提到的三個(gè)問題主要是:

          * 緩存雪崩 Cache Avalanche
          * 緩存穿透 Cache Penetration
          * 緩存擊穿 Hotspot Invalid

          對于上面的三個(gè)名詞我一直分不清楚,腦海中并沒有清晰的區(qū)別,于是想到去谷歌看看歪果仁是怎么說的,然而英文表述就是上面的英文,基本上和漢語翻譯是一樣的,所以只能強(qiáng)記了。

          A.緩存雪崩問題


          所謂雪崩就是原來有所支撐的冰雪,某一瞬間失去依托,瞬間涌下來。這個(gè)場景讓我想起了2011年上映的柯南劇場版《沉默的十五分鐘》,柯南在北澤村水庫為了拯救村莊制造的雪崩:
          注:圖為柯南被雪崩所埋,黃金搶救期時(shí)毛利蘭在尋找他的鏡頭
          可見雪崩確實(shí)很可怕,回到高并發(fā)系統(tǒng),如果緩存系統(tǒng)故障,大量的請求無法從緩存完成數(shù)據(jù)請求,因此就全量洶涌沖向磁盤數(shù)據(jù)庫系統(tǒng),導(dǎo)致數(shù)據(jù)庫被打死,整個(gè)系統(tǒng)徹底崩潰。

          緩存雪崩解決方案


          從原因來看主要是緩存系統(tǒng)不夠高可用,因此提高緩存系統(tǒng)的穩(wěn)定性和可用性十分必要,對于使用Redis作為緩存的系統(tǒng)而言需要使用Sentinel哨兵機(jī)制、集群化、持久化等來提高緩存系統(tǒng)的HA。


          ?另一方面除了保證緩存系統(tǒng)的HA之外,服務(wù)本身也需要支持降級,可以使用奈飛的Hystrix來實(shí)現(xiàn)服務(wù)的熔斷、降級、限流來降低出現(xiàn)雪崩時(shí)的故障程度。說白了就是別讓服務(wù)徹底死掉就行,就像大雪封高速肯定徹底不能通行了,堵車就是慢一些至少可以走,如果還不清楚,回想一下每年你回鄉(xiāng)的車票是怎么從12306搶回來的。

          ?

          B.緩存穿透問題

          穿透形象一點(diǎn)就是:請求過來了 轉(zhuǎn)了一圈 一無所獲 就像穿過透明地帶一樣。


          在高并發(fā)系統(tǒng)中緩存穿透,其實(shí)是這樣的如果一個(gè)req需要請求的key在緩存中沒有,這時(shí)業(yè)務(wù)線程就會(huì)訪問磁盤數(shù)據(jù)庫系統(tǒng),然而磁盤數(shù)據(jù)庫也沒有這個(gè)key,無奈業(yè)務(wù)線程只能返回null,白白處理一圈。

          小概率事件在高并發(fā)系統(tǒng)幾乎要成為必然,也就是如果某時(shí)段有大量惡意的不存在的key的爆破請求,那么服務(wù)將一直處理這些根本不存在的請求,導(dǎo)致正常請求無法被處理,從而出現(xiàn)問題。
          舉個(gè)栗子:


          拉面館的服務(wù)員和廚師不允許拒絕已經(jīng)進(jìn)來的消費(fèi)者,但是拉面館的經(jīng)營范圍有限,此時(shí)惡意消費(fèi)者點(diǎn)了一只5斤的澳洲龍蝦,經(jīng)過服務(wù)員和廚師都無法響應(yīng)這個(gè)需求,因此被最終被拒絕,此時(shí)輪流來了1000個(gè)這樣的惡意消費(fèi)者,拉面館基本要歇菜了。

          緩存穿透解決方案

          高并發(fā)系統(tǒng)也是如此,有效甄別是否存在這個(gè)key再?zèng)Q定是否讀取很重要,常見的做法有:


          ?a.把不存在的key寫一下null,這樣再來就相當(dāng)于命中了,其實(shí)這種方法局限性很大,今天是5斤龍蝦,明天改成6斤的螃蟹,緩存系統(tǒng)和數(shù)據(jù)庫中存儲(chǔ)大量無用key本身是無意義的,所以一般不建議。
          ?b.另外一種思路,轉(zhuǎn)換為查找問題,類似于在海量數(shù)據(jù)中查找某個(gè)key是否存在,考慮空間復(fù)雜度和時(shí)間復(fù)雜度,一般選用布隆過濾器來實(shí)現(xiàn)。

          緩布隆過濾器簡介

          布隆過濾器是個(gè)好東西,在1970年由布隆提出的,它實(shí)際上是一個(gè)很長的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。

          布隆可以實(shí)現(xiàn)的系統(tǒng)包括:垃圾郵件識(shí)別、搜索蜘蛛爬蟲url去重等,主要借助K個(gè)哈希函數(shù)和一個(gè)超大的bit數(shù)組來降低哈希沖突本身帶來的誤判,從而提高識(shí)別準(zhǔn)確性。

          布隆過濾器也存在一定的誤判,假如判斷存在可能不一定存在,但是假如判斷不存在就一定不存在,因此剛好用在解決緩存穿透的key查找場景,事實(shí)上很多系統(tǒng)都是基于布隆過濾器來解決緩存穿透問題的。

          ?

          C.緩存擊穿問題


          緩存擊穿是這樣一種情況:由于緩存系統(tǒng)中的熱點(diǎn)數(shù)據(jù)都有過期時(shí)間,如果沒有過期時(shí)間就造成了主存和緩存的數(shù)據(jù)不一致,因此過期時(shí)間一般都不會(huì)太長,設(shè)想某時(shí)刻一批熱點(diǎn)數(shù)據(jù)同時(shí)在緩存系統(tǒng)中過期失效,那么這部分?jǐn)?shù)據(jù)就都將請求磁盤數(shù)據(jù)庫系統(tǒng)。

          從描述上來看有點(diǎn)像微小規(guī)模的雪崩,但是對數(shù)據(jù)庫的壓力就很小了,只不過會(huì)影響并發(fā)性能,然而在多線程場景中緩存擊穿卻是經(jīng)常發(fā)生的,相反緩存穿透和雪崩頻率不如緩存擊穿,因此
          研究擊穿的現(xiàn)實(shí)意義更大一些。

          緩存擊穿解決方案

          可以采用的方案大概有幾種:

          a. 在設(shè)置熱點(diǎn)數(shù)據(jù)過期時(shí)間時(shí)盡量分散,比如設(shè)置100ms的基礎(chǔ)值,在此基礎(chǔ)上正負(fù)浮動(dòng)10ms,從而降低相同時(shí)刻出現(xiàn)CacheMiss的key的數(shù)量。
          b.
          另外一種做法是多線程加鎖,其中第一個(gè)線程發(fā)現(xiàn)CacheMiss之后進(jìn)行加鎖,再從數(shù)據(jù)庫獲取內(nèi)容之后寫到緩存中,其他線程獲取鎖失敗則阻塞數(shù)ms之后再進(jìn)行緩存讀取,這樣可以降低訪問數(shù)據(jù)數(shù)據(jù)庫的線程數(shù),需要注意在單機(jī)和集群需要使用不同的鎖,集群環(huán)境使用分布式鎖來實(shí)現(xiàn),但是由于鎖的存在也會(huì)影響并發(fā)效率。
          c.還有一種辦法是使用類似于Redis的SETNX命令,這種貌似存在問題,存在一個(gè)gap間隙請求處于無法從緩存獲取數(shù)據(jù)也無法從主存獲取數(shù)據(jù)的未決狀態(tài)。
          d.
          最后一種方法是在業(yè)務(wù)層對使用的熱點(diǎn)數(shù)據(jù)查看是否即將過期,如果即將過期則去數(shù)據(jù)庫獲取最新數(shù)據(jù)進(jìn)行更新并延長該熱點(diǎn)key在緩存系統(tǒng)中的時(shí)間,從而避免后面的過期CacheMiss,相當(dāng)于把事情提前解決了。

          緩存擊穿的解決方法都有一定的權(quán)衡,實(shí)際中根據(jù)自己的需求來解決,不過緩存擊穿的影響一般來說并不會(huì)太大,或許在你的服務(wù)跑了很久之后你才意識(shí)到會(huì)有緩存擊穿問題。

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                国产这里只有精品 | 亚洲成人高清无码在线 | 午夜免费视频网站 | 国产精品入口日韩视频大尺度 | 日本添阴视频 |