1. 程式人生 > 其它 >HBase基礎架構解析

HBase基礎架構解析

技術標籤:分散式資料庫javamysql大資料

本文章來源於:https://github.com/Zeb-D/my-review ,請star 強力支援,你的支援,就是我的動力。

[TOC]


概述

HBase作為NoSQL的一員,在效能上不如memcached和redis,但是持久化儲存方面比記憶體NoSQL強。作為文件型NoSQL在分散式儲存上比mongo做sharding和MapReduce分析方便多。

HBase是一個分散式儲存、資料庫引擎,可以支援千萬的QPS、PB級別的儲存。

場景

HBase可以說是一個數據庫,也可以說是一個儲存。擁有雙重屬性的HBase天生就具備廣闊的應用場景。在最近的一些版本中,引入了OffHeap降低gc影響,優化鏈路延遲,提供Replica等可以滿足線上的需求。引入MOB,可以儲存10M左右的物件,完全適應了物件儲存。另外由於自身的併發能力、儲存能力,可以說是具有最為競爭力的引擎

../../image/hbase-use-scence.jpeg

  • 物件儲存:我們知道不少的頭條類、新聞類的的新聞、網頁、圖片儲存在HBase之中,一些病毒公司的病毒庫也是儲存在HBase之中
  • 時序資料:HBase之上有OpenTSDB模組,可以滿足時序類場景的需求
  • 推薦畫像:特別是使用者的畫像,是一個比較大的稀疏矩陣,螞蟻的風控就是構建在HBase之上
  • 時空資料:主要是軌跡、氣象網格之類,滴滴打車的軌跡資料主要存在HBase之中,另外在技術所有大一點的資料量的車聯網企業,資料都是存在HBase之中
  • CubeDB OLAP:Kylin一個cube分析工具,底層的資料就是儲存在HBase之中,不少客戶自己基於離線計算構建cube儲存在hbase之中,滿足線上報表查詢的需求
  • 訊息/訂單:在電信領域、銀行領域,不少的訂單查詢底層的儲存,另外不少通訊、訊息同步的應用構建在HBase之上
  • Feeds流:典型的應用就是xx朋友圈類似的應用
  • NewSQL:之上有Phoenix的外掛,可以滿足二級索引、SQL的需求,對接傳統資料需要SQL非事務的需求

更多的場景需要不斷挖掘

架構

邏輯儲存模型

HBase以表的形式儲存資料,表由行和列組成。列劃分為若干個列族,如下圖所示:

RowKey:Hbase使用Rowkey來唯一的區分某一行的資料。如圖中"rk001"

列族:Hbase通過列族劃分資料的儲存,列族下面可以包含任意多的列,實現靈活的資料存取。Hbase的列族不是越多越好,官方推薦的是列族最好小於或者等於3。我們使用的場景一般是1個列族。如圖中的“CF1”列族,下面包含兩個列:"Name"和"Alias"。

時間戳:TimeStamp對Hbase來說至關重要,因為它是實現Hbase多版本的關鍵。在Hbase中使用不同的timestame來標識相同rowkey行對應的不通版本的資料。

Cell:HBase 中通過 rowkey 和 columns 確定的為一個儲存單元稱為 cell。每個 cell 都儲存著同一份 資料的多個版本。版本通過時間戳來索引。

物理儲存模型

HBase的物理儲存模型如下圖:

在HBase中,資料以表的形式儲存,表由很多行組成,每一行由Row key(行鍵)以及一個或多個的列值組成。

當表有很多很多的Row時,我們把這個表按某些規則(比如每500條)拆分成很多部分,那麼拆分後的每一部分就是所謂的HRegion,這個HRegion作為一個整體被HMaster分配到某一個RegionServer中。

可以這樣理解,把HMaster想象成一個老大,他把HRegion給分配到某一個伺服器上,這樣一來,一個表就被分成多個HRegion並可能分配到了不同的RegionServer上。

我們剛說HRegion是一個整體,意思是他不能再繼續往下分割了,他必須在一個RegionServer上。

總體架構

HBase的總體結構圖如下:

