不吹不黑,贊一下應用運維管理的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+樹的對比也就講完了。