不吹不黑,贊一下應用運維管理的cassacdra

不吹不黑的爲菊廠的應用運維管理AOM點個贊。Why?

某菊廠應用運維管理工具AOM每天處理着億級條數據,這麼多數據是怎麼存儲的呢?

說到數據存儲就會想到關係型數據庫,比如mysql,oracle,sybase。關係型數據庫有自己的優勢,數據強一致性,支持事務,通用,技術成熟。但是對於大批量數據的存儲和查詢就稍顯吃力,畢竟AOM每秒的寫入數據至少都是上萬條,甚至是十幾萬條,隨着系統規模增長,數據庫的擴容也成爲新的瓶頸。

AOM的數據存儲系統使用的是非關係型數據庫-----cassandra,相比關係型數據庫,cassandra擁有高併發,大數據下讀寫能力強,支持分佈式,易擴展等優點,當前也有最致命的缺點,不支持事務,不過對於事務我們可以通過zk/etcd等其他組件協助完成。

對於關係型數據庫相比非關係型數據庫爲什麼會有這麼大的差異,這個就得從兩者的架構上來講了,下面編者以mysql和cassandra進行對比分析。

不管是mysql還是cassandra,最終數據的存儲都要落盤,我們先來看下磁盤的寫入原理:

磁盤的基本組件可分爲以下幾部分:磁頭,盤片,盤面,磁道,柱面,扇區等。

盤片被劃分成一系列同心環,圓心是盤片中心,每個同心環叫做一個磁道,所有半徑相同的磁道組成一個柱面。磁道被沿半徑線劃分成一個個小的段,每個段叫做一個扇區,每個扇區是磁盤的最小存儲單元。當需要從磁盤讀取數據時,系統會將數據邏輯地址傳給磁盤,磁盤的控制電路按照尋址邏輯將邏輯地址翻譯成物理地址,即確定要讀的數據在哪個磁道,哪個扇區。爲了讀取這個扇區的數據,需要將磁頭放到這個扇區上方,爲了實現這一點,磁頭需要移動對準相應磁道,這個過程叫做尋道,所耗費時間叫做尋道時間,然後磁盤 旋轉將目標扇區旋轉到磁頭下,這個過程耗費的時間叫做旋轉時間。

即一次訪盤請求(讀/寫)完成過程由三個動作組成:
1)尋道(時間):磁頭移動定位到指定磁道 

2)旋轉延遲(時間):等待指定扇區從磁頭下旋轉經過 
3)數據傳輸(時間):數據在磁盤與內存之間的實際傳輸

大家應該有過類似的經歷,進行數據拷貝時,文件個數越少,單個文件越大,拷貝的速率越快,反之文件個數多,單個文件小,拷貝的速率越慢,這其中的原因就是因爲在拷貝小文件時,系統的耗時基本都耗費在尋址上了。Cassandra相比mysql有更高的寫入能力,就是因爲cassandra採用了更高效的寫入機制,該機制大大縮短了磁盤的尋址時間(準確來講應該是尋址次數)。

我們先來看下Mysql(InnoDB)的索引原理, InnoDB的索引採用B+樹,其數據結構如下所示:

所有的數據都存儲在葉子節點,葉子節點之間都有指針,這是爲了做範圍遍歷。B+樹的優勢在於快速索引,B+樹的層高基本都在2~3層,也就意味着一次數據查找只需要2~3次IO操作。而且每次的單條數據都非常穩定,耗時和查找次數都差不多。B+樹最大的性能問題是會產生大量的隨機IO,隨着數據的插入,葉子節點會慢慢分裂,邏輯上連續的節點物理上確不連續,甚至相隔甚遠,順序遍歷的時候,會產生大量的隨機IO操作。這正如大家熟知的ArrayList和LinkedList,ArrayList在內存中是一塊連續的內存,訪問的時候順序訪問,LinkedList是多個內存塊通過指針串聯起來的,訪問的時候必須先通過指針獲取下一個內存塊的地址,然後再通過地址訪問,因此ArrayList的訪問遠遠高於LinkedList。B+樹的葉子節點就類似一個LinkedList,隨着葉子節點的分裂,在做順序檢索時,跨葉子節點的訪問往往需要先找到下一個葉子節點的地址(磁盤尋址),然後才能訪問到具體的葉子節點。

