原文: http://ofps.oreilly.com/titles/9781449396107/architecture.htmlhtml
譯者:phylips@bmy 2011-10-1 node
出處:http://duanple.blog.163.com/blog/static/709717672011925102028874/mysql
1. Read Path
web
HBase中的每一個column family可能有多個文件,文件中包含實際的cells或者是KeyValue實例。當memstore中積累的更新被flush到磁盤上時這些文件就會建立出來。負責compaction的後臺線程會經過將小文件合併成更大的文件來將文件數控制在必定水平上。Major compaction最終會將全部的文件集合壓縮成一個,以後隨着flush的進行,小文件又會出現。sql
由於全部的存儲文件都是不可變的,因此就無法直接將一個值從它們裏面刪除,也無法對某個值進行覆蓋。而只能經過寫入一個墓碑式的標記,來表明某個cell或者某幾個cell或者是整行都被刪除了。apache
假設今天你在給定的一行裏寫了一個列,以後你一直不斷的添加數據,那麼你可能會爲該行寫入另外一個列。問題是,假設最初的列值已經被持久化到了磁盤中,而新寫入的列還在memstore中,或者已經被flush到了磁盤,那該行到底算存放到哪呢?換句話說,當你對該行執行一個get命令時,系統怎麼知道該返回什麼內容?做爲一個客戶端,你可能但願返回全部的列—看起來它們好像就是一個實體同樣。可是實際的數據是存儲在獨立的KeyValue實例中的,並且可能跨越任意數目的存儲文件。api
若是你刪除了最初的那個列值,而後再執行get操做,你但願該值已經不存在了,雖然實際上它還存在於某處,可是墓碑式的標記代表你已經把它刪除了。可是該標記頗有可能與你要刪除的值是分開存儲的。關於該架構更細節的內容參見the section called 「Seek vs. Transfer」。緩存
該問題是經過使用QueryMatcher以及一個ColumnTracker解決的。在讀取全部的存儲文件以找到一個匹配的記錄以前,可能會有一個快速的排除檢查,可使用時間戳或者Bloom filter來跳過那些確定不包含該記錄的存儲文件。而後,對剩餘的存儲文件進行掃描以找到匹配該key的記錄。服務器
爲什麼Gets即Scans網絡
在HBase以前的版本中,Get方法的確是單獨實現的。最近的版本進行了改變,目前它內部已經和Scan API使用相同的源代碼。
你可能會很奇怪,按理來講一個簡單的Get應該比Scan快的。把它們區分對待,更容易針對Get進行某些優化。實際上這是由HBase自己架構致使的,內部沒有任何的索引文件來支持對於某個特定的行或列的直接訪問。最小的訪問單元就是HFile中的一個block,爲了找到被請求的數據,RegionServer代碼和它的底層Store實例必須load那些可能包含該數據的blocks而後進行掃描。實際上這就是Scan的操做過程。換句話說,Get本質上就是對單個行的Scan,就是一個從start row到start row+1的scan。
Scan是經過RegionScanner類實現的,它會每一個Store實例(每一個表明一個column family)執行StoreScanner檢索,若是讀操做沒有包含某個column family,那麼它的Store實例就會被略過。
StoreScanner會合並它所包含的存儲文件和memstore。同時這也是根據Bloomfilter或者時間戳進行排除性檢查的時候,而後你能夠跳過那些不須要的存儲文件。參見the section called 「Key Design」瞭解排除性檢查的細節,以及如何利用它。
同時也是由StoreScanner持有QueryMatcher(這裏是ScanQueryMatcher類)。它會記錄下那些包含在最終結果中的KeyValue。
RegionScanner內部會使用一個KeyValueHeap類來按照時間戳順序安排全部的Store scanners。StoreScanner也會採用相同的方式來對存儲文件進行排序。這就保證了用戶能夠按照正確的順序進行KeyValue的讀取(好比根據時間戳的降序)。
在store scanners被打開時,它們會將本身定位到請求的row key處。準備進行數據讀取。
Figure 8.10. Rows are stored and scanned across different stores, on-disk or in-memory
|
對於一個get()調用,全部的服務器須要作的就是調用RegionScanner的next()。該調用內部會讀取組成結果的全部內容。包括全部請求的版本,假設某列有三個版本,同時用戶請求檢索它們中全部的。這三個KeyValue可能分佈在磁盤或內存中的存儲文件。Next()調用會從全部的存儲文件中讀取直到讀到下一行,或者直到讀到足夠的版本。
與此同時,它也會記錄那些刪除標記。當它掃描當前行的KeyValue時,可能會碰到這些刪除標記,那些時間戳小於等於該刪除標記的記錄都會被認爲是已經清除掉了。
圖中展現了一個由一系列KeyValue組成的邏輯行,某些存儲在相同的存儲文件中,某些在其餘文件上,包含了多個column family。因爲時間戳或者Bloom filter的排除過程,某些存儲文件和memstore可能會被跳過。最後一個存儲文件中的刪除標記可能會遮蔽掉全部的記錄,可是它們仍然是同一行的一部分。這些scanners—實際上能夠用一系列指向存儲文件的箭頭表示—要麼指向文件中的第一個匹配點,要麼是緊挨着所請求的key的那個點(若是沒有直接匹配的點的話)。
在執行next調用時,只有那些具備匹配點的scanners纔會被考慮。內部循環會從第一個存儲文件到最後一個存儲文件,按照時間地降序一個挨一個地讀取其中的KeyValue,直到超出當前請求的key。
對於scan操做,則是經過在ResultScanner上不斷的調用next(),直到碰到表的結束行或者爲當前的batch讀取了足夠多的行時。
最終的結果是一個匹配了給定的get或者scan操做的KeyValue的列表。它會被髮送給客戶端,客戶端就可使用API函數來訪問裏面的列。
爲了讓客戶端可以找到持有特定的row key range的region server,HBase提供了兩個特殊的元數據表:-ROOT-和.META.。
-ROOT-表用於保存.META.表的全部regions的信息。HBase認爲只有一個root region,同時它永不會被split,這樣就能夠保證一個三層的類B+樹查找模式:第一層是存儲在ZooKeeper上的一個保存了root 表的region信息的節點,換句話說就是保存了root region的那個region server的名稱。第二層須要到-ROOT-表中查找匹配的meta region,而後第三層就是到.META.表中檢索用戶表的region信息。
元數據表中的row key由每一個region的表名,起始行,及一個ID(一般使用當前時間,單位是毫秒)。從HBase 0.90.0開始,這些key可能會有一個額外的與之關聯的hash值。目前只是用於用戶表中。
注:Bigtable論文指出,在.META.表的region大小限制在128MB的狀況下,它能夠尋址2^34個regions,若是按每一個region 128MB大小算,就是2^61字節大小。由於region大小能夠增長而不會影響到定位模式,所以根據須要這個值還能夠增大。
儘管客戶端會緩存region位置信息,可是客戶端在首次查詢時都須要發送請求來查找特定row key或者一個region也可能會被split,merge或者移動,這樣cache可能會無效。客戶端庫採用一種遞歸的方式逐層向上地找到當前的信息。它會詢問與給定的row key匹配的.META.表region所屬的region server地址。若是信息是無效的,它就退回到上層詢問root表對應的.META. region的位置。最後,若是也失敗了,它就須要讀取Zookeeper節點以找到root表region的位置。
最壞狀況下,將會須要6次網絡傳輸才能找到用戶region,由於無效記錄只有當查找失敗時才能發現出來,固然系統假設這種狀況並不常常發生。在緩衝爲空的狀況下,客戶端須要三次網絡傳輸來完成緩存更新。一種下降這種網絡傳輸次數的方法是對位置信息進行預取,提早更新客戶端緩存。具體細節見the section called 「Miscellaneous Features」。
Figure 8.11. Starting with an empty cache, the client has to do three lookups.
一旦用戶表region已知以後,客戶端就能夠直接訪問而不須要進一步的查找。圖中對查找進行了標號,同時假設緩存是空的。
2.1. Region生命週期
Region的狀態會被master追蹤,經過使用AssignmentManager類。它會記下region從offline狀態開始的整個生命週期。表8.1列出了一個region的全部可能狀態。
Table 8.1. Possible states of a region
State |
Description |
Offline |
The region is offline. |
Pending Open |
A request to open the region was sent to the server. |
Opening |
The server has started opening the region. |
Open |
The region is open and fully operational. |
Pending Close |
A request to close the region has been sent to the server. |
Closing |
The server is in the process of closing the region. |
Closed |
The region is closed. |
Splitting |
The server started splitting the region. |
Split |
The region has been split by the server. |
狀態間的轉換多是由master引發,也多是由持有它的那個region server引發。好比master可能將region分配給某個server,以後它會由該server打開。另外一方面,region server可能會啓動split過程,這會觸發region打開和關閉事件。
因爲這些事件自己的分佈式屬性,服務器使用ZooKeeper在一個專門的znode中記錄各類狀態。
從0.20.x開始,HBase使用ZooKeeper做爲它的分佈式協調服務。包括region servers的追蹤,root region的位置及其餘一些方面。0.90.x版引入了新的master實現,與ZooKeeper有了更緊密的集成。它使得HBase能夠去除掉master和region servers之間發送的心跳信息。這些如今都經過ZooKeeper完成了,當其中的某一部分發生變化時就會進行通知,而以前是經過固定的週期性檢查完成。
HBase會在它的根節點下建立一系列的znodes。根節點默認是」/hbase」,能夠經過zookeeper.znode.parent進行配置。下面是所包含的znodes節點列表及其功用:
注:下面的例子使用了ZooKeeper命令行接口(簡稱CLI)來運行這些命令。能夠經過以下命令啓動CLI:
$ $ZK_HOME/bin/zkCli.sh -server <quorum-server>
/hbase/hbaseid
包含了集羣ID,跟存儲在HDFS上的
hbase.id
文件中的一致. 以下:
[zk: localhost(CONNECTED) 1] get /hbase/hbaseid
e627e130-0ae2-448d-8bb5-117a8af06e97
/hbase/master
包含了服務器名稱, (具體參見the section called 「Cluster Status Information」 ). 以下:
[zk: localhost(CONNECTED) 2] get /hbase/master
foo.internal,60000,1309859972983
/hbase/replication
包含了replication的細節信息。相關細節參見 the section called 「Internals」。
/hbase/root-region-server
包含了持有
-ROOT-
regions 的region server的服務器名稱。在region查找過程當中會用到它 (見 the section called 「Region Lookups」). 以下:
[zk: localhost(CONNECTED) 3] get /hbase/root-region-server
rs1.internal,60000,1309859972983
/hbase/rs
做爲全部region servers的根節點,會記錄它們是什麼時候啓動。用來追蹤服務器的失敗。每一個內部的znode節點是臨時性的,以它所表明的region server的服務器名稱爲名。好比:
[zk: localhost(CONNECTED) 4] ls /hbase/rs
[rs1.internal,60000,1309859972983,rs2.internal,60000,1309859345233] /hbase/shutdown
該節點用於追蹤集羣狀態。包含集羣啓動時間,當集羣關閉時其內容爲空。好比:
[zk: localhost(CONNECTED) 5] get /hbase/shutdown
Tue Jul 05 11:59:33 CEST 2011 /hbase/splitlog
用於全部log splitting相關協調的parent znode, 細節詳見 the section called 「Log Splitting」 。好比:
[zk: localhost(CONNECTED) 6] ls /hbase/splitlog
[hdfs%3A%2F%2Flocalhost%2Fhbase%2F.logs%2Ffoo.internal%2C60020%2C \
1309850971208%2Ffoo.internal%252C60020%252C1309850971208.1309851636647,
hdfs%3A%2F%2Flocalhost%2Fhbase%2F.logs%2Ffoo.internal%2C60020%2C \
1309850971208%2Ffoo.internal%252C60020%252C1309850971208.1309851641956,
...
hdfs%3A%2F%2Flocalhost%2Fhbase%2F.logs%2Ffoo.internal%2C60020%2C \
1309850971208%2Ffoo.internal%252C60020%252C1309850971208.1309851784396]
[zk: localhost(CONNECTED) 7] get /hbase/splitlog/ \
\hdfs%3A%2F%2Flocalhost%2Fhbase%2F.logs%2Fmemcache1.internal%2C \ 60020%2C1309850971208%2Fmemcache1.internal%252C60020%252C1309850971208. \ 1309851784396
unassigned foo.internal,60000,1309851879862
[zk: localhost(CONNECTED) 8] get /hbase/splitlog/ \ \hdfs%3A%2F%2Flocalhost%2Fhbase%2F.logs%2Fmemcache1.internal%2C \ 60020%2C1309850971208%2Fmemcache1.internal%252C60020%252C1309850971208. \
1309851784396
owned foo.internal,60000,1309851879862
[zk: localhost(CONNECTED) 9] ls /hbase/splitlog [RESCAN0000293834, hdfs%3A%2F%2Flocalhost%2Fhbase%2F.logs%2Fmemcache1. \
internal%2C60020%2C1309850971208%2Fmemcache1.internal%252C \
60020%252C1309850971208.1309851681118, RESCAN0000293827, RESCAN0000293828, \
RESCAN0000293829, RESCAN0000293838, RESCAN0000293837]
這些例子列出了不少東西:你能夠看到一個未被分配的log是如何被split的,以後又如何被一個region server所擁有。"RESCAN"節點表示那些workers,好比萬一log split失敗後可能被用於進一步的工做的region server。
/hbase/table
當一個表被禁用時,它會被添加到該節點下. 表名就是新建立的znode的名稱,內容就是"DISABLED"。好比:
[zk: localhost(CONNECTED) 10] ls /hbase/table
[testtable]
[zk: localhost(CONNECTED) 11] get /hbase/table/testtable
DISABLED /hbase/unassigned
該znode是由 AssignmentManager 用來追蹤整個集羣的region狀態的。它包含了那些未被打開或者處於過渡狀態的regions對應的znodes,zodes的名稱就是該region的hash。好比:
[zk: localhost(CONNECTED) 11] ls /hbase/unassigned
[8438203023b8cbba347eb6fc118312a7]
HBase replication是在不一樣的HBase部署之間拷貝數據的一種方式。它能夠做爲一種災難恢復解決方案,也能夠用於提供HBase層的更高的可用性。同時它也能提供一些更實用的東西:好比,能夠做爲從面向web的集羣中拷貝最新的更新內容到MapReduce集羣的簡單方式,而後利用MapReduce集羣對新老數據進行處理再自動地返回結果。
HBase replication採用的基本架構模式是:master-push;由於每一個region server都有本身的write-ahead-log(即WAL或HLog),這樣就很容易記錄下從上次複製以後又發生了什麼,很是相似於其餘一些著名的解決方案,就像MySQL 的主從複製就只用了一個binary log來進行追蹤。一個master集羣能夠向任意數目的slave集羣進行復制,同時每一個region server會參與複製它自己所對應的一系列的修改。
Replication是異步進行的,這意味着參與的集羣可能在地理位置上相隔甚遠,它們之間的鏈接能夠在某段時間內是斷開的,插入到master集羣中的那些行,在同一時間在slave集羣上不必定是可用的(最終一致性)。
在該設計中所採用的replication格式在原理上相似於MySQL的基於狀態的replication。在這裏,不是SQL語句,而是整個的WALEdits(由來自客戶端的put和delete操做的多個cell inserts組成)會被複制以維持原子性。
每一個region server的HLogs是HBase replication的基礎,同時只要這些logs須要複製到其餘的slave集羣上,它們就須要保存在HDFS上。每一個RS會從它們須要複製的最老的log開始讀取,同時爲簡化故障恢復會將當前讀取位置保存到ZooKeeper上。對於不一樣的slave集羣來講,該位置多是不一樣的。參與replication各集羣大小可能不是對稱的,同時master集羣會經過隨機化來儘可能保證在slave集羣上的replication工做流的平衡。
Figure 8.12. Overview on the replication architecture
下面的幾節裏會描述下來自客戶端的一個edit從與master集羣通訊開始到到達另外一個slave集羣的整個生命歷程。
客戶端會使用HBase API將Put,Delete和Increment發送給region server。Key values會被region server轉換爲一個WALEdit對象。該edit對象會被append到當前的WAL上,同時以後會被apply到它的MemStore中。
經過一個獨立的線程,將該edit對象從log中讀出而後只保留那些須要複製的KeyValues(也就是說只保留那些在family schema中只屬於GLOBAL做用域的family的成員,同時是非元數據也就是非.META和-ROOT-)。當buffer被填滿或者讀取者讀到文件末尾後,該buffer會被隨機發送到slave集羣上的某個region server上。region server順序地接受讀到的這些edits,同時將它們按照table放到不一樣的buffers中。一旦全部的edits讀取完畢,全部的buffer就會經過正常的HBase客戶端進行flush。
回頭再看master集羣的region server,當前複製到的WAL偏移位置會註冊到ZooKeeper上。
4.1.2. Non-responding Slave Clusters
Edit會以一樣的方式進行插入。在獨立的線程中,region server像正常處理過程那樣進行讀取,過濾以及對log edits進行緩存。假設如今所聯繫的那個slave集羣的region server再也不響應RPC了,這樣master集羣的region server會進行休眠而後等待一個配置好的時間段後再進行重試。若是slave集羣的region server仍然沒有響應,master集羣的region server就會從新選擇一個要複製到的region server子集,而後會從新嘗試發送緩存的那些edits。
與此同時,WALs將會進行切換同時會被存儲在ZooKeeper的一個隊列中。那些被所屬的region server歸檔(歸檔過程基本上就是把一個日誌從它所屬的region server的目錄下移到一箇中央的logs歸檔目錄下)了的日誌會更新它們在複製線程的內存隊列中的路徑信息。
當slave集羣最終可用後,處理方式就又跟正常處理流程一致了。Master集羣的region server就又開始進行以前積壓的日誌的複製了。
本節會深刻描述下replication的內部操做機制。
當一個master集羣的region server開始做爲某個slave集羣的複製源以後,它首先會經過給定的集羣key聯繫slave集羣的ZooKeeper。
該key由以下部分組成:
hbase.zookeeper.quorum
zookeeper.znode.parent
hbase.zookeeper.property.clientPort。
以後,它會掃描/hbase/rs目錄以找到全部可用的sinks(即那些可用接收用於複製的edits數據流的region servers)同時根據配置的比率(默認是10%)來選出它們中的一個子集。好比若是slave集羣有150臺機器,那麼將會有15臺選定爲master集羣的region server將要發送的edits的接受者。由於複製過程當中,master的全部region server都會進行,這樣這些slave集羣的region server的負載就可能會很高,同時該方法適用於各類大小的集羣。好比,一個具備10臺機器的master集羣向一個具備10%比率的5臺集羣的slave集羣進行復制。意味着master集羣的region servers每次都會隨機選擇一臺機器,這樣slave集羣的重疊和總的使用率仍是很高的。
每一個master集羣的region server在replication znodes體系中都有本身的節點。同時節點下針對每一個集羣節點還會有一個znode(若是有5個slave集羣,就會有5個znode建立出來),每一個znode下又包含一個待處理的HLogs隊列。這些隊列是用來追蹤由該region server建立的HLogs的,這些隊列的大小可能有所不一樣。好比,若是某個slave集羣某段時間不可用,那麼這段時間的HLogs就不能被刪除,所以它們就得呆在隊列裏(而其餘的可能已經處理過了)。具體例子能夠參考:the section called 「Region Server Failover」。
當一個source被實例化時,它會包含region server當前正在寫入的HLog。在log切換時,新的文件在可用以前就會被添加到每一個slave集羣的znode的隊列中。這可讓全部的sources在該HLog能夠append edits以前就可以知道一個新log已經存在了,可是該操做的開銷目前是很昂貴的。當replication線程沒法從文件中讀出更多的記錄以後(由於它已經讀到了最後一個block),就會將它從隊列中刪除,此時要求隊列中的還有其餘文件存在{!還有其餘文件存在就意味着這個文件是一個已經寫完的日誌文件,而不是正在寫入的那個}。這就意味着若是一個source已經是最新狀態,同時複製進程已經到了region server正在寫入的那個log,那麼即便讀到了當前文件的」end」部分,也不能將它從隊列中刪除{!若是該文件正在被寫入,那麼即便讀到了末尾,也不能認爲它已經結束}。
當一個log被歸檔後(由於它再也不被使用或者是由於插入速度超過了region flushing的速度致使當前log文件數超過了hbase.regionserver.maxlogs的限制),它會通知source線程該log的路徑已經發生改變。若是某個source已經處理完該log,會忽略該消息。若是它還在隊列中,該路徑會更新到相應的內存中。若是該log目前正在被複制,該變動會自動完成,讀取者不須要從新打開該被移動的文件。由於文件的移動只是一個NameNode操做,若是讀取者當前正在讀取該log文件,它不會產生任何異常。
默認狀況下,一個source會盡可能地讀取日誌文件而後將日誌記錄儘快地發送給一個sink。可是首先它須要對log記錄進行過濾;只有那些具備GLOBAL做用域同時不屬於元數據表的KeyValues才能保留下來。第二個限制是,附加在每一個slave集羣上所能複製的edits列表的大小限制,默認是64MB。這意味着一個具備三個slave集羣的master集羣的region server最多隻能使用192MB來存儲被複制的數據。
一旦緩存的edits大小達到上限或者讀取者讀到了log文件末尾,source線程將會中止讀取而後隨機選擇一個sink進行復制。它會對選定的集羣直接產生一個RPC調用,而後等待該方法返回。若是成功返回,source會判斷當前的文件是否已經讀完或者仍是繼續從裏面讀。若是是前者,它會將它從znode的隊列中刪除。若是是後者,它會在該log的znode中註冊一個新的offset。若是PRC拋出了異常,該source在尋找另外一個sink以前會重試十次。
若是replication沒有開啓,master的logs清理線程將會使用用戶配置的TTL進行舊logs的刪除。當使用replication時,這樣是沒法工做的,由於被歸檔的log雖然超過了它們本身的TTL可是仍可能在隊列中。所以,須要修改默認行爲,在日誌超出它的TTL時,清理線程還要查看每一個隊列看可否找到該log,若是找不到就能夠將該log刪除。查找過程當中它會緩存它找到的那些log,在下次log查找時,它會首先查看緩存。
只要region servers沒有出錯,ZooKeeper中的日誌記錄就不須要添加任何值。不幸的是,它們一般都會出錯,這樣咱們就能夠藉助ZooKeeper的高可用性和它的語義來幫助咱們管理隊列的傳輸。
master集羣的全部region servers相互之間都有一個觀察者,當其中一個死掉時,其餘的都能獲得通知。若是某個死掉後,它們就會經過在死掉的region server的znode(該znode也包含它的隊列)內建立一個稱爲lock的znode來進行競爭性選舉。最終成功建立了該znode的region server會將全部的隊列傳輸到它本身的znode下(逐個傳輸由於ZooKeeper並不支持rename操做)當傳輸完成後就會刪掉老的那些。恢復後的隊列的znodes將會在死掉的服務器的名稱後加上slave集羣的id來進行命名。
完成以後,master集羣的region server會對每一個拷貝出的隊列建立一個新的source線程。它們中的每個都會遵照read/filter/ship模式。主要的區別是這些隊列不會再有新數據由於它們再也不屬於它們的新region server,同時意味着當讀取者到達最後一個日誌的末尾時,隊列對應的znode就能夠被刪除了,同時master集羣的region server將會關閉那個replication source。
好比,考慮一個具備3個region servers的master集羣,該集羣會向一個id爲2的單個slave集羣進行復制。下面的層次結構表明了znodes在某個時間點上的分佈。咱們能夠看到該region servers的znodes都包含一個具備一個隊列的peers znode。這些隊列的znodes的在HDFS上的實際文件名稱具備以下形式」 address,port.timestamp」。
/hbase/replication/rs/
1.1.1.1,60020,123456780/
peers/
2/
1.1.1.1,60020.1234 (Contains a position)
1.1.1.1,60020.1265
1.1.1.2,60020,123456790/
peers/
2/
1.1.1.2,60020.1214 (Contains a position)
1.1.1.2,60020.1248
1.1.1.2,60020.1312
1.1.1.3,60020, 123456630/
peers/
2/
1.1.1.3,60020.1280 (Contains a position)
如今咱們假設1.1.1.2丟失了它的ZK會話,倖存者將會競爭以建立一個lock,最後1.1.1.3得到了該鎖。而後它開始將全部隊列傳輸到它本地的peers znode,同時在原有的名稱上填上死掉的服務器的名稱。在1.1.1.3清理老的znodes以前,節點分佈以下:
/hbase/replication/rs/
1.1.1.1,60020,123456780/
peers/
2/
1.1.1.1,60020.1234 (Contains a position)
1.1.1.1,60020.1265
1.1.1.2,60020,123456790/
lock
peers/
2/
1.1.1.2,60020.1214 (Contains a position)
1.1.1.2,60020.1248
1.1.1.2,60020.1312
1.1.1.3,60020,123456630/
peers/
2/
1.1.1.3,60020.1280 (Contains a position)
2-1.1.1.2,60020,123456790/
1.1.1.2,60020.1214 (Contains a position)
1.1.1.2,60020.1248
1.1.1.2,60020.1312
一段時間後,但在1.1.1.3結束來自1.1.1.2的最後一個HLog的複製以前,咱們假設它也死掉了(並且某些以前建立的新logs還在正常隊列中)。最後一個region server會嘗試鎖住1.1.1.3的znode而後開始傳輸全部的隊列。新的節點分佈以下:
/hbase/replication/rs/
1.1.1.1,60020,123456780/
peers/
2/
1.1.1.1,60020.1378 (Contains a position)
2-1.1.1.3,60020,123456630/
1.1.1.3,60020.1325 (Contains a position)
1.1.1.3,60020.1401
2-1.1.1.2,60020,123456790-1.1.1.3,60020,123456630/
1.1.1.2,60020.1312 (Contains a position)
1.1.1.3,60020,123456630/
lock
peers/
2/
1.1.1.3,60020.1325 (Contains a position)
1.1.1.3,60020.1401
2-1.1.1.2,60020,123456790/
1.1.1.2,60020.1312 (Contains a position)
Replication 目前仍是一個處於實驗階段的feature。在將它應用到你的使用場景中時須要進行仔細地評估。
[83] See "B+ trees" on Wikipedia
[84] See LSM-Tree, O'Neil et al., 1996
[85] From "Open Source Search" by Doug Cutting, Dec. 05, 2005.
[86] See the JIRA issue HADOOP-3315 for details.
[87] For the term itself please read Write-Ahead Logging on Wikipedia.
[88] Subsequently they are referred to interchangeably as root table and meta table respectively, since for example
"-ROOT-"
is how the table is actually named in HBase and calling it root table is stating its purpose.