1. 程式人生 > 程式設計 >對快取的一些簡單理解

對快取的一些簡單理解

1. 快取

提起 快取(cache),一般會想到cpu快取記憶體、記憶體快取。快取的本質是將部分的資料使用另一種存取速度更快的介質儲存,使系統更快的操作和響應。比如我們將部分的資料從磁碟放到記憶體中,直接操作記憶體的資料,這樣比從磁碟讀取資料要快上幾千幾萬倍。

既然高速的介質這麼好用,那為什麼不全部使用高速的介質呢,這裡直接用我們平常用的記憶體和磁碟做對比。

首先是價格差異巨大,目前市場價磁碟的價格大概在幾毛錢到幾塊錢1GB,而記憶體則需要幾十塊,甚至接近百塊1GB,兩者價格相差甚遠。全部使用記憶體來儲存資料,這口袋的錢頂不住啊。如果是cpu快取記憶體的造價跟磁碟比,那根本就是一個天一個地,而且CPU的快取是按MB單位來算的。英特爾i9-9900K處理器,快取16MB。

另一個很重要的原因是記憶體和磁碟的定位不一樣,記憶體是為了系統中能夠快速處理資料而設立的,它是即時的,並不具有永續性。開機通電之後記憶體才會起作用,一旦關機或者停電,資料就消失。這個資料不能永久儲存,這也不不是個辦法啊。而磁碟就不一樣,它雖然比較慢,但是資料是持久儲存的。

因為記憶體和磁碟的定位和特點,導致了它們各自有適合的使用場景,一般情況都是共同使用的。

2.使用快取的問題

這裡開始,只講記憶體和資料庫相關的東西,快取資料指的是儲存在記憶體中的副本資料。

平時我們編寫的伺服器中,因為記憶體大小的限制,會將常用的部分資料從資料庫快取到記憶體中,以此來加快伺服器的處理速度,增大服務的吞吐量。但是快取的使用並不是那麼簡單的,裡面含有很多坑,就等著你們來踩。

1. 資料一致性問題

使用快取最大的問題就是 資料不一致,在複雜的環境下,就更明顯,更難處理。

快取中的資料是資料庫的副本,如果是隻讀操作,那麼不會出現什麼問題,如果涉及到修改刪除等操作,就會存在資料不一致的問題。

舉個例子,一個使用者的名稱為nameA,此時他將名稱改為nameB,這時只操作快取或者資料庫,都會導致快取和資料庫資料不一致的問題。

那麼有人就說了,同時操作資料庫和快取不就可以了。思路是可以的,但是在併發條件下實現起來可是會出現問題的。

假設有兩個執行緒t1和t2,執行緒t1是修改操作,執行緒t2是讀取操作,執行緒t1先修改了資料庫,還沒來得及修改快取,此時執行緒t2讀取快取資料,那麼t2讀取的資料就不是最新的資料。

那麼這時候又有人說,加個鎖不就好了,可以用讀寫鎖,並且將鎖的粒度變小,以使用者id來作為鎖。在讀的操作所有執行緒都可以讀,但是寫操作時,只有一個執行緒可以操作,這樣既保證了資料一致性,又能滿足伺服器的高效能要求。

這是保證快取一致性的一個解決方案,但是並不是說這種方法就是完美的,也不一定適合其他應用場景。

在使用快取的時候,沒有最完美最通用的解決方案,只有最適合該場景的方案。

2. 命中率

快取畢竟只是部分資料的副本,在資料讀取的時候,首先會讀取快取中的資料,如果快取中沒有,就會去讀取資料庫的資料。如果說請求需要的資料快取中都沒有,這時候快取就沒有一點作用。在平時使用快取的時候,要評估哪些是常用的資料。

在提高命中率時,有一個較為通用的方法。當一個資料不在快取中時,此時執行緒會讀取資料庫,在讀取完後將該資料存入快取中,下次讀取的時候,直接讀取快取就行了。

3. 空間整理

記憶體的空間是比較小的,在使用的過程中快取的資料會越來越多,這時候就要進行資料清理了,將不常用,不必要的資料刪除。那麼用什麼方法找出不常用的資料呢,這裡列出比較常用的幾種快取清除策略。

FIFO ( first in first out)

先進先出策略,很簡單粗暴,在清除的時候,最開始存入的資料,將先被清除。這在某些特定場合下是可以的,但是一般情況下使用這個策略會顯得程式非常死板,不夠"智慧"。

LFU(less frequently used)

最少使用策略。指的是某些資料使用次數最少,將最先被清除。常用的做法是標記資料的命中次數,以此來判斷資料是否比較常用。

一般來說命中次數還得加上一個時間段的限制,記錄某個時間段內資料的命中次數,防止出現某些資料在一開始是常用,後來根本不會被使用到。

比如某個玩家一開始沉迷某艦娘,畢竟那麼大,哦不對,是那麼好玩,該玩家天天登入,理所當然的他個人資訊命中次數很高。但某一天他氪不動也肝不動,棄坑了,之後都沒登入過,那麼這個資料其實是不常用的了。

LRU (less recently used)

最近最少使用策略,標記資料最近一次使用的時間,在清除時,將釋放太久沒有被使用的資料。這個適用熱點資料場景中。

設定過期時間

新增快取的時候,就給該資料標記存活時間,超過了這個時間,該資料將被釋放。這個Redis中挺經常用到的。

隨機清理

如它的名稱一樣,清除的時候隨機清理。多麼粗暴的清理方法,可能會有程式會使用,的吧(我並不確定)。我的閱歷少,還沒見過使用這種方法的應用場景,如果有,麻煩告訴我一聲。

4. 快取雪崩

快取雪崩是指大量的請求直接透過了快取層請求資料庫(快取穿透),導致資料庫壓力過大,嚴重的會出現資料庫宕機。

快取穿透出現可能是由於原快取過期(或其他原因被清除),新的快取未存放,導致請求穿透到資料庫。也有可能是伺服器剛啟動,還來不及快取資料。

解決方案就是要避免大量快取在同一時刻過期,還有在伺服器啟動時,將請求量從小到大的引導到伺服器中。

3. 總結

為什麼要使用快取

因為它速度快,僅此而已

使用快取的問題

這裡就不總結了,看文章吧

其實還想寫一寫在具體的業務場景中快取的設計以及在設計時考慮和抉擇,不過寫起來挺長的,還是放到另一篇文章裡好了。

參考文章