一條數(shù)據(jù)HBase之旅,簡明HBase入門教程-Write全流程

      網(wǎng)友投稿 998 2022-05-29

      本文整體思路:

      1. 前文內(nèi)容回顧

      2. 示例數(shù)據(jù)

      3. HBase可選接口介紹

      4. 表服務(wù)接口介紹

      5. 介紹幾種寫數(shù)據(jù)的模式

      6. 如何構(gòu)建Put對象(含RowKey定義以及列定義)

      7. 數(shù)據(jù)路由

      8. Client側(cè)的分組打包

      9. Client發(fā)RPC請求到RegionServer

      10. 安全訪問控制

      11. RegionServer側(cè)處理:Region分發(fā)

      12. Region內(nèi)部處理:寫WAL

      13. Region內(nèi)部處理:寫MemStore

      為了保證"故事"的完整性,導(dǎo)致本文篇幅過長,非常抱歉,讀者可以按需跳過不感興趣的內(nèi)容。

      前文內(nèi)容回顧

      上篇文章《一條數(shù)據(jù)的HBase之旅,簡明HBase入門教程-開篇》主要介紹了如下內(nèi)容:

      HBase項目概況(搜索引擎熱度/社區(qū)開發(fā)活躍度)

      HBase數(shù)據(jù)模型(RowKey,稀疏矩陣,Region,Column Family,KeyValue)

      基于HBase的數(shù)據(jù)模型,介紹了HBase的適合場景(以實體/事件為中心的簡單結(jié)構(gòu)的數(shù)據(jù))

      介紹了HBase與HDFS的關(guān)系,集群關(guān)鍵角色以及部署建議

      寫數(shù)據(jù)前的準(zhǔn)備工作:建立連接,建表

      示例數(shù)據(jù)

      (上篇文章已經(jīng)提及,這里再復(fù)制一次的原因,一是為了讓下文內(nèi)容更容易理解,二是個別字段名稱做了調(diào)整)

      給出一份我們?nèi)粘6伎梢越佑|到的數(shù)據(jù)樣例,先簡單給出示例數(shù)據(jù)的字段定義:

      本文力求簡潔,僅給出了最簡單的幾個字段定義。如下是"虛構(gòu)"的樣例數(shù)據(jù):

      在本文大部分內(nèi)容中所涉及的一條數(shù)據(jù),是上面加粗的最后一行"Mobile1"為"13400006666"這行記錄。在下面的流程圖中,我們使用下面這樣一個紅色小圖標(biāo)來表示該數(shù)據(jù)所在的位置:

      可選接口

      HBase中提供了如下幾種主要的接口:

      Java Client API

      HBase的基礎(chǔ)API,應(yīng)用最為廣泛。

      HBase Shell

      基于Shell的命令行操作接口,基于Java Client API實現(xiàn)。

      Restful API

      Rest Server側(cè)基于Java Client API實現(xiàn)。

      Thrift API

      Thrift Server側(cè)基于Java Client API實現(xiàn)。

      MapReduce Based Batch Manipulation API

      基于MapReduce的批量數(shù)據(jù)讀寫API。

      除了上述主要的API,HBase還提供了基于Spark的批量操作接口以及C++ Client接口,但這兩個特性都被規(guī)劃在了3.0版本中,當(dāng)前尚在開發(fā)中。

      無論是HBase Shell/Restful API還是Thrift API,都是基于Java Client API實現(xiàn)的。因此,接下來關(guān)于流程的介紹,都是基于Java Client API的調(diào)用流程展開的。

      關(guān)于表服務(wù)接口

      同步連接與異步連接,分別提供了不同的表服務(wù)接口抽象:

      Table 同步連接中的表服務(wù)接口定義

      AsyncTable 異步連接中的表服務(wù)接口定義

      異步連接AsyncConnection獲取AsyncTable實例的接口默認(rèn)實現(xiàn):

      同步連接ClusterConnection的實現(xiàn)類ConnectionImplementation中獲取Table實例的接口實現(xiàn):

      寫數(shù)據(jù)的幾種方式

      Single Put

      單條記錄單條記錄的隨機put操作。Single Put所對應(yīng)的接口定義如下:

      在AsyncTable接口中的定義:

      在Table接口中的定義:

      Batch Put

      匯聚了幾十條甚至是幾百上千條記錄之后的小批次隨機put操作。

      Batch Put只是本文對該類型操作的稱法,實際的接口名稱如下所示:

      在AsyncTable接口中的定義:

      在Table接口中的定義:

      Bulkload

      基于MapReduce API提供的數(shù)據(jù)批量導(dǎo)入能力,導(dǎo)入數(shù)據(jù)量通常在GB級別以上,Bulkload能夠繞過Java Client API直接生成HBase的底層數(shù)據(jù)文件(HFile),因此性能非常高。

      構(gòu)建Put對象

      設(shè)計合理的RowKey

      RowKey通常是一個或若干個字段的直接組合或經(jīng)一定處理后的信息,因為一個表中所有的數(shù)據(jù)都是基于RowKey排序的,RowKey的設(shè)計對讀寫都會有直接的性能影響。

      我們基于本文的樣例數(shù)據(jù),先給出兩種RowKey的設(shè)計,并簡單討論各自的優(yōu)缺點:

      樣例數(shù)據(jù):

      RowKey Format 1: Mobile1 + StartTime

      為了方便讀者理解,我們在兩個字段之間添加了連接符"^"。如下是RowKey以及相關(guān)排序結(jié)果:

      RowKey Format 2: StartTime + Mobile1

      從上面兩個表格可以看出來,不同的字段組合順序設(shè)計,帶來截然不同的排序結(jié)果,我們將RowKey中的第一個字段稱之為"先導(dǎo)字段"。第一種設(shè)計,有利于查詢"手機號碼XXX的在某時間范圍內(nèi)的數(shù)據(jù)記錄",但不利于查詢"某段時間范圍內(nèi)有哪些手機號碼撥出了電話?",而第二種設(shè)計卻恰好相反。

      上面是兩種設(shè)計都是兩個字段的直接組合,這種設(shè)計在實際應(yīng)用中,會帶來讀寫熱點問題,難以保障數(shù)據(jù)讀寫請求在所有Regions之間的負(fù)載均衡。避免熱點的常見方法有如下幾種:

      Reversing

      如果先導(dǎo)字段本身會帶來熱點問題,但該字段尾部的信息卻具備良好的隨機性,此時,可以考慮將先導(dǎo)字段做反轉(zhuǎn)處理,將尾部幾位直接提前到前面,或者直接將整個字段完全反轉(zhuǎn)。

      將先導(dǎo)字段Mobile1翻轉(zhuǎn)后,就具備非常好的隨機性。

      例如:

      13400001111^201803010800

      將先導(dǎo)字段Mobile1反轉(zhuǎn)后的RowKey變?yōu)椋?/p>

      11110000431^201803010800

      Salting

      Salting的原理是在RowKey的前面添加固定長度的隨機Bytes,隨機Bytes能保障數(shù)據(jù)在所有Regions間的負(fù)載均衡。

      Salting能很好的保障寫入時將數(shù)據(jù)均勻分散到各個Region中,但對于讀取卻是不友好的,例如,如果讀取Mobile1為"13400001111"在20180301這一天的數(shù)據(jù)記錄時,因為Salting Bytes信息是隨機選擇添加的,查詢時并不知道前面添加的Salting Bytes是"A",因此{(lán)“A”, “B”, “C”}所關(guān)聯(lián)的Regions都得去查看一下是否有所需的數(shù)據(jù)。

      Hashing

      Hashing是將一個RowKey通過一個Hash函數(shù)生成一組固定長度的bytes,Hash函數(shù)能保障所生成的隨機bytes具備良好的離散度,從而也能夠均勻打散到各個Region中。Hashing既有利于隨機寫入,又利于基于知道RowKey各字段的確切信息之后的隨機讀取操作,但如果是基于RowKey范圍的Scan或者是RowKey的模糊信息進(jìn)行查詢的話,就會帶來顯著的性能問題,因為原來在字典順序相鄰的RowKey列表,通過Hashing打散后導(dǎo)致這些數(shù)據(jù)被分散到了多個Region中。

      因此,RowKey的設(shè)計,需要充分考慮業(yè)務(wù)的讀寫特點。

      本文內(nèi)容假設(shè)RowKey設(shè)計:reversing(Mobile1) +StartTime

      也就是說,RowKey由反轉(zhuǎn)處理后的Mobile1與StartTime組成。對于我們所關(guān)注的這行數(shù)據(jù):

      RowKey應(yīng)該為:?66660000431^201803011300

      因為創(chuàng)建表時預(yù)設(shè)的Region與RowKey強相關(guān),我們現(xiàn)在才可以給出本文樣例所需要創(chuàng)建的表的"Region分割點"信息:

      假設(shè),Region分割點為"1,2,3,4,5,6,7,8,9",基于這9個分割點,可以預(yù)先創(chuàng)建10個Region,這10個Region的StartKey和StopKey如下所示:

      第一個Region的StartKey為空,最后一個Region的StopKey為空

      每一個Region區(qū)間,都包含StartKey本身,但不包含StopKey

      由于Mobile1字段的最后一位是0~9之間的隨機數(shù)字,因此,可以均勻打散到這10個Region中

      定義列

      每一個列在HBase中體現(xiàn)為一個KeyValue,而每一個KeyValue擁有特定的組成結(jié)構(gòu),這一點在上一篇文章中的數(shù)據(jù)模型章節(jié)部分已經(jīng)提到過。

      所謂的定義列,就是需要定義出每一個列要存放的列族(Column Family)以及列標(biāo)識(Qualifier)信息。

      我們假設(shè),存放樣例數(shù)據(jù)的這個表名稱為"TelRecords",為了簡單起見,僅僅設(shè)置了1個名為"I"的列族。

      因為Mobile1與StartTime都已經(jīng)被包含在RowKey中,所以,不需要再在列中存儲一份。關(guān)于列族名稱與列標(biāo)識名稱,建議應(yīng)該簡短一些,因為這些信息都會被包含在KeyValue里面,過長的名稱會導(dǎo)致數(shù)據(jù)膨脹。

      基于RowKey和列定義信息,就可以組建HBase的Put對象,一個Put對象用來描述待寫入的一行數(shù)據(jù),一個Put可以理解成與某個RowKey關(guān)聯(lián)的1個或多個KeyValue的集合。

      至此,這條數(shù)據(jù)已經(jīng)轉(zhuǎn)變成了Put對象,如下圖所示:

      數(shù)據(jù)路由

      初始化ZooKeeper Session

      因為meta Region的路由信息存放于ZooKeeper中,在第一次從ZooKeeper中讀取META Region的地址時,需要先初始化一個ZooKeeper Session。ZooKeeper Session是ZooKeeper Client與ZooKeeper Server端所建立的一個會話,通過心跳機制保持長連接。

      獲取Region路由信息

      通過前面建立的連接,從ZooKeeper中讀取meta Region所在的RegionServer,這個讀取流程,當(dāng)前已經(jīng)是異步的。獲取了meta Region的路由信息以后,再從meta Region中定位要讀寫的RowKey所關(guān)聯(lián)的Region信息。如下圖所示:

      因為每一個用戶表Region都是一個RowKey Range,meta Region中記錄了每一個用戶表Region的路由以及狀態(tài)信息,以RegionName(包含表名,Region?StartKey,Region ID,副本ID等信息)作為RowKey。基于一條用戶數(shù)據(jù)RowKey,快速查詢該RowKey所屬的Region的方法其實很簡單:只需要基于表名以及該用戶數(shù)據(jù)RowKey,構(gòu)建一個虛擬的Region Key,然后通過Reverse Scan的方式,讀到的第一條Region記錄就是該數(shù)據(jù)所關(guān)聯(lián)的Region。如下圖所示:

      Region只要不被遷移,那么獲取的該Region的路由信息就是一直有效的,因此,HBase Client有一個Cache機制來緩存Region的路由信息,避免每次讀寫都要去訪問ZooKeeper或者meta Region。

      進(jìn)階內(nèi)容1:meta Region究竟在哪里?

      meta Region的路由信息存放在ZooKeeper中,但meta Region究竟在哪個RegionServer中提供讀寫服務(wù)?

      在1.0版本中,引入了一個新特性,使得Master可以"兼任"一個RegionServer角色(可參考HBASE-5487, HBASE-10569),從而可以將一些系統(tǒng)表的Region分配到Master的這個RegionServer中,這種設(shè)計的初衷是為了簡化/優(yōu)化Region Assign的流程,但這依然帶來了一系列復(fù)雜的問題,尤其是Master初始化和RegionServer初始化之間的Race,因此,在2.0版本中將這個特性暫時關(guān)閉了。詳細(xì)信息可以參考:HBASE-16367,HBASE-18511,HBASE-19694,HBASE-19785,HBASE-19828

      Client數(shù)據(jù)分組"打包"

      如果這條待寫入的數(shù)據(jù)采用的是Single Put的方式,那么,該步驟可以略過(事實上,單條Put操作的流程相對簡單,就是先定位該RowKey所對應(yīng)的Region以及RegionServer信息后,Client直接發(fā)送寫請求到RegionServer側(cè)即可)。

      但如果這條數(shù)據(jù)被混雜在其它的數(shù)據(jù)列表中,采用Batch Put的方式,那么,客戶端在將所有的數(shù)據(jù)寫到對應(yīng)的RegionServer之前,會先分組"打包",流程如下:

      按Region分組:遍歷每一條數(shù)據(jù)的RowKey,然后,依據(jù)meta表中記錄的Region信息,確定每一條數(shù)據(jù)所屬的Region。此步驟可以獲取到Region到RowKey列表的映射關(guān)系。

      按RegionServer"打包":因為Region一定歸屬于某一個RegionServer(注:本文內(nèi)容中如無特殊說明,都未考慮Region Replica特性),那屬于同一個RegionServer的多個Regions的寫入請求,被打包成一個MultiAction對象,這樣可以一并發(fā)送到每一個RegionServer中。

      Client發(fā)RPC請求到RegionServer

      類似于Client發(fā)送建表到Master的流程,Client發(fā)送寫數(shù)據(jù)請求到RegionServer,也是通過RPC的方式。只是,Client到Master以及Client到RegionServer,采用了不同的RPC服務(wù)接口。

      single put請求與batch put請求,兩者所調(diào)用的RPC服務(wù)接口方法是不同的,如下是Client.proto中的定義:

      安全訪問控制

      如何保障UserA只能寫數(shù)據(jù)到UserA的表中,以及禁止UserA改寫其它User的表的數(shù)據(jù),HBase提供了ACL機制。ACL通常需要與Kerberos認(rèn)證配合一起使用,Kerberos能夠確保一個用戶的合法性,而ACL確保該用戶僅能執(zhí)行權(quán)限范圍內(nèi)的操作。

      HBase將權(quán)限分為如下幾類:

      READ('R')

      WRITE('W')

      EXEC('X')

      CREATE('C')

      ADMIN('A')

      一條數(shù)據(jù)的HBase之旅,簡明HBase入門教程-Write全流程

      可以為一個用戶/用戶組定義整庫級別的權(quán)限集合,也可以定義Namespace、表、列族甚至是列級別的權(quán)限集合。

      RegionServer:Region分發(fā)

      RegionServer的RPC Server側(cè),接收到來自Client端的RPC請求以后,將該請求交給Handler線程處理。

      如果是single put,則該步驟比較簡單,因為在發(fā)送過來的請求參數(shù)MutateRequest中,已經(jīng)攜帶了這條記錄所關(guān)聯(lián)的Region,那么直接將該請求轉(zhuǎn)發(fā)給對應(yīng)的Region即可。

      如果是batch puts,則接收到的請求參數(shù)為MultiRequest,在MultiRequest中,混合了這個RegionServer所持有的多個Region的寫入請求,每一個Region的寫入請求都被包裝成了一個RegionAction對象。RegionServer接收到MultiRequest請求以后,遍歷所有的RegionAction,而后寫入到每一個Region中,此過程是串行的:

      從這里可以看出來,并不是一個batch越大越好,大的batch size甚至可能導(dǎo)致吞吐量下降。

      Region內(nèi)部處理:寫WAL

      HBase也采用了LSM-Tree的架構(gòu)設(shè)計:LSM-Tree利用了傳統(tǒng)機械硬盤的“順序讀寫速度遠(yuǎn)高于隨機讀寫速度”的特點。隨機寫入的數(shù)據(jù),如果直接去改寫每一個Region上的數(shù)據(jù)文件,那么吞吐量是非常差的。因此,每一個Region中隨機寫入的數(shù)據(jù),都暫時先緩存在內(nèi)存中(HBase中存放這部分內(nèi)存數(shù)據(jù)的模塊稱之為MemStore,這里僅僅引出概念,下一章節(jié)詳細(xì)介紹),為了保障數(shù)據(jù)可靠性,將這些隨機寫入的數(shù)據(jù)順序?qū)懭氲揭粋€稱之為WAL(Write-Ahead-Log)的日志文件中,WAL中的數(shù)據(jù)按時間順序組織:

      如果位于內(nèi)存中的數(shù)據(jù)尚未持久化,而且突然遇到了機器斷電,只需要將WAL中的數(shù)據(jù)回放到Region中即可:

      在HBase中,默認(rèn)一個RegionServer只有一個可寫的WAL文件。WAL中寫入的記錄,以Entry為基本單元,而一個Entry中,包含:

      WALKey?包含{Encoded Region Name,Table Name,Sequence ID,Timestamp}等關(guān)鍵信息,其中,Sequence ID在維持?jǐn)?shù)據(jù)一致性方面起到了關(guān)鍵作用,可以理解為一個事務(wù)ID。

      WALEdit?WALEdit中直接保存待寫入數(shù)據(jù)的所有的KeyValues,而這些KeyValues可能來自一個Region中的多行數(shù)據(jù)。

      也就是說,通常,一個Region中的一個batch put請求,會被組裝成一個Entry,寫入到WAL中:

      將Entry寫到文件中時是支持壓縮的,但該特性默認(rèn)未開啟。

      WAL進(jìn)階內(nèi)容

      WAL Roll and Archive

      當(dāng)正在寫的WAL文件達(dá)到一定大小以后,會創(chuàng)建一個新的WAL文件,上一個WAL文件依然需要被保留,因為這個WAL文件中所關(guān)聯(lián)的Region中的數(shù)據(jù),尚未被持久化存儲,因此,該WAL可能會被用來回放數(shù)據(jù)。

      如果一個WAL中所關(guān)聯(lián)的所有的Region中的數(shù)據(jù),都已經(jīng)被持久化存儲了,那么,這個WAL文件會被暫時歸檔到另外一個目錄中:

      注意,這里不是直接將WAL文件刪除掉,這是一種穩(wěn)妥且合理的做法,原因如下:

      避免因為邏輯實現(xiàn)上的問題導(dǎo)致WAL被誤刪,暫時歸檔到另外一個目錄,為錯誤發(fā)現(xiàn)預(yù)留了一定的時間窗口

      按時間維度組織的WAL數(shù)據(jù)文件還可以被用于其它用途,如增量備份,跨集群容災(zāi)等等,因此,這些WAL文件通常不允許直接被刪除,至于何時可以被清理,還需要額外的控制邏輯

      另外,如果對寫入HBase中的數(shù)據(jù)的可靠性要求不高,那么,HBase允許通過配置跳過寫WAL操作。

      思考:put與batch put的性能為何差別巨大?

      在網(wǎng)絡(luò)分發(fā)上,batch put已經(jīng)具備一定的優(yōu)勢,因為batch put是打包分發(fā)的。

      而從寫WAL這塊,看的出來,batch put寫入的一小批次Put對象,可以通過一次sync就持久化到WAL文件中了,有效減少了IOPS。

      但前面也提到了,batch size并不是越大越好,因為每一個batch在RegionServer端是被串行處理的。

      利用Disruptor提升寫并發(fā)性能

      在高并發(fā)隨機寫入場景下,會帶來大量的WAL Sync操作,HBase中采用了Disruptor的RingBuffer來減少競爭,思路是這樣:如果將瞬間并發(fā)寫入WAL中的數(shù)據(jù),合并執(zhí)行Sync操作,可以有效降低Sync操作的次數(shù),來提升寫吞吐量。

      Multi-WAL

      默認(rèn)情形下,一個RegionServer只有一個被寫入的WAL Writer,盡管WAL Writer依靠順序?qū)懱嵘龑懲掏铝浚诨谄胀C械硬盤的配置下,此時只能有單塊盤發(fā)揮作用,其它盤的IOPS能力并沒有被充分利用起來,這是Multi-WAL設(shè)計的初衷。Multi-WAL可以在一個RegionServer中同時啟動幾個WAL Writer,可按照一定的策略,將一個Region與其中某一個WAL Writer綁定,這樣可以充分發(fā)揮多塊盤的性能優(yōu)勢。

      關(guān)于WAL的未來

      WAL是基于機械硬盤的IO模型設(shè)計的,而對于新興的非易失性介質(zhì),如3D XPoint,WAL未來可能會失去存在的意義,關(guān)于這部分內(nèi)容,請參考文章《從HBase中移除WAL?3D XPoint技術(shù)帶來的變革》。

      Region內(nèi)部處理:寫MemStore

      每一個Column Family,在Region內(nèi)部被抽象為了一個HStore對象,而每一個HStore擁有自身的MemStore,用來緩存一批最近被隨機寫入的數(shù)據(jù),這是LSM-Tree核心設(shè)計的一部分。

      MemStore中用來存放所有的KeyValue的數(shù)據(jù)結(jié)構(gòu),稱之為CellSet,而CellSet的核心是一個ConcurrentSkipListMap,我們知道,ConcurrentSkipListMap是Java的跳表實現(xiàn),數(shù)據(jù)按照Key值有序存放,而且在高并發(fā)寫入時,性能遠(yuǎn)高于ConcurrentHashMap。

      因此,寫MemStore的過程,事實上是將batch put提交過來的所有的KeyValue列表,寫入到MemStore的以ConcurrentSkipListMap為組成核心的CellSet中:

      MemStore因為涉及到大量的隨機寫入操作,會帶來大量Java小對象的創(chuàng)建與消亡,會導(dǎo)致大量的內(nèi)存碎片,給GC帶來比較重的壓力,HBase為了優(yōu)化這里的機制,借鑒了操作系統(tǒng)的內(nèi)存分頁的技術(shù),增加了一個名為MSLab的特性,通過分配一些固定大小的Chunk,來存儲MemStore中的數(shù)據(jù),這樣可以有效減少內(nèi)存碎片問題,降低GC的壓力。當(dāng)然,ConcurrentSkipListMap本身也會創(chuàng)建大量的對象,這里也有很大的優(yōu)化空間,去年阿里的一篇文章透露了阿里如何通過優(yōu)化ConcurrentSkipListMap的結(jié)構(gòu)來有效降低GC時間。

      進(jìn)階內(nèi)容2:先寫WAL還是先寫MemStore?

      在0.94版本之前,Region中的寫入順序是先寫WAL再寫MemStore,這與WAL的定義也相符。

      但在0.94版本中,將這兩者的順序顛倒了,當(dāng)時顛倒的初衷,是為了使得行鎖能夠在WAL sync之前先釋放,從而可以提升針對單行數(shù)據(jù)的更新性能。詳細(xì)問題單,請參考HBASE-4528。

      在2.0版本中,這一行為又被改回去了,原因在于修改了行鎖機制以后(下面章節(jié)將講到),發(fā)現(xiàn)了一些性能下降,而HBASE-4528中的優(yōu)化卻無法再發(fā)揮作用,詳情請參考HBASE-15158。改動之后的邏輯也更簡潔了。

      進(jìn)階內(nèi)容3:關(guān)于行級別的ACID

      在之前的版本中,行級別的任何并發(fā)寫入/更新都是互斥的,由一個行鎖控制。但在2.0版本中,這一點行為發(fā)生了變化,多個線程可以同時更新一行數(shù)據(jù),這里的考慮點為:

      如果多個線程寫入同一行的不同列族,是不需要互斥的

      多個線程寫同一行的相同列族,也不需要互斥,即使是寫相同的列,也完全可以通過HBase的MVCC機制來控制數(shù)據(jù)的一致性

      當(dāng)然,CAS操作(如checkAndPut)或increment操作,依然需要獨占的行鎖

      更多詳細(xì)信息,可以參考HBASE-12751。

      至此,這條數(shù)據(jù)已經(jīng)被同時成功寫到了WAL以及MemStore中:

      總結(jié)

      本文主要內(nèi)容總結(jié)如下:

      介紹HBase寫數(shù)據(jù)可選接口以及接口定義。

      通過一個樣例,介紹了RowKey定義以及列定義的一些方法,以及如何組裝Put對象

      數(shù)據(jù)路由,數(shù)據(jù)分發(fā)、打包,以及Client通過RPC發(fā)送寫數(shù)據(jù)請求至RegionServer

      RegionServer接收數(shù)據(jù)以后,將數(shù)據(jù)寫到每一個Region中。寫數(shù)據(jù)流程先寫WAL再寫MemStore,這里展開了一些技術(shù)細(xì)節(jié)

      簡單介紹了HBase權(quán)限控制模型

      需要說明的一點,本文所講到的MemStore其實是一種"簡化"后的模型,在2.0版本中,這里已經(jīng)變的更加復(fù)雜,這些內(nèi)容將在下一篇介紹Flush與Compaction的流程中詳細(xì)介紹。

      相關(guān)閱讀

      一條數(shù)據(jù)的HBase之旅,簡明HBase入門教程-開篇

      致謝

      感謝Apache HBase PMC成員Ted Yu,李鈺,張鐸對本文中與2.0版本相關(guān)特性/流程方面描述內(nèi)容的Review,感謝鐘超強對全文內(nèi)容的Review。感謝畢美杰同學(xué)為本文提供的漂亮的封面圖片。

      本文轉(zhuǎn)載自微信公眾號【NoSql漫談】。

      NoSQL數(shù)據(jù)庫

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:相約HDC,感謝了不起的你
      下一篇:今天,四項可信云最佳實踐獎!
      相關(guān)文章
      亚洲网红精品大秀在线观看| 亚洲avav天堂av在线不卡| 亚洲人成在线电影| 亚洲AV中文无码乱人伦下载| 亚洲人成图片小说网站| 久久久久国产亚洲AV麻豆| 亚洲AV日韩综合一区| 亚洲国产成人综合精品| 亚洲av乱码中文一区二区三区| 亚洲日韩一区精品射精| 亚洲国产视频久久| 一本色道久久综合亚洲精品蜜桃冫 | 亚洲精品精华液一区二区| 亚洲一区AV无码少妇电影| 亚洲一卡2卡3卡4卡5卡6卡| 亚洲欧美不卡高清在线| 亚洲av午夜电影在线观看| 噜噜综合亚洲AV中文无码| 亚洲AV无码成人网站在线观看| 337P日本欧洲亚洲大胆艺术图| 国产成人亚洲毛片| 亚洲综合国产精品第一页| 久久影视国产亚洲| 亚洲成AV人片在线观看| 亚洲电影国产一区| 亚洲无圣光一区二区| ww亚洲ww在线观看国产| 456亚洲人成影院在线观| 亚洲熟妇AV一区二区三区宅男| 久久亚洲精品无码gv| 亚洲第一福利网站在线观看| 久久精品国产亚洲一区二区三区 | 337p欧洲亚洲大胆艺术| 亚洲人成电影在线观看网| 国产精品亚洲一区二区麻豆| 亚洲成在人线在线播放无码| xvideos亚洲永久网址| 亚洲中文字幕在线乱码| 亚洲av日韩av无码| 亚洲人成网站在线观看播放动漫| 亚洲最大福利视频|