NoSQL理論之 記憶體是新的硬碟,硬碟是新的磁帶

2022-03-19 05:07:31 字數 2697 閱讀 6698

**:

「記憶體是新的硬碟,硬碟是新的磁帶」此話出自圖靈獎得主jim gray。

我理解這句話的意思是,我們應該把隨機io都放到記憶體中去,而把像磁帶一樣的順序io留給硬碟(這裡不包括ssd)。

如果應用沒有達到一定的級別,可能我們看上面兩句話都會覺得太geek,然而在應用資料量日益龐大,動態內容比例日益增大的今天,再忽視這個基本準則將會是乙個災難。

今天我們談一下這一理論在nosql產品中的展現。

我們先看一下幾個傑出的nosql代表,cassandra,mongodb,redis。他們幾乎都使用了同一種儲存模式,就是將寫操作在內

存中進行,定時或按某一條件將記憶體中的資料直接寫到磁碟上。這樣做的好處是我們可以充分利用內存在隨機io上的優勢,而避免了直接寫磁碟帶來的隨機io瓶

頸:磁碟尋道時間。當然,壞處就是如果遭遇宕機等問題時,可能會丟失一些資料。

解決宕機丟資料的問題有兩個方法:

1.實時記錄操作日誌

這時通常的做法是當乙個寫操作到達,系統首先會往日誌檔案裡追加一條寫記錄,成功後再操作記憶體進行寫資料操作。而由於日誌檔案是不斷追加的,因此也就保證了不會有大量的隨機io產生。

2.quorum nrw

這一理論是基於集群式儲存的,其原理是如果集群有n個結點,那麼如果我們每次寫操作需要至少同步到w個結點才算成功,而每次讀操作只要從r個結

點讀資料就一定能保證其得到正確結果(如果某一結點有此資料,既成功,如果所有r個結點都無資料,則說明無此資料)。而nrw之間的關係必須滿足n

< r + w 。其實這一理論並不難理解,我們可以將這個不等式做一下移項:r > n – w

,我們有n個結點,寫的時候最少寫w個才算成功,也就是w個結點有這份資料,那麼n-w就是說可能沒有某乙份資料的最大結點數。最多可能有n-w個結點沒

有某一資料,那如果我們進行資料讀取操作時,讀到大於n-w個結點,那麼必然有乙個以上的結點是有這份資料的。所以要求r > n – w。

所以可能你已經想明白了,為了防止資料丟失,我們採用的實際是簡單的冗餘備份的方法。資料寫到多台機器會比寫單台機器的磁碟快嗎?對。相對於直接的磁碟操作,跨網路進行記憶體操作可以更快。其最簡單的例子就是改進的一致性hash,(關於一致性hash請看這裡):

上圖摘自amazon的dynamo文件,key的hash值位於a,b結點間的資料,並不是只存在b結點上,而是順著環的方向分別在c和d結點進行備份。當然這樣做的好處並不完全在於上面說的冗餘備份。

當然,很多時候是上面兩種解決方法同時使用以保證資料的高可用性。

當我們將記憶體當作硬碟來用的時候,我們必然會面臨容量問題。這也是我們上面說到的資料會定時flush到磁碟的原因,當記憶體中的資料已經超出可

用記憶體的大小,那麼我們就需要將其進行落地操作,對swap的過度使用是不符合我們初衷的,也是達不到高效隨機io的效果的。這裡也有兩種解決方案:

1.應用層swap

採用這種方法的有 tokyocabinet 和 redis

兩個產品。tokyocabinet主要是通過mmap提高io效率,而其mmap到的只有資料檔案頭部的一部分內容。一旦資料檔案大於其設定的最大

mmap長度(由引數xmsize控制),那剩下的部分就是純粹的低效磁碟操作了。於是它提供了一種類似於memcached的快取機制,通過引數

rcnum配置,將一些通過lru機制篩選出來的熱資料進行key-value式的快取,這一部分記憶體是和mmap占用的記憶體完全獨立的。同樣

的,redis在2.0版本之後增加了對磁碟儲存的支援,其機制與 tokyocabinet

類似,也是通過資料操作來判斷資料的熱度,並將熱資料盡量放到記憶體中。

2.多版本的資料合併

什麼叫多版本的資料合併呢?我們上面講 bigtable,或其開源版本

cassandra,都是通過定時將記憶體中的資料塊flush到磁碟中,那麼我們會想,如果這次是乙個update操作,比如 keya 的值從

valuea 變成了 valueb,那麼我們在flush到磁碟的時候就得執行對老資料 valuea

的清除工作了。而這樣,是否就達不到我們希望進行順序的磁碟io的目的呢?沒錯,這樣是達不到的,所以 bigtable

型別的系統確實也並不是這樣做的,在flush磁碟的時候,並不會執行合併操作,而是直接將記憶體資料寫入磁碟。這樣寫是方便很多,那讀的時候可能會存在一

個值有多個版本的情況,這時就需要我們來進行多版本合併了。所以第二種方法就是將一段時間的寫操作寫成乙個塊(可能並非乙個檔案),保證記憶體的使用不會無

限膨脹。在讀取時通過讀多個檔案塊進行資料版本合併來完成。

那如果儲存在磁碟的資料量是記憶體容量的很多倍,我們可能會產生許多個資料塊,那麼我們在獲取資料版本時,是否需要全部遍歷所有資料塊呢?當然不用,如果你看過bigtable**,相信你還記得它其中用到了 bloom-filter

演算法。bloom-filter

演算法最廣泛的應用是在搜尋引擎爬蟲中,它用於判斷乙個url是否存在於已抓取集合中,這一演算法並不百分之百精準(可能將不在集合中的資料誤判為在集合中,

但不會出現相反的誤差),但其在時間複雜度上僅是幾次hash計算,而空間複雜度也非常低。bigtable 實現中也用到了 bloom-filter

演算法,用它來判斷乙個值是否在某乙個集合中。而由於 bloom-filter

演算法的特點,我們只會多讀(機率很小),不會少讀資料塊。於是我們就實現對遠遠大於物理記憶體容量的資料的儲存。

硬碟不足掛載新的硬碟

1 加掛硬碟 sudo lshw c disk 看看有多少個硬碟,一般會顯示 disk 0 裝置名為 dev sda disk 1 裝置名為 dev sdb 2 檢視分割槽,sda是第一塊scsi硬碟,sdb第二塊,以此類推.物理分割槽使用a b編號 sudo fdisk l 檢視有沒有分割槽 3 ...

virtualBox掛載新的虛擬硬碟

在virtualbox中裝好ubuntu後,發現硬碟空間太小,怎樣才能增加硬碟容量?那就是再建乙個硬碟 1.新增新硬碟 設定 storage sata控制器 右擊,選擇 新增虛擬硬碟 然後,根據需求建立合適的硬碟 2.重啟虛擬機器 檢視現有系統的磁碟空間 sudo fdisk l 可看到新加的虛擬硬...

virtualBox掛載新的虛擬硬碟

在virtualbox中裝好ubuntu後,發現硬碟空間太小,怎樣才能增加硬碟容量?那就是再建乙個硬碟 1.新增新硬碟 設定 storage sata控制器 右擊,選擇 新增虛擬硬碟 然後,根據需求建立合適的硬碟 2.重啟虛擬機器 檢視現有系統的磁碟空間 sudo fdisk l 可看到新加的虛擬硬...