表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
開始表演
“表哥,我被虐了。” 表弟哭喪著臉對我說道。
“怎么滴,連跪?哥帶你飛。”
“不是LOL,我這不秋招嘛,那個面試官逮著我問,把我都問蒙了。” 表弟一臉懵逼,懷疑人生。
“問啥了啊,我平時教你的唱跳 rap 都沒用上?” 我幸災樂禍的說道,這小子平時就跟我吹,什么天天考第一,進大廠跟玩兒一樣,這不傻了吧。
“一來就問我一堆緩存的問題,什么是緩存啊,什么讀寫策略,如何保證緩存高可用啊,緩存穿透怎么處理啊,巴拉巴拉一堆,我記不得了都,整得我腦瓜子疼,你說我一個還沒畢業的憨憨,至于嘛?” 表弟悶悶不樂,繼續說道:“哥,要不教教我?”
“現在知道自己是憨憨了?我都說了叫你改下簡歷,你丫的一堆精通我看著都懵逼,梁靜茹給你的勇氣?”
“對對對我是憨憨,憨中之憨。哥教教我吧。” 表弟一臉舔狗樣地看著我。
“哎,想喝奶茶了。這腦子啊突然就一片混沌,你剛說啥來著?”
表弟反應也是很快:“我現在就叫外賣,不,我直接騎我的小電驢去買,哥您稍等片刻,我去去就來。”
這小子轉身就要出門,我在背后喊住了他。
“老弟啊,別買奈雪的茶里面的芝芝芒芒啊,那太貴了,我怕我喝不慣。”
表弟的嘴角動了動,最后勉強擠出一個笑容說道:“多喝喝就習慣了,我這就去買。”
什么是緩存
“回來了啊,來來來坐坐坐,哥先來給你講講什么是緩存。” 拿著芝芝芒芒深吸了一口,真香啊!
首先這個緩存主要是為了協調訪問之間的速度差異而存在的一種東西,可以是一個硬件,也可以是一個數據結構。比如我們的內存就是因為磁盤訪問太慢了,用內存存儲一些磁盤上的數據,便于CPU的讀取。
當然再深入還有L1、L2等緩存,也是因為嫌內存慢而產生的。
這種呢是因為純粹的訪問速度慢,還有一種慢,表明看起來是訪問慢,實際上的訪問的成本高。
什么意思呢?例如一個復雜的計算,如果每次都去算一遍拿結果,就慢了,于是就用緩存把結果存起來,下次就直接拿結果不用重新算了。這就叫空間換時間。
在我們實際工程應用上緩存可以分為三大類:靜態緩存、分布式緩存、本地緩存。
靜態緩存常指的是前端靜態頁面,html 啊,js等等,常放在靜態服務器上,還能通過 CDN 來縮減響應的時間,提高用戶訪問速度。
分布式緩存常指的是利用 Redis 、Memcached 等分布式緩存中間件來存放一些較為常用的數據,多個應用共享緩存,不僅可以提高訪問速率,也算上在高并發下起到保護脆弱的數據庫作用,算是高并發利器了!
本地緩存常指的是應用在同一個進程中的緩存組件,交互之間不會有網絡開銷,當你的項目還用不上分布式緩存,就存一些簡單的變量時候可以用本地緩存來解決。最簡單的 HashMap 就能作為本地緩存,或者Ehcache、Guava Cache等。
“老弟???你口水怎么都留下來了??”
“啊?沒沒沒,只是我也想喝啊,這奶茶太貴了,我都沒舍得給我自己搞一杯”,表弟目不轉睛的盯著我手里的奶茶說道。
“做夢,趕緊的還問啥來著?” 我又深吸了一大口奶茶,真香!
“還有那啥緩存讀寫策略,我都不明白啥策略,不就去讀緩存,沒數據就去數據庫讀,讀完了寫到緩存中唄,有緩存直接返回就好了,更新數據就先更新數據庫,再更新緩存上的數據不就得了,這么簡單還跟我整啥策略,他咋不整個孫子兵法呢?” 表弟一臉不忿道。
“我給你整個愛情三十六計不?小年輕,沒經歷過社會的毒打,今兒我就帶你看看沒你想的那么簡單!” 撩了撩我所剩無幾的 “秀發”,戳了下我那厚重的眼鏡。我清了清嗓子:“聽好了!”
緩存讀寫策略
緩存讀寫策略其實是應對不同場景的。讀的策略你說的沒錯,基本上都是這么個套路,但是寫呢就比較講究了。主要是就有因為分布式緩存數據是共享的,并且緩存和數據庫屬于兩個獨立的組件,這么一來數據就容易出問題。
比如你說的先更新數據庫,再更新緩存,假如你現在賬上有 100 塊錢,你媽給你打了 100 塊,數據庫把你賬上的錢變成了 200,然后呢你爸這時候剛好也給你打了 100 塊,數據庫賬上此時變成了 300,你爸的那個請求把緩存更新成了 300,然后你媽的那個請求把緩存更新成了200,然后你賬上就變成了200了。
就是因為并發更新,寫入順序不一樣導致的。
直接更新緩存還有個問題,例如A請求準備取緩存中的值,此時的值是1,然后+1,此時B請求也打算這樣做,拿到的值也是1,這樣更新到緩存里面的值就變成2而不是3。
因此還是得靠咱們得到數據庫老大哥,它可以保證數據的正確。數據以它為準。這種策略叫cache aside 旁路緩存策略,也是最常見的策略。
讀策略:從緩存中讀數據。命中,則直接返回數據。不命中,則從數據庫中查,查到數據后,將數據寫入到緩存中,并且返回給用戶。
寫策略:先更新數據庫,然后刪除緩存(讓數據庫來保證數據正確,緩存就不更新,咱就做個搬運工,豈不美滋滋)。
“不對不對,先更新數據庫,再刪除緩存。假如有個A先讀緩存,但是此時緩存是沒數據,于是去數據庫讀數據,讀到了數據,然后此時有B來更新數據庫,然后刪除了緩存。此時A再把緩存寫回,這不就出問題了嗎?表哥,你行不行啊?奶茶退我!” 表弟不樂意了。
“表弟,有點東西啊!你說的沒錯。其實不論是先刪除再更新,還是先更新再刪除,只是后刪除出錯的概率比較低!因為你說的情況需要一個請求先讀緩存,然后需要等待另一個請求更新完數據庫再刪除緩存之后,再寫入緩存,這個讀緩存要早于數據庫寫并晚于數據庫更新完畢且刪除緩存幾率很低。”
“并且一般為了解決最終一致性問題都會設置過期時間,避免臟數據一直存在。所以這種很小很小概率的事件,加上一些補償措施還是可以容忍的。”
“行吧行吧,好像還挺有道理的,還有啥策略?”
“還有write through / read through,簡單的說就是應用只和緩存打交道,由緩存自身來和數據庫打交道。也就是說啥并發更新的咱不用管,write through就是寫數據的時候如果緩存有數據則直接寫緩存由緩存組件來同步數據到數據庫,如果緩存中沒數據可以選擇和有數據一樣的操作,或者直接寫數據庫。”
“read through 就是從緩存中讀,緩存中沒數據由緩存組件自己去數據庫加載。不過遺憾的是咱們常用分布式緩存都不支持這種,不過本地緩存例如 ?Guava cache 的 loading Cache 有點 read through 那味兒。”
“最后一個就是 Write back,這個策略的核心在于寫緩存的時候會把緩存標記為臟,然后當緩存需要再次被使用的時候才會刷到后端存儲中。當讀緩存如果命中直接返回,如果沒得話找干凈的地兒(數據塊)讀取數據寫入緩存,假設沒有干凈的地兒,就把臟的緩存塊刷到后端存儲,然后再寫入數據,標記不為臟。”
“發現沒 PageCache 就是這么個讀寫策略,也就是因為刷盤慢呀,所以臟緩存先存著。怎么樣老弟,學會了沒?” ?我又深吸了一口奶茶,發出了絲絲的聲音,滿足。
“學會了學會了,哥真棒!那還有緩存高可用呢?怎么說?”
“高啥高,今天就到這,這幾個策略你先回去好好學,這奶茶都沒了,口干了說不了不了,下次一定下次一定。”
“別啊表哥,這奶茶32一杯呢,這才哪到哪啊?”
“趕緊滴,今天已經說了很多干貨了,快一遍消化去”,我不耐煩地說道。
“就這?就這?真是有夠好笑呢?我要找姨去!” 表弟要是能打得過我,感覺他應該要沖上來了。
“行行行,改天一定和你說........唉唉唉,把拖鞋放下!快放下!反了你!!!”
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用命令之------tcpdump
- 下一篇: Arduino与NodeMCU——联网