一條數(shù)據(jù)的HBase之旅,簡明HBase入門教程-開篇
一些常見的HBase新手問題
- 什么樣的數(shù)據(jù)適合用HBase來存儲?
- 既然HBase也是一個數(shù)據(jù)庫,能否用它將現(xiàn)有系統(tǒng)中昂貴的Oracle替換掉?
- 存放于HBase中的數(shù)據(jù)記錄,為何不直接存放于HDFS之上?
- 能否直接使用HBase來存儲文件數(shù)據(jù)?
- Region(HBase中的數(shù)據(jù)分片)遷移后,數(shù)據(jù)是否也會被遷移?
- 為何基于Spark/Hive分析HBase數(shù)據(jù)時性能較差?
開篇
用慣了Oracle/MySQL的同學(xué)們,心目中的數(shù)據(jù)表,應(yīng)該是長成這樣的:
這種表結(jié)構(gòu)規(guī)整,每一行都有固定的列構(gòu)成,因此,非常適合結(jié)構(gòu)化數(shù)據(jù)的存儲。但在NoSQL領(lǐng)域,數(shù)據(jù)表的模樣卻往往換成了另外一種"畫風(fēng)":
行由看似"雜亂無章"的列組成,行與行之間也無須遵循一致的定義,而這種定義恰好符合半結(jié)構(gòu)化數(shù)據(jù)或非結(jié)構(gòu)化數(shù)據(jù)的特點。本文所要講述的HBase,就屬于該派系的一個典型代表。這些"雜亂無章"的列所構(gòu)成的多行數(shù)據(jù),被稱之為一個"稀疏矩陣",而上圖中的每一個"黑塊塊",在HBase中稱之為一個KeyValue。
Apache HBase官方給出了這樣的定義:
Apache HBase™ is the Hadoop database, a distributed, scalable, big data store.
即:Apache HBase是基于Hadoop構(gòu)建的一個分布式的、可伸縮的海量數(shù)據(jù)存儲系統(tǒng)。
HBase常被用來存放一些海量的(通常在TB級別以上)結(jié)構(gòu)比較簡單的數(shù)據(jù),如歷史訂單記錄,日志數(shù)據(jù),監(jiān)控Metris數(shù)據(jù)等等,HBase提供了簡單的基于Key值的快速查詢能力。
HBase在國內(nèi)市場已經(jīng)取得了非常廣泛的應(yīng)用,在搜索引擎中,也可以看出來,HBase在國內(nèi)呈現(xiàn)出了逐年上升的勢態(tài):
從Apache HBase所關(guān)聯(lián)的github項目的commits統(tǒng)計信息來看,也可以看出來該項目非?;钴S:
(需要說明的一點:HBase中的每一次commit,都已經(jīng)過社區(qū)Commiter成員嚴(yán)格的Review,在commit之前,一個Patch可能已經(jīng)被修改了幾十個版本)
令人欣喜的是,國內(nèi)的開發(fā)者也積極參與到了HBase社區(qū)貢獻中,而且被社區(qū)接納了多名PMC以及Committer成員。
本文將以一條數(shù)據(jù)在HBase中的“旅程”為線索,介紹HBase的核心概念與流程,幾乎每一部分都可以展開成一篇獨立的長文,但本文旨在讓讀者能夠快速的了解HBase的架構(gòu)輪廓,所以很多特性/流程被被一言帶過,但這些特性在社區(qū)中往往經(jīng)歷了漫長的開發(fā)過程。至于講什么以及講到什么程度,本文都做了艱難的取舍,在講解的過程中,將會穿插解答本文開始所提出的針對初學(xué)者的一些常見問題。
本文適用于HBase新手,而對于具備一定經(jīng)驗的HBase開發(fā)人員,相信本文也可以提供一些有價值的參考。本文內(nèi)容基于HBase 2.0 beta 2版本,對比于1.0甚至是更早期的版本,2.0出現(xiàn)了大量變化,下面這些問題的答案將揭示部分關(guān)鍵的變化(新手可以直接跳過這些問題):
- HBase meta Region在哪里提供服務(wù)?
- HBase是否可以保證單行操作的原子性?
- Region中寫WAL與寫MemStore的順序是怎樣的?
- 你是否遇到過Region長時間處于RIT的狀態(tài)? 你認為舊版本中Assignment Manager的主要問題是什么?
- 在面對Full GC問題時,你嘗試做過哪些優(yōu)化?
- 你是否深究過HBase Compaction帶來的“寫放大”有多嚴(yán)重?
- HBase的RPC框架存在什么問題?
- 導(dǎo)致查詢時延毛刺的原因有哪些?
本系列文章的整體行文思路如下:
- 介紹HBase數(shù)據(jù)模型
- 基于數(shù)據(jù)模型介紹HBase的適用場景
- 快速介紹集群關(guān)鍵角色以及集群部署建議
- 示例數(shù)據(jù)介紹
- 寫數(shù)據(jù)流程
- 讀數(shù)據(jù)流程
- 數(shù)據(jù)更新
- 負載均衡機制
- HBase如何存儲小文件數(shù)據(jù)
這些內(nèi)容將會被拆成幾篇文章。至于集群服務(wù)故障的處理機制,集群工具,周邊生態(tài),性能調(diào)優(yōu)以及***實踐等進階內(nèi)容,暫不放在本系列文章范疇內(nèi)。
約定
- 本文范圍內(nèi)針對一些關(guān)鍵特性/流程,使用了加粗以及加下劃線的方式做了強調(diào),如"ProcedureV2"。這些特性往往在本文中僅僅被粗淺提及,后續(xù)計劃以獨立的文章來介紹這些特性/流程。
- 術(shù)語縮寫:對于一些進程/角色名稱,在本文范圍內(nèi)可能通過縮寫形式來表述:
數(shù)據(jù)模型
RowKey
用來表示唯一一行記錄的主鍵,HBase的數(shù)據(jù)是按照RowKey的字典順序進行全局排序的,所有的查詢都只能依賴于這一個排序維度。
通過下面一個例子來說明一下"字典排序"的原理:
RowKey列表{"abc", "a", "bdf", "cdf", "defg"}按字典排序后的結(jié)果為{"a", "abc", "bdf", "cdf", "defg"}
也就是說,當(dāng)兩個RowKey進行排序時,先對比兩個RowKey的***個字節(jié),如果相同,則對比第二個字節(jié),依次類推...如果在對比到第M個字節(jié)時,已經(jīng)超出了其中一個RowKey的字節(jié)長度,那么,短的RowKey要被排在另外一個RowKey的前面。
稀疏矩陣
參考了Bigtable,HBase中一個表的數(shù)據(jù)是按照稀疏矩陣的方式組織的,"開篇"部分給出了一張關(guān)于HBase數(shù)據(jù)表的抽象圖,我們再結(jié)合下表來加深大家關(guān)于"稀疏矩陣"的印象:
看的出來:每一行中,列的組成都是靈活的,行與行之間并不需要遵循相同的列定義, 也就是HBase數(shù)據(jù)表"schema-less"的特點。
Region
區(qū)別于Cassandra/DynamoDB的"Hash分區(qū)"設(shè)計,HBase中采用了"Range分區(qū)",將Key的完整區(qū)間切割成一個個的"Key Range" ,每一個"Key Range"稱之為一個Region。
也可以這么理解:將HBase中擁有數(shù)億行的一個大表,橫向切割成一個個"子表",這一個個"子表"就是Region:
Region是HBase中負載均衡的基本單元,當(dāng)一個Region增長到一定大小以后,會自動分裂成兩個。
Column Family
如果將Region看成是一個表的橫向切割,那么,一個Region中的數(shù)據(jù)列的縱向切割,稱之為一個Column Family。每一個列,都必須歸屬于一個Column Family,這個歸屬關(guān)系是在寫數(shù)據(jù)時指定的,而不是建表時預(yù)先定義。
KeyValue
KeyValue的設(shè)計不是源自Bigtable,而是要追溯至論文"The log-structured merge-tree(LSM-Tree)"。每一行中的每一列數(shù)據(jù),都被包裝成獨立的擁有特定結(jié)構(gòu)的KeyValue,KeyValue中包含了豐富的自我描述信息:
看的出來,KeyValue是支撐"稀疏矩陣"設(shè)計的一個關(guān)鍵點:一些Key相同的任意數(shù)量的獨立KeyValue就可以構(gòu)成一行數(shù)據(jù)。但這種設(shè)計帶來的一個顯而易見的缺點:每一個KeyValue所攜帶的自我描述信息,會帶來顯著的數(shù)據(jù)膨脹。
適用場景
在介紹完了HBase的數(shù)據(jù)模型以后,我們可以回答本文一開始的前兩個問題:
- 什么樣的數(shù)據(jù)適合用HBase來存儲?
- 既然HBase也是一個數(shù)據(jù)庫,能否用它將現(xiàn)有系統(tǒng)中昂貴的Oracle替換掉?
HBase的數(shù)據(jù)模型比較簡單,數(shù)據(jù)按照RowKey排序存放,適合HBase存儲的數(shù)據(jù),可以簡單總結(jié)如下:
- 以實體為中心的數(shù)據(jù)
實體可以包括但不限于如下幾種:
& 自然人/賬戶/手機號/車輛相關(guān)數(shù)據(jù)
& 用戶畫像數(shù)據(jù)(含標(biāo)簽類數(shù)據(jù))
& 圖數(shù)據(jù)(關(guān)系類數(shù)據(jù))
描述這些實體的,可以有基礎(chǔ)屬性信息、實體關(guān)系(圖數(shù)據(jù))、所發(fā)生的事件(如交易記錄、車輛軌跡點)等等。
- 以事件為中心的數(shù)據(jù)
- 監(jiān)控數(shù)據(jù)
- 時序數(shù)據(jù)
- 實時位置類數(shù)據(jù)
- 消息/日志類數(shù)據(jù)
上面所描述的這些數(shù)據(jù),有的是結(jié)構(gòu)化數(shù)據(jù),有的是半結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)。HBase的“稀疏矩陣”設(shè)計,使其應(yīng)對非結(jié)構(gòu)化數(shù)據(jù)存儲時能夠得心應(yīng)手,但在我們的實際用戶場景中,結(jié)構(gòu)化數(shù)據(jù)存儲依然占據(jù)了比較重的比例。由于HBase僅提供了基于RowKey的單維度索引能力,在應(yīng)對一些具體的場景時,依然還需要基于HBase之上構(gòu)建一些專業(yè)的能力,如:
- OpenTSDB 時序數(shù)據(jù)存儲,提供基于Metrics+時間+標(biāo)簽的一些組合維度查詢與聚合能力
- GeoMesa 時空數(shù)據(jù)存儲,提供基于時間+空間范圍的索引能力
- JanusGraph 圖數(shù)據(jù)存儲,提供基于屬性、關(guān)系的圖索引能力
HBase擅長于存儲結(jié)構(gòu)簡單的海量數(shù)據(jù)但索引能力有限,而Oracle等傳統(tǒng)關(guān)系型數(shù)據(jù)庫(RDBMS)能夠提供豐富的查詢能力,但卻疲于應(yīng)對TB級別的海量數(shù)據(jù)存儲,HBase對傳統(tǒng)的RDBMS并不是取代關(guān)系,而是一種補充。
HBase與HDFS
我們都知道HBase的數(shù)據(jù)是存儲于HDFS里面的,相信大家也都有這么的認知:
HBase是一個分布式數(shù)據(jù)庫,HDFS是一個分布式文件系統(tǒng)
理解了這一點,我們先來粗略回答本文已開始提出的其中兩個問題:
1. HBase中的數(shù)據(jù)為何不直接存放于HDFS之上?
HBase中存儲的海量數(shù)據(jù)記錄,通常在幾百Bytes到KB級別,如果將這些數(shù)據(jù)直接存儲于HDFS之上,會導(dǎo)致大量的小文件產(chǎn)生,為HDFS的元數(shù)據(jù)管理節(jié)點(NameNode)帶來沉重的壓力。
2. 文件能否直接存儲于HBase里面?
如果是幾MB的文件,其實也可以直接存儲于HBase里面,我們暫且將這類文件稱之為小文件,HBase提供了一個名為MOB的特性來應(yīng)對這類小文件的存儲。但如果是更大的文件,強烈不建議用HBase來存儲,關(guān)于這里更多的原因,希望你在詳細讀完本系列文章所有內(nèi)容之后能夠自己解答。
集群角色
關(guān)于集群環(huán)境,你可以使用國內(nèi)外大數(shù)據(jù)廠商的平臺,如Cloudera,Hontonworks以及國內(nèi)的華為,都發(fā)行了自己的企業(yè)版大數(shù)據(jù)平臺,另外,華為云、阿里云中也均推出了全托管式的HBase服務(wù)。
我們假設(shè)集群環(huán)境已經(jīng)Ready了,先來看一下集群中的關(guān)鍵角色:
相信大部分人對這些角色都已經(jīng)有了一定程度的了解,我們快速的介紹一下各個角色在集群中的主要職責(zé):
- ZooKeeper
在一個擁有多個節(jié)點的分布式系統(tǒng)中,假設(shè),只能有一個節(jié)點是主節(jié)點,如何快速的選舉出一個主節(jié)點而且讓所有的節(jié)點都認可這個主節(jié)點?這就是HBase集群中存在的一個最基礎(chǔ)***。
利用ZooKeeper就可以非常簡單的實現(xiàn)這類"仲裁"需求,ZooKeeper還提供了基礎(chǔ)的事件通知機制,所有的數(shù)據(jù)都以 ZNode的形式存在,它也稱得上是一個"微型數(shù)據(jù)庫"。
- NameNode
HDFS作為一個分布式文件系統(tǒng),自然需要文件目錄樹的元數(shù)據(jù)信息,另外,在HDFS中每一個文件都是按照Block存儲的,文件與Block的關(guān)聯(lián)也通過元數(shù)據(jù)信息來描述。NameNode提供了這些元數(shù)據(jù)信息的存儲。
- DataNode
HDFS的數(shù)據(jù)存放節(jié)點。
- RegionServer
HBase的數(shù)據(jù)服務(wù)節(jié)點。
- Master
HBase的管理節(jié)點,通常在一個集群中設(shè)置一個主Master,一個備Master,主備角色的"仲裁"由ZooKeeper實現(xiàn)。 Master主要職責(zé):
①負責(zé)管理所有的RegionServer。
②建表/修改表/刪除表等DDL操作請求的服務(wù)端執(zhí)行主體。
③管理所有的數(shù)據(jù)分片(Region)到RegionServer的分配。
④如果一個RegionServer宕機或進程故障,由Master負責(zé)將它原來所負責(zé)的Regions轉(zhuǎn)移到其它的RegionServer上繼續(xù)提供服務(wù)。
⑤Master自身也可以作為一個RegionServer提供服務(wù),該能力是可配置的。
集群部署建議
如果基于物理機/虛擬機部署,通常建議:
1. RegionServer與DataNode聯(lián)合部署,RegionServer與DataNode按1:1比例設(shè)置。
這種部署的優(yōu)勢在于,RegionServer中的數(shù)據(jù)文件可以存儲一個副本于本機的DataNode節(jié)點中,從而在讀取時可以利用HDFS中的"短路徑讀取(Short Circuit)"來繞過網(wǎng)絡(luò)請求,降低讀取時延。
2. 管理節(jié)點獨立于數(shù)據(jù)節(jié)點部署
如果是基于物理機部署,每一臺物理機節(jié)點上可以設(shè)置幾個RegionServers/DataNodes來提升資源使用率。
也可以選擇基于容器來部署,如在HBaseCon Asia 2017大會知乎的演講主題中,就提到了知乎基于Kubernetes部署HBase服務(wù)的實踐。
對于公有云HBase服務(wù)而言,為了降低總體擁有成本(TCO),通常選擇"計算與存儲物理分離"的方式,從架構(gòu)上來說,可能導(dǎo)致平均時延略有下降,但可以借助于共享存儲底層的IO優(yōu)化來做一些"彌補"。
HBase集群中的RegionServers可以按邏輯劃分為多個Groups,一個表可以與一個指定的Group綁定,可以將RegionServer Group理解成將一個大的集群劃分成了多個邏輯子集群,借此可以實現(xiàn)多租戶間的隔離,這就是HBase中的RegionServer Group特性。
示例數(shù)據(jù)
給出一份我們?nèi)粘6伎梢越佑|到的數(shù)據(jù)樣例,先簡單給出示例數(shù)據(jù)的字段定義:
本文力求簡潔,僅給出了最簡單的示例。如下是"虛構(gòu)"的樣例數(shù)據(jù):
在本文大部分內(nèi)容中所涉及的一條數(shù)據(jù),是上面加粗的***一行"Mobile1"為"13400006666"這行記錄。
寫數(shù)據(jù)之前:創(chuàng)建連接
Login
在啟用了安全特性的前提下,Login階段是為了完成用戶認證(確定用戶的合法身份),這是后續(xù)一切安全訪問控制的基礎(chǔ)。
當(dāng)前Hadoop/HBase僅支持基于Kerberos的用戶認證,ZooKeeper除了Kerberos認證,還能支持簡單的用戶名/密碼認證,但都基于靜態(tài)的配置,無法動態(tài)新增用戶。如果要支持其它第三方認證,需要對現(xiàn)有的安全框架做出比較大的改動。
創(chuàng)建Connection
Connection可以理解為一個HBase集群連接的抽象,建議使用ConnectionFactory提供的工具方法來創(chuàng)建。因為HBase當(dāng)前提供了兩種連接模式:同步連接,異步連接,這兩種連接模式下所創(chuàng)建的Connection也是不同的。我們給出ConnectionFactory中關(guān)于獲取這兩種連接的典型方法定義:
Connection中主要維護著兩類共享的資源:
- 線程池
- Socket連接
這些資源都是在真正使用的時候才會被創(chuàng)建,因此,此時的連接還只是一個"虛擬連接"。
寫數(shù)據(jù)之前:創(chuàng)建數(shù)據(jù)表
DDL操作的抽象接口 - Admin
Admin定義了常規(guī)的DDL接口,列舉幾個典型的接口:
預(yù)設(shè)合理的數(shù)據(jù)分片 - Region
分片數(shù)量會給讀寫吞吐量帶來直接的影響,因此,建表時通常建議由用戶主動指定劃分Region分割點,來設(shè)定Region的數(shù)量。
HBase中數(shù)據(jù)是按照RowKey的字典順序排列的,為了能夠劃分出合理的Region分割點,需要依據(jù)如下幾點信息:
- Key的組成結(jié)構(gòu)
- Key的數(shù)據(jù)分布預(yù)估
如果不能基于Key的組成結(jié)構(gòu)來預(yù)估數(shù)據(jù)分布的話,可能會導(dǎo)致數(shù)據(jù)在Region間的分布不均勻
- 讀寫并發(fā)度需求
依據(jù)讀寫并發(fā)度需求,設(shè)置合理的Region數(shù)量
為表定義合理的Schema
既然HBase號稱"schema-less"的數(shù)據(jù)存儲系統(tǒng),那何來的是"schema "?的確,在數(shù)據(jù)庫范式的支持上,HBase非常弱,這里的"schema",主要指如下一些信息的設(shè)置:
1. NameSpace設(shè)置
2. Column Family的數(shù)量
3. 每一個Column Family中所關(guān)聯(lián)的一些關(guān)鍵配置:
① Compression
HBase當(dāng)前可以支持Snappy,GZ,LZO,LZ4,Bzip2以及ZSTD壓縮算法
② DataBlock Encoding
HBase針對自身的特殊數(shù)據(jù)模型所做的一種壓縮編碼
③ BloomFilter
可用來協(xié)助快速判斷一條記錄是否存在
④ TTL
指定數(shù)據(jù)的過期時間
⑤ StoragePolicy
指定Column Family的存儲策略,可選項有:"ALL_SSD","ONE_SSD","HOT","WARM","COLD","LAZY_PERSIST"
HBase中并不需要預(yù)先設(shè)置Column定義信息,這就是HBase schema less設(shè)計的核心。
Client發(fā)送建表請求到Master
建表的請求是通過RPC的方式由Client發(fā)送到Master:
- RPC接口基于Protocol Buffer定義
- 建表相關(guān)的描述參數(shù),也由Protocol Buffer進行定義及序列化
Client端側(cè)調(diào)用了Master服務(wù)的什么接口,參數(shù)是什么,這些信息都被通過RPC通信傳輸?shù)組aster側(cè),Master再依據(jù)這些接口\參數(shù)描述信息決定要執(zhí)行的操作。2.0版本中,HBase目前已經(jīng)支持基于Netty的異步RPC框架。
關(guān)于HBase RPC框架
早期的HBase RPC框架,完全借鑒了Hadoop中的實現(xiàn),那時,Netty項目尚不盛行。
Master側(cè)接收到Client側(cè)的建表請求以后,一些主要操作包括:
1. 生成每一個Region的描述信息對象HRegionInfo,這些描述信息包括:Region ID, Region名稱,Key范圍,表名稱等信息。
2. 生成每一個Region在HDFS中的文件目錄。
3. 將HRegionInfo信息寫入到記錄元數(shù)據(jù)的hbase:meta表中。
說明
meta表位于名為"hbase"的namespace中,因此,它的全稱為"hbase:meta"。但在本系列文章范疇內(nèi),常將其縮寫為"meta"。
整個過程中,新表的狀態(tài)也是記錄在hbase:meta表中的,而不用再存儲在ZooKeeper中。
如果建表執(zhí)行了一半,Master進程故障,如何處理?這里是由HBase自身提供的一個名為Procedure(V2)的框架來保障操作的事務(wù)性的,備Master接管服務(wù)以后,將會繼續(xù)完成整個建表操作。
一個被創(chuàng)建成功的表,還可以被執(zhí)行如下操作:
- Disable 將所有的Region下線,該表暫停讀寫服務(wù)
- Enable 將一個Disable過的表重新Enable,也就是上線所有的Region來正常提供讀寫服務(wù)
- Alter 更改表或列族的描述信息
Master分配Regions
新創(chuàng)建的所有的Regions,通過AssignmentManager將這些Region按照輪詢(Round-Robin)的方式分配到每一個RegionServer中,具體的分配計劃是由LoadBalancer來提供的。
AssignmentManager負責(zé)所有Regions的分配/遷移操作,Master中有一個定時運行的線程,來檢查集群中的Regions在各個RegionServer之間的負載是否是均衡的,如果不均衡,則通過LoadBalancer生成相應(yīng)的Region遷移計劃,HBase中支持多種負載均衡算法,有最簡單的僅考慮各RegionServer上的Regions數(shù)目的負載均衡算法,有基于遷移代價的負載均衡算法,也有數(shù)據(jù)本地化率優(yōu)先的負載均衡算法,因為這一部分已經(jīng)提供了插件化機制,用戶也可以自定義負載均衡算法。
總結(jié)
本文主要介紹了如下內(nèi)容:
1. HBase項目概述,呈現(xiàn)了HBase社區(qū)的活躍度以及搜索引擎熱度等信息
2. HBase數(shù)據(jù)模型部分,講到了RowKey,稀疏矩陣,Region,Column Family,KeyValue等概念
3. 基于HBase的數(shù)據(jù)模型,介紹了HBase的適合場景(以實體/事件為中心的簡單結(jié)構(gòu)的數(shù)據(jù))
4. 介紹了HBase與HDFS的關(guān)系
5. 介紹了集群的關(guān)鍵角色:ZooKeeper, Master, RegionServer,NameNode, DataNode
6. 集群部署建議
7. 給出了一些示例數(shù)據(jù)
8. 寫數(shù)據(jù)之前的準(zhǔn)備工作:建立集群連接,建表(建表時應(yīng)該定義合理的Schema以及設(shè)置合理的Region數(shù)量),建表由Master處理,新創(chuàng)建的Regions由Region AssignmentManager負責(zé)分配到各個RegionServer。
下一篇文章將正式開始介紹寫數(shù)據(jù)的流程。