什麼是緩存及其算法介紹記錄

什麼是緩存?

       緩存是“存貯數據(使用頻繁的數據)的臨時地方,因爲取原始數據的代價太大了,所以我可以取得快一些。”

  緩存可以認爲是數據的池,這些數據是從數據庫裏的真實數據複製出來的,並且爲了能別取回,被標上了標籤(鍵 ID)。


命中:

  當客戶發起一個請求(我們說他想要查看一個產品信息),我們的應用接受這個請求,並且如果是在第一次檢查緩存的時候,需要去數據庫讀取產品信息。

  如果在緩存中,一個條目通過一個標記被找到了,這個條目就會被使用、我們就叫它緩存命中。所以,命中率也就不難理解了。


Cache Miss:

  但是這裏需要注意兩點:

  1. 如果還有緩存的空間,那麼,沒有命中的對象會被存儲到緩存中來。

  2. 如果緩存慢了,而又沒有命中緩存,那麼就會按照某一種策略,把緩存中的舊對象踢出,而把新的對象加入緩存池。而這些策略統稱爲替代策略(緩存算法),這些策略會決定到底應該提出哪些對象。


存儲成本:

  當沒有命中時,我們會從數據庫取出數據,然後放入緩存。而把這個數據放入緩存所需要的時間和空間,就是存儲成本。


索引成本:

和存儲成本相仿。


失效:

當存在緩存中的數據需要更新時,就意味着緩存中的這個數據失效了。


替代策略:

當緩存沒有命中時,並且緩存容量已經滿了,就需要在緩存中踢出一個老的條目,加入一條新的條目,而到底應該踢出什麼條目,就由替代策略決定。


最優替代策略:

  最優的替代策略就是想把緩存中最沒用的條目給踢出去,但是未來是不能夠被預知的,所以這種策略是不可能實現的。但是有很多策略,都是朝着這個目前去努力。


緩存算法

  沒有人能說清哪種緩存算法優於其他的緩存算法


Least Frequently Used(LFU):

  大家好,我是 LFU,我會計算爲每個緩存對象計算他們被使用的頻率。我會把最不常用的緩存對象踢走。


Least Recently User(LRU):

  我是 LRU 緩存算法,我把最近最少使用的緩存對象給踢走。

  我總是需要去了解在什麼時候,用了哪個緩存對象。如果有人想要了解我爲什麼總能把最近最少使用的對象踢掉,是非常困難的。

  瀏覽器就是使用了我(LRU)作爲緩存算法。新的對象會被放在緩存的頂部,當緩存達到了容量極限,我會把底部的對象踢走,而技巧就是:我會把最新被訪問的緩存對象,放到緩存池的頂部。

  所以,經常被讀取的緩存對象就會一直呆在緩存池中。有兩種方法可以實現我,array 或者是 linked list。

  我的速度很快,我也可以被數據訪問模式適配。我有一個大家庭,他們都可以完善我,甚至做的比我更好(我確實有時會嫉妒,但是沒關係)。我家庭的一些成員包括 LRU2 和 2Q,他們就是爲了完善 LRU 而存在的。


Least Recently Used 2(LRU2):

我是 Least Recently Used 2,有人叫我最近最少使用 twice,我更喜歡這個叫法。我會把被兩次訪問過的對象放入緩存池,當緩存池滿了之後,我會把有兩次最少使用的緩存對象踢走。因爲需要跟蹤對象2次,訪問負載就會隨着緩存池的增加而增加。如果把我用在大容量的緩存池中,就會有問題。另外,我還需要跟蹤那麼不在緩存的對象,因爲他們還沒有被第二次讀取。我比LRU好,而且是 adoptive to access 模式 。

Two Queues(2Q):

  我是 Two Queues;我把被訪問的數據放到 LRU 的緩存中,如果這個對象再一次被訪問,我就把他轉移到第二個、更大的 LRU 緩存。

  我踢走緩存對象是爲了保持第一個緩存池是第二個緩存池的1/3。當緩存的訪問負載是固定的時候,把 LRU 換成 LRU2,就比增加緩存的容量更好。這種機制使得我比 LRU2 更好,我也是 LRU 家族中的一員,而且是 adoptive to access 模式 。


