最終還是寫到數據存儲的東西了啊!我對大文件存儲的直接認識是從Google的三大論文裡面瞭解的,感興趣的可以去搜索,三大論文主要講三個實現:Google File System(大文件存儲系統),Big Table(大表),MapReduce(基於大文件的數據統計方法)。Google的大文件系統是閉源的(C++實現),只發布了這些論文,開源的實現是Hadoop(Java語言實現)。Hadoop幾乎是大數據必備的,大數據方面的開發者估計都很熟悉它。

這裡講的是我對大文件存儲的解析、以及自己打算實現一個什麼樣的系統,包含了我對它的簡化處理,簡單說就是「如何用C++手把手實現一個簡化版的大文件系統」。如果不感興趣的可以直接忽略了。

(一)瞭解大文件的目的

(1)讀寫單體大文件(幾百G甚至上T的文件),使用分散式處理提高總體的處理效率

(2)容災,某個或幾個機器宕機仍然可以保持文件完整,並且能自動拷貝丟失的備份

目前單體機器是很難處理上T的大文件的,不管是受限於物理帶寬還是內存、CPU,或者從容災上面考量,這不是一個好方案。於是大文件系統應運而生,這就是一個最典型的分散式文件系統。一個大文件,被分解成為多個段落(chunk,大小上限64M),這些chunk就是一個普通文件,記錄在機器的文件系統裡面。每一個chunk會有3個或者多個備份,而且每一個chunk備份都部署在不同的機器上面。

(二)大致實現機制

(1)根據不同的功能,分成三個服務模塊:master,node(chunkserver),client

(2)主要數據結構包含:node的IP地址、chunk元數據、文件chunk列表數據

圖片來自Google論文

node節點是用來存儲chunk數據的,chunk數據包含這個文件的段落,還有描述這個段落歸屬的信息(chunk元數據)。mater節點是用來匯總當前所有node上面的chunk元數據,master本地不記錄任何元數據。當node連接到master時,推送自己本地擁有的chunk元數據給master,由master來做一個匯總的操作。client是一個類似hiredis之類的客戶端連接庫,通過嵌入到你的程序裡面來使用,會向上提供一些read/write文件的介面。

每個client在啟動之後,都會向master諮詢自己的大文件信息,也就是chunk列表數據和node的IP地址。client會連接每一個大文件所在的node,讀寫數據不經過master,直接從node進行讀寫操作。不過在對chunk進行操作時,比如分配新的chunk,仍然是由master分配的。

在這裡還有一個租約的概念。租約是針對chunk的,每一個chunk都有3個或者多個備份,有一個chunk(在某個node上面)會被master分配作為主chunk,其他的作為從chunk。那麼在修改或者寫入數據的時候,為了確保寫入數據的順序,由主chunk分配數據修改的順序,保證數據修改在各個chunk上面是按照一致的順序執行的,確保各個chunk的數據一致性。

租約是將master負責的東西分配給了node來執行,減輕master的負擔。那麼從上面來看,master除了管理chunk元數據之外,還做了哪些呢,有這麼大壓力?根據論文描述,一個大文件系統很可能管理上百萬個文件的元數據,需要響應可能幾百個client的請求。而且master還需要記錄一個chunk元數據變更的日誌(以及checkpoint文件),為了防止master宕機丟失元數據,重啟時可以從checkpoint之後的文件進行恢復。

(三)為什麼要去研究它

前面也說了,已經有Hadoop這樣完整的實現了,幹嘛還要去研究這個玩意?幹嘛還大費周章再去造個輪子呢?

一個是練手。寫一個簡單的,不用完整的去實現整個系統,丟棄一些設計,真正動手實現一個簡易的大文件系統。不管是對於個人技術的成長還是對於這個大文件的理解,都會更加深刻,因為沒有任何源碼參考,你要努力實現它,你在思考每一個細節,推敲怎麼合理的實現。這些東西最終會構成你對它的認知。

另一個是能否對整個設計結構進行改進。就我目前所知,數據從原始數據(歷史數據)加工到終端可用(比如智能決策數據),需要編寫大量的MapReduce方法進行數據統計,方法之間還有各種依賴,整個處理時間是非常繁瑣而漫長的。有沒有可能對這個流程做出優化呢?提升處理效率,縮短獲取決策數據需要的時間。

還有一個是關於MapReduce的。這些方法的編寫基本上是和業務掛鉤,Hadoop的話是Java寫的(Google的話應該是C++)。那麼這方面的開發有沒有可能引入虛擬機(比如LuaJIT)使用腳本來作為MapReduce的開發語言,那樣應該挺便利,但是不知道會有多少性能損失。

最後一個是可能用於分散式KV資料庫或者分散式SQL的實現。這個大文件自帶讀寫分離,容災等特性,如果掛載一個功能模塊,比如SQL存儲,那有沒有可能就可以實現分散式SQL。這些都不知道,去試試就好了。

(四)準備的物料

我沒有從零去開發這個系統,使用了以前編寫的網路庫,以及節點管理方式,節省了不少時間,不過到目前為止都還沒有完全實現這個大文件系統。準備的東西包括:

(1)一個用於連接功能的網路庫

(2)編寫一個節點之間連接管理模塊,處理重連等

(3)序列化協議,為此我為eproto協議添加了一個C++的版本,用來同步服務間的協議調用。

zhouxingtuan/eproto?

github.com
圖標

(4)封裝基於eproto的RPC模塊

(5)剩下的就是挨個服務邏輯的編寫邏輯代碼+調試了

這個大文件系統看著簡單,其實挺花時間,你能想像到這個是Google在20年前設計的東西嗎?這兩個月利用平常的下班時間進行開發,斷斷續續,碰到一些不清楚的細節有時還會卡殼。沒有什麼美好的東西可以簡簡單單就獲得,不是嗎?嗯,不過其實大部分經歷過艱難困苦才獲得的東西也不一定美好!這纔是現實吧


推薦閱讀:
相關文章