包括了HMaster、HRegionSever、HRegion、HLog、Store、MemStore、StoreFile、HFile等。

HBase底層依賴HDFS,通過DFS Cilent進行HDFS操作。HMaster負責把HRegion分配給HRegionServer,每一個HRegionServer可以包含多個HRegion,多個HRegion共享HLog,HLog用來做災難恢復。

每一個HRegion由一個或多個Store組成,一個Store對應表的一個列族,每個Store中包含與其對應的MemStore以及一個或多個StoreFile(是實際資料儲存檔案HFile的輕量級封裝),MemStore是在記憶體中的,儲存了修改的資料,MemStore中的資料寫到檔案中就是StoreFile。

HMaster

HMaster的主要功能有:

  • 把HRegion分配到某一個RegionServer。
  • 有RegionServer宕機了,HMaster可以把這臺機器上的Region遷移到active的RegionServer上。
  • 對HRegionServer進行負載均衡。
  • 通過HDFS的dfs client介面回收垃圾檔案(無效日誌等)

注:HMaster沒有單點問題,HBase中可以啟動多個HMaster,通過Zookeeper的Master Election機制保證總有一個Master執行。

HRegionServer

  • 維護HMaster分配給它的HRegion,處理對這些HRegion的IO請求,也就是說客戶端直接和HRegionServer打交道。(從圖中也能看出來)
  • 負責切分正在執行過程中變得過大的HRegion

HRegion

每個HRegion由多個Store構成,每個Store儲存一個列族(Columns Family),表有幾個列族,則有幾個Store,每個Store由一個MemStore和多個StoreFile組成,MemStore是Store在記憶體中的內容,寫到檔案後就是StoreFile。StoreFile底層是以HFile的格式儲存。

HLog

HLog(WAL log):WAL意為write ahead log(預寫日誌),用來做災難恢復使用,HLog記錄資料的變更,包括序列號和實際資料,所以一旦region server 宕機,就可以從log中回滾還沒有持久化的資料。

HFile

HBase的資料最終是以HFile的形式儲存在HDFS中的,HBase中HFile有著自己的格式。

詳解

HFile

what

HFile是HBase中KeyValue資料的儲存格式(這裡不要把KeyValue想成Map的那種形式,理解起來會好一點),HFile是Hadoop的二進位制格式檔案,實際上StoreFile就是對HFile做了輕量級包裝,即StoreFile底層就是HFile 。

HFile由六部分組成:

  • Data(資料塊):儲存表中的資料(KeyValue的形式),這部分可以被壓縮。由多個block(塊)組成,每個塊的格式為:

    [塊頭] + [key長] + [value長] + [key] + [value]。
    
  • Meta (元資料塊):儲存使用者自定義KeyValue。元資料是key-value型別的值,但元資料快只儲存元資料的value值,元資料的key值儲存在第五項(元資料索引塊)中。該塊由多個元資料值組成。

  • File Info:定長;記錄了檔案的一些元資訊,例如:AVG_KEY_LEN,AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。

    fileInfo是以key值排序key-value型別的值。基本格式為:
    keyValue元素的個數 +
    (key + value型別id + value) +
    (key + value型別id + value) +
     ……
    
  • Data Index(資料塊索引):記錄了每個Data塊的起始索引。

    該塊的組成為:
    索引塊頭 +
    (資料塊在檔案中的偏移 + 資料塊長 + 資料塊的第一個key) +
    (資料塊在檔案中的偏移 + 資料塊長 + 資料塊的第一個key) +
    ……
    
  • Meta Index(元資料塊索引):記錄了每個Meta塊的起始索引。

    該塊組成格式同資料塊索引,只是某部分的意義不一樣,組成格式:
    索引塊頭 +
    (元資料在檔案中的偏移 + 元資料value長 + 元資料key) +
    (元資料在檔案中的偏移 + 元資料value長 + 元資料key) +
    ……
    
  • Trailer:定長;用於指向其他資料塊的起始點。

    該塊記錄了其他各塊在hfile檔案中的偏移資訊和其他一些元資訊。組成格式如下:
    檔案尾 +
    Fileinfo偏移 +
    資料塊索引偏移 +
    資料塊索引個數 +
    元資料索引偏移 +
    元資料索引個數 +
    資料塊中未壓縮資料位元組數 +
    資料塊中全部資料的key-value個數 +
    壓縮程式碼標識 +
    版本標識
    