Adaptive Replacement Cache(ARC):

  我是 ARC,有人說我是介於 LRU 和 LFU 之間,爲了提高效果,我是由2個 LRU 組成,第一個,也就是 L1,包含的條目是最近只被使用過一次的,而第二個 LRU,也就是 L2,包含的是最近被使用過兩次的條目。因此, L1 放的是新的對象,而 L2 放的是常用的對象。所以,別人纔會認爲我是介於 LRU 和 LFU 之間的,不過沒關係,我不介意。

  我被認爲是性能最好的緩存算法之一,能夠自調,並且是低負載的。我也保存着歷史對象,這樣,我就可以記住那些被移除的對象,同時,也讓我可以看到被移除的對象是否可以留下,取而代之的是踢走別的對象。我的記憶力很差,但是我很快,適用性也強。


Most Recently Used(MRU):

  我是 MRU,和 LRU 是對應的。我會移除最近最多被使用的對象,你一定會問我爲什麼。好吧,讓我告訴你,當一次訪問過來的時候,有些事情是無法預測的,並且在緩存系統中找出最少最近使用的對象是一項時間複雜度非常高的運算,這就是爲什麼我是最好的選擇。

  我是數據庫內存緩存中是多麼的常見!每當一次緩存記錄的使用,我會把它放到棧的頂端。當棧滿了的時候,你猜怎麼着?我會把棧頂的對象給換成新進來的對象!

First in First out(FIFO):

  我是先進先出,我是一個低負載的算法,並且對緩存對象的管理要求不高。我通過一個隊列去跟蹤所有的緩存對象,最近最常用的緩存對象放在後面,而更早的緩存對象放在前面,當緩存容量滿時,排在前面的緩存對象會被踢走,然後把新的緩存對象加進去。我很快,但是我並不適用。


Second Chance:

  大家好,我是 second chance,我是通過 FIFO 修改而來的,被大家叫做 second chance 緩存算法,我比 FIFO 好的地方是我改善了 FIFO 的成本。我是 FIFO 一樣也是在觀察隊列的前端,但是很FIFO的立刻踢出不同,我會檢查即將要被踢出的對象有沒有之前被使用過的標誌(1一個 bit 表示),沒有沒有被使用過,我就把他踢出;否則,我會把這個標誌位清除,然後把這個緩存對象當做新增緩存對象加入隊列。你可以想象就這就像一個環隊列。當我再一次在隊頭碰到這個對象時,由於他已經沒有這個標誌位了,所以我立刻就把他踢開了。我在速度上比 FIFO 快。


CLock:

  我是 Clock,一個更好的 FIFO,也比 second chance 更好。因爲我不會像 second chance 那樣把有標誌的緩存對象放到隊列的尾部,但是也可以達到 second chance 的效果。

  我持有一個裝有緩存對象的環形列表,頭指針指向列表中最老的緩存對象。當緩存 miss 發生並且沒有新的緩存空間時,我會問問指針指向的緩存對象的標誌位去決定我應該怎麼做。如果標誌是0,我會直接用新的緩存對象替代這個緩存對象;如果標誌位是1,我會把頭指針遞增,然後重複這個過程,知道新的緩存對象能夠被放入。我比 second chance 更快。


Simple time-based:

  我是 simple time-based 緩存算法,我通過絕對的時間週期去失效那些緩存對象。對於新增的對象,我會保存特定的時間。我很快,但是我並不適用。


Extended time-based expiration:

  我是 extended time-based expiration 緩存算法,我是通過相對時間去失效緩存對象的;對於新增的緩存對象,我會保存特定的時間,比如是每5分鐘,每天的12點。


Sliding time-based expiration:

  我是 sliding time-based expiration,與前面不同的是,被我管理的緩存對象的生命起點是在這個緩存的最後被訪問時間算起的。我很快,但是我也不太適用。

  其他的緩存算法還考慮到了下面幾點:

    成本:  如果緩存對象有不同的成本,應該把那些難以獲得的對象保存下來。

    容量:如果緩存對象有不同的大小,應該把那些大的緩存對象清除,這樣就可以讓更多的小緩存對象進來了。

    時間:一些緩存還保存着緩存的過期時間。電腦會失效他們,因爲他們已經過期了。

    根據緩存對象的大小而不管其他的緩存算法可能是有必要的。


Random Cache

  我是隨機緩存,我隨意的替換緩存實體,沒人敢抱怨。你可以說那個被替換的實體很倒黴。通過這些行爲,我隨意的去處緩存實體。我比 FIFO 機制好,在某些情況下,我甚至比 LRU 好,但是,通常LRU都會比我好。


摘自什麼是緩存及其算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章