Redis:MySQL算老几?
前言:上一篇《MySQL:緩存算什么東西?》里挖了一個(gè)坑,也有很多人說沒看過癮,今天接著寫,把坑填上,不過得把視角換一下,讓Redis上臺(tái)發(fā)言。
我知道MySQL看我不順眼,不就是他的好基友Tomcat不怎么搭理他了嗎? 這能怪我? 誰(shuí)讓他那么慢?
張大胖把我Redis安排到這個(gè)系統(tǒng)中來,那就是為了提升系統(tǒng)的響應(yīng)速度,我把數(shù)據(jù)都暫時(shí)放到了內(nèi)存中,每當(dāng)Tomcat需要的時(shí)候直接拿走就是了,都不用聯(lián)系MySQL。只有我這里沒有數(shù)據(jù)的時(shí)候Tomcat才會(huì)給MySQL說一句:“哥們,把這個(gè)SQL執(zhí)行一下啊,把數(shù)據(jù)告訴我!”
MySQL不死心,不斷使壞,總想著把我給干掉,恢復(fù)他昔日的榮耀和地位。可歷史的車輪滾滾向前,想逆潮流而動(dòng),無(wú)異于螳臂擋車啊!
有時(shí)候我真想把我緩存中的數(shù)據(jù)刪除,讓高并發(fā)的訪問都?jí)旱剿抢锶?#xff0c; 累死他! 可一想到自己的職業(yè)道德,尤其是張大胖那可憐樣,還是忍了吧。
?
黑客攻擊?
這一天中午,Tomcat發(fā)現(xiàn)流量有些異常,之前大部分的數(shù)據(jù)我都可以處理,這一次大量的請(qǐng)求在我Redis這里竟然獲取不到數(shù)據(jù)! Tomcat被迫向MySQL求援:“哥們,這兒有一個(gè)SQL啊, 這兒還有一個(gè), 又來一個(gè)......”
MySQL剛開始非常高興,滿心歡喜地去執(zhí)行,可是他很快就發(fā)現(xiàn)事情不對(duì), 執(zhí)行完這些SQL,在數(shù)據(jù)庫(kù)中也查不到數(shù)據(jù)。他不滿地對(duì)Tomcat說:“兄弟,你這是在折騰我嗎? 你看看你這個(gè)SQL中where ID = xxxx, 這些ID在數(shù)據(jù)庫(kù)都不存在嘛。”
Tomcat頭也不抬:“又來一個(gè)SQL, 還有一個(gè)......”
讓我比較佩服的是, MySQL還是比較職業(yè)的,盡管有怨氣,他還是不折不扣地執(zhí)行,很快他就累到了。
整個(gè)系統(tǒng)慢如蝸牛,連正常的請(qǐng)求也處理不了。
張大胖趕緊介入,經(jīng)過一番調(diào)查,他發(fā)現(xiàn)很多請(qǐng)求故意去查詢那些一定不存在的數(shù)據(jù),緩存中肯定沒有,于是請(qǐng)求一定會(huì)發(fā)到MySQL去執(zhí)行,在流量大時(shí),MySQL就掛掉了。
換句話說:在黑客的精心算計(jì)之下,我這個(gè)緩存成了擺設(shè),緩存被穿透了!
?
張大胖把此事定性為黑客攻擊。
?
緩存空值
這一次,MySQL終于意識(shí)到了我的價(jià)值,他出了一個(gè)主意:“Redis同學(xué),你把那些不存在的key和對(duì)應(yīng)的空值也緩存下來不就行了?下次訪問,就直接返回一個(gè)null給這些黑客,別再來找我了。”
我一聽就知道這是個(gè)餿主意:“這些key在你那里都不存在,還讓我緩存,那不就是要浪費(fèi)我的空間嗎? 張大胖給我分配的空間是有限的啊。”
“你不是可以設(shè)定數(shù)據(jù)的有效期嘛,比如過3分鐘就過期,刪除它,空間不就騰出來了。”
“那在這三分鐘內(nèi),如果這個(gè)key對(duì)應(yīng)的數(shù)據(jù)真的被加入到了你MySQL當(dāng)中,那豈不就不一致了?!” 我問道。
MySQL說道:“如果發(fā)生這種情況,就可以想辦法清除掉緩存中的數(shù)據(jù),只是程序邏輯就變得復(fù)雜了......”
“退一步來說,假設(shè)我緩存了他們,那黑客完全可以換一些新的key來攻擊啊!緩存中還是沒有,還得去你那里查,這個(gè)辦法不妥!” ?我下了結(jié)論。
?
布隆過濾器
MySQL說:“如果能事先得知這個(gè)key是不是在數(shù)據(jù)庫(kù)存在就好了,可是想知道是否存在,那就得把所有的key都放到緩存中,Redis,你能受得了嗎?”
我當(dāng)然受不了。
Tomcat眼前一亮:“你們聽說過布隆過濾器沒有?”
我說:“當(dāng)然知道了,這是個(gè)神奇的數(shù)據(jù)結(jié)構(gòu),只需要極少的空間就可以判斷一個(gè)元素是不是在一個(gè)集合之內(nèi),這正好是我們所需要的場(chǎng)景啊:判斷key是否存在。”
(碼農(nóng)翻身注:布隆過濾器大家可以參考相關(guān)資料,這里不再展開。)
Tomcat說:“對(duì),比如我們可以把所有的用戶ID建立一個(gè)布隆過濾器,這樣當(dāng)那些黑客的請(qǐng)求過來以后,先用這個(gè)過濾器攔截一下,如果黑客要訪問的用戶ID不在這個(gè)過濾器中,我們就直接把他踢出去了。”
MySQL也是經(jīng)驗(yàn)豐富:“可是這個(gè)Bloom Filter有誤報(bào)啊,即使某個(gè)用戶ID不在集合中,他也可能報(bào)告說在集合中。這個(gè)時(shí)候Tomcat就認(rèn)為這是一個(gè)合法的用戶ID,就去Redis中查,不存在,然后到我這里查,還是不存在。”
我說:“哎呀,一定的誤報(bào)也是允許的,沒有完美的事情,總要付出代價(jià)不是?”
大家都表示同意。
?
數(shù)據(jù)失效
黑客的攻擊的威脅解除了,日子又恢復(fù)了平靜,MySQL意識(shí)到了我的價(jià)值,也不再嘮嘮叨叨了。
我這個(gè)緩存的容量是有限的,不可能無(wú)限制地增加,所以張大胖添加到緩存的數(shù)據(jù)有一個(gè)有效期,過了有效期,我就會(huì)把他刪除,騰出空間,讓別的數(shù)據(jù)使用。
如果是普通的緩存數(shù)據(jù)失效,那就罷了,大不了從數(shù)據(jù)庫(kù)中再去一次就是了。
可是這一次,有個(gè)超級(jí)熱門的數(shù)據(jù)失效了,Tomcat組成的集群中有無(wú)數(shù)的線程都問我要數(shù)據(jù),當(dāng)我告訴他們這個(gè)數(shù)據(jù)已經(jīng)失效以后,他們扭頭便轉(zhuǎn)向MySQL,瘋狂地發(fā)出SQL語(yǔ)句,問MySQL要數(shù)據(jù)。
MySQL傻眼了,這么多的線程,每個(gè)要發(fā)出的SQL都是相同的,可是又不得不執(zhí)行。
MySQL又一次累倒了,我想他再次體會(huì)到了我的重要性。
?
他對(duì)Tomcat說道:“兄弟,給我發(fā)這么多的一模一樣的SQL,你想累死我啊!?你就不能控制一下?只讓一個(gè)線程發(fā)查詢過來,讓其他的等待一下??那個(gè)線程取到數(shù)據(jù)以后,其他線程就可以從緩存取了!”
Tomcat覺得很有道理,可是現(xiàn)在系統(tǒng)中有多個(gè)Tomcat,每個(gè)都是平等的,怎么去選出那個(gè)唯一的線程呢?
如果是在同一個(gè)JVM中還好辦,輕輕松松用一把進(jìn)程內(nèi)的鎖搞定, 可是這分布式的Tomcat,每個(gè)都是一個(gè)JVM,每個(gè)都是一個(gè)進(jìn)程, 怎么搞?
我說:“這很簡(jiǎn)單,我Redis這里可以提供一個(gè)分布式的鎖,誰(shuí)獲得了這把鎖,誰(shuí)就可以訪問數(shù)據(jù)庫(kù)。”
MySQL佩服地說:“老弟真是不錯(cuò),我服了你了,以后你一定要盡可能的把流量都給擋住,別往我這里發(fā)了,實(shí)在是太可怕了!”
Tomcat補(bǔ)充到:“是啊,這Redis緩存太重要了!”
突然間他注意到了我還只有一臺(tái)機(jī)器: “你現(xiàn)在怎么還是單臺(tái)機(jī)器? 一個(gè)實(shí)例? 萬(wàn)一掛了怎么辦? 一定得像我一樣,搞集群,提高可用性啊!”
MySQL說:“啊? 這多嚇人,從今天開始,我將時(shí)時(shí)刻刻為你祈禱,上帝保佑,你千萬(wàn)別掛掉。”
與此同時(shí),張大胖開始著手Redis集群了......
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Redis:MySQL算老几?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL:缓存算什么东西?!
- 下一篇: NoSQL还是SQL?这一篇讲清楚