我的理解 : Trailer中有指向其他資料塊的“指標”,通過Trailer能找到File Info,Data Index, Meta Index,然後通過Data Index和 Meta Index又能找到對應的資料塊和元資料塊。

同時這裡有幅圖不錯,建議認真看下這幅圖,很好懂:

Data結構

提到HFile中有Data(資料塊)部分,Data的結構又是如何的呢?

資料塊組成圖如下:

Data Block Magic{'D', 'A', 'T', 'A', 'B', 'L', 'K', 42 }
key長value長keyvalue
key長value長keyvalue
……
key長value長keyvalue
Data Block Magic{'D', 'A', 'T', 'A', 'B', 'L', 'K', 42 }
key長value長keyvalue
key長value長keyvalue
……
key長value長keyvalue
Blocks ……

資料塊部分由多個block塊組成,每個資料塊由塊頭 + 多個cell(key-value對)集合組成,如上圖。每個資料塊的大小在建立表的列族的時候可以指定,預設為(64 * 1024)。

  1. 塊大小的設定由HColumnDescriptor.setBlockSize(int)指定,預設(64 * 1024)。
  2. 塊大小設定,塊設定的越小,訪問速度越快,但資料塊索引越大,消耗的記憶體越多。因為在載入HFile時會把資料塊索引全部載入到記憶體中。

資料塊組成說明:

  1. Data Block Magic – 資料塊頭,8位元組,固定位元組如下:{'D', 'A', 'T', 'A', 'B', 'L', 'K', 42 }。

  2. key長 – 4位元組整型,記錄每個cell的key的長度。

  3. value長 – 4位元組整型,記錄每個cell的value的長度。

  4. key – cell的key值,byte[]型別,組成如下:

    rowKey的長(2位元組)+ rowKey + family的長(1位元組) + family + qualify + timestampe(8位元組) + keyType型別(1位元組)**

    1)rowKey的長度不能大於0x7fff(32767).

    2)rowKey不能為空。

    3)family(列族)的長度不能大於0x7f(127)

    4)qualify(限定符)的長度不能大於(0x7fffffff(2147483647) – row長度 – family長度)。

  5. value – cell的value值,byte[]型別,value值不能為空。

**例如:**在hbase中有一個表(student),其中有一個列族(info),該列族不壓縮。其中的rowkey用學號表示,現在插入一個記錄(rowkey='033', qualify='age', value='19')。那麼該記錄將被表示成一個cell(key-value對)儲存到HFile中,那麼該cell在HFile中的內容如下:

位元組表示
key長{0,0,0,24}
value長{0,0,0,2}
key{0,3}+{'0', '3', '3'}+{4}+{'i', 'n', 'f', 'o'}+{'a', 'g', 'e'}+{0,0,0,0,0,0,0,8}+{4}
value{'1', '9'}

問題:

  1. 塊大小的設定策略?

  2. keyType的說明?

  3. compress壓縮的說明?

KeyValue結構

包含了:key length, value length, 緊接著是Key部分:開始是固定長度的數值,表示RowKey的長度,緊接著是 RowKey,然後是固定長度的數值,表示Family的長度,然後是Family,接著是Qualifier,然後是兩個固定長度的數值,表示Time Stamp和Key Type(Put/Delete)。Value部分沒有這麼複雜的結構,就是純粹的二進位制資料了。

舉個栗子: 執行這條語句:Put #1: rowkey=row1, cf:attr1=value1。KeyValue的核心部分將會是這樣:

rowlength -----------→ 4(row1長度)

row -----------------→ row1

columnfamilylength --→ 2

columnfamily --------→ cf

columnqualifier -----→ attr1

timestamp -----------→ server time of Put

keytype -------------→ Put

元資料塊詳解

