1. 程式人生 > >MySQL:快取算什麼東西?!

MySQL:快取算什麼東西?!

十年前,我們還是一個企業內部的應用,使用者不多,資料也不多。

Tomcat一天也處理不了多少請求,閒得無聊的時候只能和我聊天,這是沒有辦法的事情,因為整個系統只有我們兩個:

沒錯,我就是大名鼎鼎的MySQL ,我和Tomcat位於不同的機器上,每次通訊都是一次網路的請求。

這樣的情況持續了三年,我們倆把話都快要說盡了的時候,人類終於送來了一個新傢伙:快取。

從外表看來,這個快取就是一個Map而已, 儲存的都是一些(key,value)這樣的東西。

從內部看,他還真是個Map,是那個叫做張大胖的人類寫的、一個執行緒安全的、可以設定過期時間的Map。

Tomcat和我都有點瞧不上他,覺得他實在是簡陋,甚至難以成為一個獨立的元件。

更讓Tomcat不爽的是,這個簡陋的傢伙竟然和自己一起,共享JVM程序。

慢慢地事情發生了變化,張大胖改變了程式邏輯:在之前,使用者的請求發到Tomcat這裡,如果需要訪問資料庫的資料, Tomcat直接就把SQL語句扔給我來執行。

現在, 先要到那個Map,不,是快取中查一下,看看有沒有相關資料,如果有,直接就返回了,根本不用和我打交道; 如果快取中沒有,那才發出SQL查詢,並且把快取也給填充上,這樣下次就不用訪問資料庫了。

Tomcat整天和快取打交道,聊得熱火朝天。 我觀察了幾天,終於明白這小子把我這個好基友給拋棄了。

Tomcat得意地對我說: “這快取和我在一個程序中,訪問起來速度快得很,立刻就能返回資料,哪裡像你MySQL,慢慢悠悠地執行半天?! ”

說完他又做了一個總結:程序內呼叫就是好啊。

其實吧,快取這小子的本質我比誰都清楚,我內部就有快取啊,就是為了避免頻繁地訪問硬碟, 大家利用的都是序的區域性性原理嘛,有什麼神祕的?!

我耐心蟄伏,等待機會,準備一舉把這個不知好歹的Map幹掉。

從程序內到程序外

過了幾個月,張大胖把系統的架構做了升級,為了應對高併發的訪問,他用一個nginx來搞負載均衡,分發使用者的請求,在後面搞了很多Tomcat和很多程序內的快取,我們的系統變成了這個樣子:

我一看就意識到我的機會來了:這快取之間很容易出現不一致啊。

比如: 使用者的請求在JVM 1 中進行處理,MySQL做了更新,JVM 1中相關的快取也做了更新或者被刪除, 可是JVM 2和JVM 3中快取的資料還是舊的啊。

不出我的所料,資料不一致的問題非常嚴重,使用者頻繁抱怨,快取這小子這下要完蛋了!

可是快取還想垂死掙扎,他說:”可以這樣嘛,如果一個JVM中的快取發生了變化,就通知其他JVM。”

可是通知總會有延遲,如果JVM 1還沒來得及通知JVM 2和JVM 3, 而使用者的請求已經在這兩臺機器上開始處理了,資料不一致還是存在。

特別是各個JVM之間需要來回互動,快取的更新需要你通知我,我通知你,麻煩得要死。

Tomcat出了一個餿主意:“別讓快取互相更新,讓快取定時從MySQL那裡更新!”

可是既然是定時更新,那快取中的資料和我這裡在某些時間段內還是會出現不一致。

除非資料的變化頻率極低,否則這幾乎是個無解的問題。

終於,張大胖如我所願, 把程序內快取給刪除了!

我整打算好好跟Tomcat敘敘舊(這麼多Tomcat啊!), 可是第二天他便弄來了一個新的傢伙:Redis,還是快取!

和之間那簡陋的Map相比,Redis可是強大得太多太多了,這個快取獨自霸佔了一臺機器,讓幾個Tomcat都可以共享訪問。

換句話說,快取從程序內搬到了程序外!

我對Redis說:“你小子也需要網路才能訪問了,和我差不多,有存在的必要嗎?”

Redis說:“當然有了,雖然都是網路訪問,但是我這裡所有的資料可都在記憶體中啊,訪問起來還是比你快。”

我承認,他說的是對的。

資料不一致

這天晚上,訪問量突然間特別的大,是平時的百倍,不,千倍。 據Redis說,這是張大胖那傢伙在搞壓力測試了。

壓力測試過後,一地雞毛。 一盤點就發現,Redis的資料和我的資料居然發現了不一致。

Redis傻眼了,這是怎麼回事?資料不一致,人類肯定以我MySQL的資料庫資料為準啊。

Tomcat提示Redis:“估計是高併發惹的禍,我們看看是怎麼更新資料的。”

Redis說:“簡單啊,先更新MySQL,然後更新我的資料。”

Tomcat說:“這是兩步操作,如果有兩個執行緒都在這麼幹,就出問題了! 比如MySQL的有個值是100,現線上程1想把它改成200, 執行緒2想把它改成300。”

Redis說:“看來這裡有個大漏洞啊,那怎麼辦?”

看著他們倆一籌莫展的樣子,我忍不住說道:“這還不簡單,當需要更新資料的時候,不要去更新快取,把快取中相關資料刪除就行了。”

Redis說:“你這是官報私仇吧,把資料從我這裡刪除了,下次使用者訪問的時候沒有,還得找你去要,對不對?”

我說:“是得找我要,但是能解決你的問題啊,兩個執行緒同時寫,不會出現資料庫和快取不一致啊。“

再說了,這其實不是我們能管的事情,咱們走著瞧,看看張大胖怎麼做。”

第二天,張大胖果然按照我說的邏輯修改了程式,還美名其曰:Cache Aside Pattern。

雖然我一直想把快取幹掉,可是,幾天後的經歷卻深刻地教育了我,快取還是必不可少的......

(唉,再挖個坑,主題估計你也想到了,就是快取穿透,擊穿,雪崩......)

(完)