B+樹的順序檢索會產生大量的隨機IO,B+樹的寫入同樣會產生類似的問題,比如上圖B+樹中的9和86,它們所屬的葉子節點在磁盤上相隔甚遠,數據插入時就會產生兩次隨機寫入。當大批量數據寫入時,隨機IO操作的次數也就更多。

如下是一張隨機讀寫和順序讀寫的性能比對圖:

從上圖可以直觀的感受到隨機讀寫與順序讀寫的差異,這兩者完全不在一個量級。用過kafka和HDFS的開發者就會發現kafka和HDFS的磁盤IO使用率非常高,有時甚至接近磁盤的最大寫入速率,這個就是因爲kafka和HDFS是基於文件的順序寫入(當然還有其他技術)。從以上分析來看,磁盤的隨機讀取/寫入是影響mysql順序檢索和批量寫入的最大因素,那我們有沒有辦法減少這種隨機寫入呢,此時LSM-Tree(Log-Structured Merge-Tree)呼之欲出。

2006年,google發表了BigTable的論文。BigTable的數據結構就採用了LSM(http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.44.2782&rep=rep1&type=pdf)。目前LSM被很多數據庫作爲存儲結構,比如HBase,Cassandra,LevelDB。LSM拋棄了大多數數據庫使用的傳統文件組織方法,通過減少更新/寫入操作帶來的隨機操作次數來提高數據的寫入能力。

LSM Tree的核心思路其實非常簡單,就是假定內存足夠大,因此不需要每次有數據更新就必須將數據寫入到磁盤中,而可以先將最新的數據駐留在磁盤中,等到積累到一定數目之後,再使用歸併排序的方式將內存內的數據合併追加到磁盤隊尾(因爲所有待排序的樹都是有序的,可以通過合併排序的方式快速合併到一起)。

LSM的核心思路可以分爲兩部分:

①、數據先寫入內存

②、將內存中的數據排序後追加到磁盤隊尾。

LSM由兩個或兩個以上的存儲結構組成。最簡單的LSM由兩部分組成,一部分常駐內存,稱爲C0;另一部分存儲在硬盤上,稱爲C1。

數據寫入時,先記錄到本地的操作日誌文件(HLog或CommitLog),爲將來做數據恢復使用。然後將數據寫入到C0中,由於C0使用的是內存,因此插入性能遠遠高於磁盤寫入。當C0的節點數目超過一定閾值時,會將C0中的數據進行一次排序,然後追加到C1樹中。

多部件的LSM就是包含多個存儲結構:

隨着數據規模增加,C0中的數據超過閾值後就會往磁盤中寫入一個新的file,這樣磁盤中的樹(file)會越來越多。當較小的Ci-1個數超過一定閾值的時候,會進行Ci-1和Ci的合併。合併是爲了減少整個C樹的個數,加快搜索速度。

數據查詢的時候,會按照樹的生成時間按照從新到舊的順序逐個遍歷每個C樹,即C0,C1,C2….Ck。爲什麼要按照時間順序從最近往之前遍歷呢,這就是LSM的另一個巧妙點(更新/刪除)。

LSM的更新和刪除操作都是往C0上新增一條記錄,通過新記錄+標記的方式完成,因此在遍歷的時候必須按照時間順序進行遍歷,這樣就可以保證數據更新和刪除的正確性,同時保證了數據的順序寫入。當前LSM在進行C樹合併時,會對刪除和更新記錄進行合併。

我們來看下HBase的整個架構圖:

HBase是基於HDFS之上採用LSM結構做的數據存儲。HBase的主要部件可以分爲如下幾類:

storeFile:小文件,不可編輯。即寫入到磁盤中的C樹。

Hlog:LSM中用於記錄寫入記錄的操作日誌,爲了將來做數據恢復使用,畢竟C0中的數據是在內存中存儲,當HBase宕機後,內存中的數據就會丟失,此時需要從Hlog中恢復。

Memstore:即C0樹。至此,LSM和B+樹的對比也就講完了。

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