每個元資料是key-value型別的值,新增的元資料會按照從小到大的順序排序。

在StoreFile中,如果使用BloomFilter,則StoreFile將會把BloomFilter的資訊儲存到HFile中的元資料中, 元資料塊中只儲存元資料的value值,key值儲存在元資料索引塊中。格式如下:

Meta Block Magic{'M', 'E', 'T', 'A', 'B', 'L', 'K', 99 }
Meta Data Value
Meta Block Magic{'M', 'E', 'T', 'A', 'B', 'L', 'K', 99 }
Meta Data Value
……

每個元資料由元資料頭+元資料值組成。

FileInfo詳解

fileInfo中儲存的資訊為key-value型別的值,其中key與value都是byte[]型別。每個新增的值在內部都以值key順序從小到大進行排序。fileInfo儲存了與該HFile相關的一些資訊,其中有系統保留的一些固定的值,這些值的key以”hfile.”為字首。也可以儲存使用者自定義的一些值,但這些值的key不能以”hfile.”開頭。其中系統內部保留的一些值如下:

key(字串表示,實際以二進位制儲存)value
LASTKEYhfile.LASTKEY該HFile中的資料塊中的最後一個值的key, 該值如果為空則不進行儲存
AVG_KEY_LENhfile.AVG_KEY_LEN該HFile中的資料塊中的所有值key的平均長度。
AVG_VALUE_LENhfile.AVG_VALUE_LEN該HFile中的資料塊中的所有值value的平均長度。
COMPARATORhfile.COMPARATOR在HFile中的資料塊中的值都是以值的key進行排序來存放的,而key的組成比較複雜,這就需要一個key的比較器類,而該值儲存了key值比較器的類的名稱。

fileInfo在HFile中的格式如下:

filInfo中所有值(key-value對)的個數,整型
keyvalue型別標識value
keyvalue型別標識value
……

fileInfo各項說明:

  1. filInfo中所有值(key-value對)的個數,整型,四位元組。

  2. key值,儲存fileInfo中值得key值。在HFile中的組成為

key長+key

其中key長以壓縮的整型儲存,整型型別包括(byte,short,int,long),如果該整數用i表示,詳細說明如下:

1. 當-112 <= i <= 127 時,用一個位元組儲存實際值。

2. 其他情況下,第一個位元組表示該整型與正負與該整數佔位元組長度,隨後儲存的是從該整數補碼的高位算起的第一個非0位元組的所有值。如果第一個位元組為v,詳細說明如下:

a) 當-120<=i<=-113時,表示該值為正數,該數所佔位元組為-(v+112)

b) 當-128<=i<=-121時,表示該值為負數,該數所佔位元組為-(v+120)

例如:

原始值壓縮後,以位元組表示說明
-87{-87}第一種情況
127{127}第一種情況
-1246{-122} + {4, -35}第二種情況的b型別。{-122}表示該數為負數,並且所佔位元組長度為-(-122+120)=2位元組。其中{4,-35}儲存的是-1246的補碼1245的第一個非0位元組開始的所有位元組。1245的16進製為0x04DD,非0位元組共2個,第一個為0x04(4),第二個為0xDD(-35),組合一起為{-122, 4,-35}
130{-113} + {-126}第二種情況的a型別。{-113}表示該數為正數,並且所佔位元組長度為-(-113+112)=1位元組。其中{-126}儲存的是130的補碼130的第一個非0位元組開始的所有位元組。130的16進製為0x04DD,非0位元組共2個,第一個為0x04(4),第二個為0x82(-126),組合一起為{-113, -126}
  1. value值,儲存fileInfo中值的value值。在HFile中的組成為

value長+value

其中value長以壓縮的整型儲存,壓縮整型具體格式參考key值中關於壓縮整型的說明。

資料塊索引

資料塊索引儲存的是每一個數據塊在HFile檔案中的位置、大小資訊以及每個塊的第一個cell的key值。格式如下:

Index Block Magic{'I', 'D', 'X', 'B', 'L', 'K', 41, 43 }
block offsetblock sizeblock first key
block offsetblock sizeblock first key
……
block offsetblock sizeblock first key

格式各項說明:

  1. block offset 塊在HFile中偏移,long(8位元組)。

  2. block size 塊大小,int(4位元組)。

  3. block first key 塊中第一個cell(key-value)值得key.該值的組成為(key的長(壓縮整型表示)+key值)

元資料塊索引

該資料塊的格式與資料庫索引相同,元資料塊索引儲存的是每一個元資料在HFile檔案中的位置、大小資訊以及每個元資料的key值。格式如下:

Index Block Magic{'I', 'D', 'X', 'B', 'L', 'K', 41, 43 }
meta offsetmeta sizemeta name
meta offsetmeta sizemeta name
……
meta offsetmeta sizemeta name

格式各項說明:

  1. meta offset 元資訊在HFile中偏移,long(8位元組)。

  2. meta size 元資訊資料大小,int(4位元組)。

  3. meta name 元資訊中的key值.該值的組成為(key的長(壓縮整型表示)+key值)

檔案尾

檔案尾主要儲存了該HFile的一些基本資訊。格式比較簡單,如下:

Trailer Block Magic{'T', 'R', 'A', 'B', 'L', 'K', 34, 36 }
FileInfo Offset (long)
Data Index Offset (long)
Data Index Count (int)
Meta Index Offset (long)
Meta Index Count (int)
Total Uncompressed Bytes (long)
Entry Count (int)
Compression Codec (int)
Version (int)

說明如下:

  1. FileInfo Offset – FileInfo資訊在HFile中的偏移。long(8位元組)。

  2. DataIndex Offset – 資料塊索引在HFile中的偏移。long(8位元組)。

  3. DataIndex Count – 資料塊索引的個數。int(4位元組)。

  4. MetaIndex Offset – 元資料索引塊在HFile中的偏移。long(8位元組)。

  5. MetaIndex Count – 元資料索引塊的個數。int(4位元組)。

  6. TotalUncompressedBytes – 未壓縮的資料塊部分的總大小。long(8位元組)。

  7. Entry Count – 資料塊中所有cell(key-value)的個數。int(4位元組)

  8. Compression Codec – 壓縮演算法為enum型別,該值表示壓縮演算法程式碼。(LZO-0,GZ-1,NONE-2),int(4位元組)

  9. Version – 版本資訊。當前該版本值為1. int(4位元組)。

HLog

HLog是用來做災難恢復的,為什麼這麼說呢?假設沒有HLog,我們進行一個寫請求,會首先寫到MemStore上,等到Memstore到達一定容量後,才會flush到storefile中。但是如果在這之前主機斷電了呢?那這部分操作的資料全丟失了。這顯然不是我們想到的結果,於是有了HLog,當發起一個寫請求時,會先往HLog中寫再往MemStore中寫,成功後(此時還沒被存到sotrefile)就給客戶端一個寫入成功的response。

WAL最重要的作用是災難恢復。和MySQL 的BIN log類似,它記錄所有的資料改動。一旦伺服器崩潰,通過重放log,我們可以恢復崩潰之前的資料。這也意味如果寫入WAL失敗,整個操作將認為失敗。

首先,客戶端初始化一個可能對資料改動的操作,如put(Put),delete(Delete) 和 incrementColumnValue()。這些操作都將被封裝在一個KeyValue物件例項中,通過RPC 呼叫傳送給HRegionServer(最好是批量操作)。 一旦達到一定大小,HRegionServer 將其傳送給HRegion。這個過程中,資料會首先會被寫入WAL,之後將被寫到實際存放資料的MemStore中。

當MemStore到達一定大小,或者經過一段時間後,資料將被非同步地寫入檔案系統中。然而,在兩次寫入檔案系統之間的資料,是保留在記憶體中的。如果這個時候系統崩潰,那資料···,別急,我們有WAL!

簡單總結:

HLog檔案就是一個普通的Hadoop Sequence File(也是KeyValue形式,與前面的資料塊中的KeyValue類比),

Sequence File 的Key是HLogKey物件,HLogKey中記錄了寫入資料的歸屬資訊,除了table和region名字外,

同時還包括 sequence number和timestamp,timestamp是“寫入時間”,sequence number的起始值為0,或者是最近一次存入檔案系統中sequence number。

HLog Sequece File的Value是HBase的KeyValue物件,即對應HFile中的KeyValue。包括:row,column family, qualifier, timestamp, value,以及“Key Type”(比如PUT或DELETE)

重要的類

HLog

HLog是實現WAL的類。一個HRegionServer對應一個HLog例項。當HRegion初始化時,HLog將作為一個引數傳給HRegion的建構函式。

HLog最核心的是呼叫doWrite的append() 方法,前面提到的可能對資料改動的操作都就將首先呼叫這個方法。出於效能的考慮,put(), delete() 和incrementColumnValue()有一個開關函式setWriteToWAL(boolean) , 設為false將禁用WAL。這是為什麼上圖中向下的箭頭是虛線的原因。預設時候當然需要WAL,但是假如你執行一個數據匯入的MapReduce Job,你可以通過關閉WAL獲得性能上的提升。

另一個重要的特性是HLog將通過“sequence number”追蹤資料改變。它內部使用AtomicLong保證執行緒安全。sequence number的起始值為0,或者是最近一次存入檔案系統中sequence number。Region開啟儲存檔案,讀取每個HFile中的最大的sequence number,如果該值大於HLog 的sequence number, 就將它作為HLog 的sequence number的值。最後,HLog將得到上次存入檔案和繼續記log的點。過會,我們將看到它的應用。

上圖表示了3個不同的region,每一個負責一段rowkey的範圍。這些region將共享同一個HLog例項,我們可以看出,從不同region來的資料寫入WAL的順序是不確定的。在後面我們會再詳細的介紹。

最後,Hlog利用HMaster恢復和切分一個由一個崩潰的HRegionServery遺留下來的Log。之後,重新部署regions。

HLogKey

WAL使用Hadoop的SequenceFile,它將記錄儲存為key/values 的資料集。對於WAL,key是一個HLogKey的例項。 KeyValue不僅包括row,column family, qualifier, timestamp, value, 還包括“Key Type”—派上用場啦, 這裡,可以用Key Type代表一個“put”或“delete”操作。

但是,哪裡去存放KeyValue的歸屬資訊,比如region或者表名呢?這些存放在HLogKey中。同時還包括 sequence number,和“寫入時間”, 是一個記錄資料何時寫入到log的時間戳。

LogFlusher

前面提到,資料以KeyValue形式到達HRegionServer,將寫入WAL,之後,寫入一個SequenceFile。看過去沒問題,但是因為資料流在寫入檔案系統時,經常會快取以提高效能。這樣,有些本以為在日誌檔案中的資料實際在記憶體中。這裡,我們提供了一個LogFlusher的類。它呼叫HLog.optionalSync(),後者根據“hbase.regionserver.optionallogflushinterval”(預設是10秒),定期呼叫Hlog.sync()。另外,HLog.doWrite()也會根據“hbase.regionserver.flushlogentries”(預設100秒)定期呼叫Hlog.sync()。Sync() 本身呼叫HLog.Writer.sync(),它由SequenceFileLogWriter實現。

LogRoller

Log的大小通過$HBASE_HOME/conf/hbase-site.xml 的“hbase.regionserver.logroll.period”限制,預設是一個小時。所以每60分鐘,會開啟一個新的log檔案。久而久之,會有一大堆的檔案需要維護。首先,LogRoller呼叫HLog.rollWriter(),定時滾動日誌,之後,利用HLog.cleanOldLogs()可以清除舊的日誌。它首先取得儲存檔案中的最大的sequence number,之後檢查是否存在一個log所有的條目的“sequence number”均低於這個值,如果存在,將刪除這個log。

這裡解釋下你可能在log中看到的令人費解的內容:

2009-12-15 01:45:48,427 INFO org.apache.hadoop.hbase.regionserver.HLog: Too`
`many hlogs: logs=130, maxlogs=96; forcing flush of region with oldest edits:`
`foobar,1b2dc5f3b5d4,1260083783909

這裡,我們看到,log file的數目超過了log files的最大值。這時,會強制呼叫flush out 以減少log的數目。

“hbase.regionserver.hlog.blocksize”和“hbase.regionserver.logroll.multiplier”兩個引數預設將在log大小為SequenceFile(預設為64MB)的95%時回滾。所以,log的大小和log使用的時間都會導致回滾,以先到達哪個限定為準

Replay

當HRegionServer啟動,開啟所管轄的region,它將檢查是否存在剩餘的log檔案,如果存在,將呼叫Store.doReconstructionLog()。重放一個日誌只是簡單地讀入一個日誌,將日誌中的條目加入到Memstore中。最後,flush操作將Memstore中資料flush到硬碟中。

舊日誌往往由region server 崩潰所產生。當HMaster啟動或者檢測到region server 崩潰,它將日誌檔案拆分為多份檔案,將其儲存在region所屬的資料夾。之後,根據上面提到的方法,將日誌重放。需要指出的是,崩潰的伺服器中的region只有在日誌被拆分和拷貝之後才能被重新分配。拆分日誌利用HLog.splitLog()。舊日誌被讀入主執行緒記憶體中,之後,利用執行緒池將其寫入所有的region資料夾中,一個執行緒對應於一個region。

問題

  1. 為什麼要一個RegionServer 對應於一個HLog。為什麼不是一個region對應於一個log file?

引用BigTable中的一段話,

如果我們每一個“tablet”(對應於HBase的region)都提交一個日誌檔案,會需要併發寫入大量的檔案到GFS,這樣,根據每個GFS server所依賴的檔案系統,寫入不同的日誌檔案會造成大量的磁碟操作。

HBase依照這樣的原則。在日誌被回滾和安全刪除之前,將會有大量的檔案。如果改成一個region對應於一個檔案,將會不好擴充套件,遲早會引發問題。

  1. 潛在問題

    1. 當server崩潰,HBase需要將其log切分成合適的片。然而,由於所有的條目混雜在日誌中,HMaster只有在將log完全分配到每一個server後,才能將崩潰server中的region重新分配。這個時間可能很長。

    2. 資料安全。你希望能儲存你所有的資料,雖然你能將flush的時間調到儘可能的低,你依然依賴於上面提到的檔案系統。那些用於儲存資料依舊有可能沒寫到磁碟而發生資料丟失。

很明顯,需要log來保證資料安全。最好是能讓一個日誌保持1個小時(或長)的開啟狀態。當資料來時,將新的key/value對寫入SequenceFile中,並定期flush資料到磁碟中。但是Hadoop不是這樣工作的。他提供了一個API,允許開啟一個檔案,寫入大量的資料,然後馬上關閉檔案,成為一個對其他人只讀的檔案。只有當檔案關閉時才是對其他人可讀的。那麼,如果一個程序在寫入檔案時僵死,那麼,資料很可能會丟失。因此,我們需要一個功能,能取到一個離崩潰伺服器寫入資料儘可能近的點。

插曲: HDFS append,hflush,hsync,sync ...

這些都起源於HADOOP-1700。Hadoop 0.19沒有能解決這個問題。這個問題後來又成為HADOOP-4379或HDFS-200,並實現了syncFS(),後者可以同步檔案的改變。同時,HBase-1470中,將這個API開放,但是依然沒有解決這個問題。

之後是HDFS-265,重新提出append的方案,並引入Syncable的介面,開放hsync()和hflush()。

SequenceFile.Writer.sync()和上面的並不相同。 它只是將一個同步標記寫入檔案,以方便資料恢復。

雖然append對於HDFS很有用,但並沒有用在HBase中。HBase用了hflush,它可以在log寫完成後將所有資料寫入磁碟。當伺服器崩潰,我們可以安全地將“髒”檔案讀到最後一次改動。Hadoop 0.19.0中,利用Hadoop fsck /可以根據HBase開啟的日誌檔案數目報告DFS的破損程度。

結論是,在Hadoop 0.21.0之前,你非常容易遇到資料丟失。在Hadoop 0.21.0之後,你將得到頂尖的系統。