一勃刨、HBase簡(jiǎn)介
1.1 HBase是什么
HBase是一個(gè)分布式的磨确、面向列的開源數(shù)據(jù)庫锋恬,Hadoop 數(shù)據(jù)庫滔岳。搭建基于 Hadoop 和 ZK 。
歷史是基于Google的 Bigtable 挽牢、Google 文件系統(tǒng)等論文谱煤。HBase 在Hadoop 之上提供了類似于 Bigtable 的能力。 HBase是Apache的Hadoop項(xiàng)目的子項(xiàng)目禽拔。HBase不同于一般的關(guān)系數(shù)據(jù)庫刘离,它是一個(gè)適合于非結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)的數(shù)據(jù)庫室叉。另一個(gè)不同的是HBase基于列的而不是基于行的模式。
1.2 HBase特性
1)海量存儲(chǔ)
Hbase適合存儲(chǔ)PB級(jí)別的海量數(shù)據(jù)硫惕,在PB級(jí)別的數(shù)據(jù)以及采用廉價(jià)PC存儲(chǔ)的情況下茧痕,能在幾十到百毫秒內(nèi)返回?cái)?shù)據(jù)。這與Hbase的極易擴(kuò)展性息息相關(guān)恼除。正式因?yàn)镠base良好的擴(kuò)展性踪旷,才為海量數(shù)據(jù)的存儲(chǔ)提供了便利。
2)列式存儲(chǔ)
這里的列式存儲(chǔ)其實(shí)說的是列族存儲(chǔ)豁辉,Hbase是根據(jù)列族來存儲(chǔ)數(shù)據(jù)的令野。列族下面可以有非常多的列,列族在創(chuàng)建表的時(shí)候就必須指定徽级。
3)極易擴(kuò)展
Hbase的擴(kuò)展性主要體現(xiàn)在兩個(gè)方面气破,一個(gè)是基于上層處理能力(RegionServer)的擴(kuò)展,一個(gè)是基于存儲(chǔ)的擴(kuò)展(HDFS)餐抢。通過橫向添加RegionSever的機(jī)器现使,進(jìn)行水平擴(kuò)展,提升Hbase上層的處理能力旷痕,提升Hbsae服務(wù)更多Region的能力碳锈。
備注:RegionServer的作用是管理region、承接業(yè)務(wù)的訪問苦蒿,這個(gè)后面會(huì)詳細(xì)的介紹通過橫向添加Datanode的機(jī)器殴胧,進(jìn)行存儲(chǔ)層擴(kuò)容,提升Hbase的數(shù)據(jù)存儲(chǔ)能力和提升后端存儲(chǔ)的讀寫能力佩迟。
4)高并發(fā)
由于目前大部分使用Hbase的架構(gòu)团滥,都是采用的廉價(jià)PC,因此單個(gè)IO的延遲其實(shí)并不小报强,一般在幾十到上百ms之間灸姊。這里說的高并發(fā),主要是在并發(fā)的情況下秉溉,Hbase的單個(gè)IO延遲下降并不多力惯。能獲得高并發(fā)、低延遲的服務(wù)召嘶。
5)稀疏
稀疏主要是針對(duì)Hbase列的靈活性父晶,在列族中,你可以指定任意多的列弄跌,在列數(shù)據(jù)為空的情況下甲喝,是不會(huì)占用存儲(chǔ)空間的。
1.3 HBase適用場(chǎng)景
(1)海量數(shù)據(jù)場(chǎng)景铛只,天然支持?jǐn)?shù)據(jù)水平擴(kuò)展埠胖,處理 TB 到 PB 數(shù)據(jù)
(2)寫性能突出糠溜,輕松打滿網(wǎng)卡,增量數(shù)據(jù)抓取直撤、批處理
(3)源于Hadoop生態(tài)非竿,和hadoop生態(tài)各個(gè)大數(shù)據(jù)系統(tǒng)天然集成
1.4 Hbase應(yīng)用場(chǎng)景
(1)半結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)
對(duì)于數(shù)據(jù)結(jié)構(gòu)字段不夠確定或雜亂無章很難按一個(gè)概念去進(jìn)行抽取的數(shù)據(jù)適合用HBase。以上面的例子為例谋竖,當(dāng)業(yè)務(wù)發(fā)展需要存儲(chǔ)author的email红柱,phone,address信息時(shí)RDBMS需要停機(jī)維護(hù)圈盔,而HBase支持動(dòng)態(tài)增加.
(2)記錄非常稀疏
RDBMS的行有多少列是固定的豹芯,為null的列浪費(fèi)了存儲(chǔ)空間。而如上文提到的驱敲,HBase為null的Column不會(huì)被存儲(chǔ)铁蹈,這樣既節(jié)省了空間又提高了讀性能。
(3)多版本數(shù)據(jù)
如上文提到的根據(jù)Row key和Column key定位到的Value可以有任意數(shù)量的版本值众眨,因此對(duì)于需要存儲(chǔ)變動(dòng)歷史記錄的數(shù)據(jù)握牧,用HBase就非常方便了。比如上例中的author的Address是會(huì)變動(dòng)的娩梨,業(yè)務(wù)上一般只需要最新的值沿腰,但有時(shí)可能需要查詢到歷史值。
(4)超大數(shù)據(jù)量
當(dāng)數(shù)據(jù)量越來越大狈定,RDBMS數(shù)據(jù)庫撐不住了颂龙,就出現(xiàn)了讀寫分離策略,通過一個(gè)Master專門負(fù)責(zé)寫操作纽什,多個(gè)Slave負(fù)責(zé)讀操作措嵌,服務(wù)器成本倍增。隨著壓力增加芦缰,Master撐不住了企巢,這時(shí)就要分庫了,把關(guān)聯(lián)不大的數(shù)據(jù)分開部署让蕾,一些join查詢不能用了浪规,需要借助中間層。隨著數(shù)據(jù)量的進(jìn)一步增加探孝,一個(gè)表的記錄越來越大笋婿,查詢就變得很慢,于是又得搞分表顿颅,比如按ID取模分成多個(gè)表以減少單個(gè)表的記錄數(shù)萌抵。經(jīng)歷過這些事的人都知道過程是多么的折騰。采用HBase就簡(jiǎn)單了元镀,只需要加機(jī)器即可绍填,HBase會(huì)自動(dòng)水平切分?jǐn)U展,跟Hadoop的無縫集成保障了其數(shù)據(jù)可靠性(HDFS)和海量數(shù)據(jù)分析的高性能(MapReduce)
1.5HBase運(yùn)行模式
(1)單機(jī)
(2)偽分布式
(3)分布式
(4)實(shí)戰(zhàn)小提示:如果 DB 數(shù)據(jù)大栖疑,想要同步到 HBase 怎么做讨永?用數(shù)據(jù)同步工具:DataX、binlog等
1.6Hbase的優(yōu)點(diǎn)
(1)列的可以動(dòng)態(tài)增加遇革,并且列為空就不存儲(chǔ)數(shù)據(jù),節(jié)省存儲(chǔ)空間.
(2)Hbase自動(dòng)切分?jǐn)?shù)據(jù)卿闹,使得數(shù)據(jù)存儲(chǔ)自動(dòng)具有水平scalability.
(3)Hbase可以提供高并發(fā)讀寫操作的支持
1.7 Hbase的缺點(diǎn)
(1)不能支持條件查詢,只支持按照Row key來查詢.
(2)暫時(shí)不能支持Master server的故障切換,當(dāng)Master宕機(jī)后,整個(gè)存儲(chǔ)系統(tǒng)就會(huì)掛掉.
1.8 HBase特性
強(qiáng)讀寫一致性:適合高速計(jì)數(shù)聚合操作
自動(dòng)切分?jǐn)?shù)據(jù):分布式存儲(chǔ)數(shù)據(jù)萝快,隨著數(shù)據(jù)增長(zhǎng)進(jìn)行自動(dòng)切片
RegionServer自動(dòng)失效備援
與HDFS集成
支持MapReduce執(zhí)行大規(guī)模并行操作
提供Java Client API
提供Thrift/REST API
針對(duì)大容量查詢優(yōu)化的塊緩存和Bloom Fliter
可視化管理界面
二锻霎、HBase安裝
2.1 Zookeeper正常部署
首先保證Zookeeper集群的正常部署,并啟動(dòng)之:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
[atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkServer.sh start
[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkServer.sh start
2.2 Hadoop正常部署
Hadoop集群的正常部署并啟動(dòng):
[atguigu@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
[atguigu@hadoop103?hadoop-2.7.2]$ sbin/start-yarn.sh
2.3 HBase的解壓
解壓HBase到指定目錄:
[atguigu@hadoop102 software]$?tar -zxvf hbase-1.3.1-bin.tar.gz -C /opt/module
2.4 HBase的配置文件
修改HBase對(duì)應(yīng)的配置文件揪漩。
1)hbase-env.sh修改內(nèi)容:
export JAVA_HOME=/opt/module/jdk1.8.0_144
export HBASE_MANAGES_ZK=false
2)hbase-site.xml修改內(nèi)容:
<configuration>
<property> ? ??
<name>hbase.rootdir</name> ? ??
<value>hdfs://hadoop102:9000/hbase</value> ?
</property>
<property> ?
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
???<!--?0.98后的新變動(dòng)旋恼,之前版本沒有.port,默認(rèn)端口為60000 -->
<property>
<name>hbase.master.port</name>
<value>16000</value>
</property>
<property> ?
<name>hbase.zookeeper.quorum</name>
?????<value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
</property>
<property> ?
<name>hbase.zookeeper.property.dataDir</name>
?????<value>/opt/module/zookeeper-3.4.10/zkData</value>
</property>
</configuration>
3)regionservers:
hadoop102
hadoop103
hadoop104
4)軟連接hadoop配置文件到hbase:
[atguigu@hadoop102 module]$ ln?-s /opt/module/hadoop-2.7.2/etc/hadoop/core-site.xml
/opt/module/hbase/conf/core-site.xml
[atguigu@hadoop102 module]$ ln?-s /opt/module/hadoop-2.7.2/etc/hadoop/hdfs-site.xml
/opt/module/hbase/conf/hdfs-site.xml
2.5 HBase遠(yuǎn)程發(fā)送到其他集群
[atguigu@hadoop102 module]$ xsync hbase/?
2.6 HBase服務(wù)的啟動(dòng)
1.啟動(dòng)方式1
[atguigu@hadoop102 hbase]$ bin/hbase-daemon.sh start master
[atguigu@hadoop102 hbase]$ bin/hbase-daemon.sh start regionserver
提示:如果集群之間的節(jié)點(diǎn)時(shí)間不同步,會(huì)導(dǎo)致regionserver無法啟動(dòng)奄容,拋出ClockOutOfSyncException異常冰更。
修復(fù)提示:
a、同步時(shí)間服務(wù)
請(qǐng)參看幫助文檔:《尚硅谷大數(shù)據(jù)技術(shù)之Hadoop入門》
b昂勒、屬性:hbase.master.maxclockskew設(shè)置更大的值
<property>
????????<name>hbase.master.maxclockskew</name>
????????<value>180000</value>
????????<description>Time difference of regionserver from master</description>
?</property>
2.啟動(dòng)方式2
[atguigu@hadoop102 hbase]$ bin/start-hbase.sh
對(duì)應(yīng)的停止服務(wù):
[atguigu@hadoop102 hbase]$ bin/stop-hbase.sh
2.7查看HBase頁面
啟動(dòng)成功后,可以通過“host:port”的方式來訪問HBase管理頁面,例如:
三菊霜、Hbase架構(gòu)
3.1 Hbase之基礎(chǔ)元素
3.2 Hbase之HTable概念
(1)Row key
行主鍵流部,HBase不支持條件查詢和Order by等查詢,讀取記錄只能按Row key(及其range)或全表掃描塘娶,因此Row key需要根據(jù)業(yè)務(wù)來設(shè)計(jì)以利用其存儲(chǔ)排序特性(Table按Row key字典序排序如1,10,100,11,2)提高性能归斤。
(2)Column Family(列族)
在表創(chuàng)建時(shí)聲明,每個(gè)Column Family為一個(gè)存儲(chǔ)單元血柳。在上例中設(shè)計(jì)了一個(gè)HBase表blog官册,該表有兩個(gè)列族:article和author。
(3)Column(列)
HBase的每個(gè)列都屬于一個(gè)列族难捌,以列族名為前綴膝宁,如列article:title和article:content屬于article列族,author:name和author:nickname屬于author列族根吁。
Column不用創(chuàng)建表時(shí)定義即可以動(dòng)態(tài)新增员淫,同一Column Family的Columns會(huì)群聚在一個(gè)存儲(chǔ)單元上,并依Column key排序击敌,因此設(shè)計(jì)時(shí)應(yīng)將具有相同I/O特性的Column設(shè)計(jì)在一個(gè)Column Family上以提高性能介返。同時(shí)這里需要注意的是:這個(gè)列是可以增加和刪除的,這和我們的傳統(tǒng)數(shù)據(jù)庫很大的區(qū)別。所以他適合非結(jié)構(gòu)化數(shù)據(jù)圣蝎。
(4)Timestamp
HBase通過row和column確定一份數(shù)據(jù)刃宵,這份數(shù)據(jù)的值可能有多個(gè)版本,不同版本的值按照時(shí)間倒序排序徘公,即最新的數(shù)據(jù)排在最前面牲证,查詢時(shí)默認(rèn)返回最新版本。如上例中row key=1的author:nickname值有兩個(gè)版本关面,分別為1317180070811對(duì)應(yīng)的“一葉渡江”和1317180718830對(duì)應(yīng)的“yedu”(對(duì)應(yīng)到實(shí)際業(yè)務(wù)可以理解為在某時(shí)刻修改了nickname為yedu坦袍,但舊值仍然存在)。Timestamp默認(rèn)為系統(tǒng)當(dāng)前時(shí)間(精確到毫秒)等太,也可以在寫入數(shù)據(jù)時(shí)指定該值捂齐。
(5)Value
每個(gè)值通過4個(gè)鍵唯一索引,tableName+RowKey+ColumnKey+Timestamp=>value缩抡,例如上例中{tableName=’blog’,RowKey=’1’,ColumnName=’author:nickname’,Timestamp=’ 1317180718830’}索引到的唯一值是“yedu”奠宜。
(6)存儲(chǔ)類型
TableName是字符串
RowKey和 ColumnName 是二進(jìn)制值(Java 類型 byte[])
Timestamp是一個(gè) 64 位整數(shù)(Java 類型 long)
value是一個(gè)字節(jié)數(shù)組(Java類型 byte[])。
(7)存儲(chǔ)結(jié)構(gòu)
可以簡(jiǎn)單的將HTable的存儲(chǔ)結(jié)構(gòu)理解為即HTable按Row key自動(dòng)排序缝其,每個(gè)Row包含任意數(shù)量個(gè)Columns挎塌,Columns之間按Column key自動(dòng)排序,每個(gè)Column包含任意數(shù)量個(gè)Values内边。理解該存儲(chǔ)結(jié)構(gòu)將有助于查詢結(jié)果的迭代榴都。
3.3 Hbase存儲(chǔ)結(jié)構(gòu)圖
3.4 Hbase存儲(chǔ)流程
1)當(dāng)客戶端提交變更操作(如插入put,刪除delete漠其,計(jì)數(shù)新增incr)嘴高,首先客戶端會(huì)連接上Zookeeper找到-Root-表的存儲(chǔ)位置,然后根據(jù)-Root-表所提供的.Meta.表的位置找到對(duì)應(yīng)的Region所在的HRegionServer和屎。數(shù)據(jù)變更信息會(huì)先通過HRegionServer寫入一個(gè)commit log拴驮,也就是WAL。當(dāng)寫入WAL成功后柴信,數(shù)據(jù)變更信息會(huì)存到MemStore中套啤。當(dāng)MemStore達(dá)到設(shè)定的maximum value(hbase.hregion.memstore.flush.size,默認(rèn)64MB)后随常,MemStore就會(huì)開始進(jìn)行Flush操作潜沦,將其內(nèi)容持久化到一個(gè)新的HFile中。在Flush操作過程中绪氛,MemStore通過滾動(dòng)機(jī)制繼續(xù)對(duì)用戶提供讀寫服務(wù)唆鸡。隨著Flush操作的不斷進(jìn)行,HFile文件越來越多枣察。 當(dāng)HFile文件超過設(shè)定的數(shù)量后争占,Hbase的HouseKeeping機(jī)制就會(huì)通過Compaction特性將HFile小文件合并成一個(gè)更大的HFile文件燃逻。在Compaction的過程中,會(huì)進(jìn)行版本的合并以及數(shù)據(jù)的刪除臂痕。由于storeFiles是不變的伯襟,用戶執(zhí)行刪除操作時(shí),并不能簡(jiǎn)單地通過刪除其鍵值對(duì)來刪除數(shù)據(jù)內(nèi)容刻蟹。Hbase提供了一個(gè)delete marker機(jī)制(也稱為tombstone marker)逗旁,會(huì)告訴HRegionServer那個(gè)指定的key已經(jīng)被刪除了。這樣其它用戶檢索這個(gè)key的內(nèi)容時(shí)舆瘪,因?yàn)橐呀?jīng)被標(biāo)記為刪除,所以也不會(huì)檢索出來红伦。在進(jìn)行Compaction操作中就會(huì)丟棄這些已經(jīng)打標(biāo)的記錄英古。經(jīng)過多次Compaction后,HFile文件會(huì)越來越大昙读,當(dāng)達(dá)到設(shè)定的值時(shí)召调,會(huì)觸發(fā)Split操作。將當(dāng)前的Region根據(jù)RowKey對(duì)等切分成兩個(gè)子Region蛮浑,當(dāng)期的那個(gè)Region被廢棄唠叛,兩個(gè)子Region會(huì)被分配到其他HRegionServer上。所以剛開始時(shí)一個(gè)表只有一個(gè)Region沮稚,隨著不斷的split艺沼,會(huì)產(chǎn)生越來越多的Region,通過HMaster
的LoadBalancer調(diào)整蕴掏,Region會(huì)均勻遍布到所有的HRegionServer中障般。
2)當(dāng)HLog滿時(shí),HRegionServer就會(huì)啟動(dòng)LogRoller,通過執(zhí)行rollWriter方法將那些所有sequence number均小于最大的那個(gè)sequence number的logfile移動(dòng)到.oldLog目錄中等待被刪除盛杰。如果用戶設(shè)置了Deferred Log Flush為true挽荡,HRegionServer會(huì)緩存有關(guān)此表的所有變更,并通過LogSyncer調(diào)用sync()方法定時(shí)將變更信息同步到filesystem即供。默認(rèn)為false的話定拟,一旦有變更就會(huì)立刻同步到filesystem。
3)在一個(gè)HRegionServer中只有一個(gè)WAL逗嫡,所有Region共享此WAL青自。HLog會(huì)根據(jù)Region提交變更信息的先后順序依次順序?qū)懭隬AL中。如果用戶設(shè)置了setWriteToWAL(false)方法祸穷,則有關(guān)此表的所有Region變更日志都不會(huì)寫入WAL中性穿。這也是上圖中Region將變更日志寫入WAL的那個(gè)垂直向下的箭頭為什么是虛線的原因。
3.5 HBase體系架構(gòu)
Client:包含訪問HBase的接口并維護(hù)cache來加快對(duì)HBase的訪問
Master:
(1)為Region server分配region
(2)負(fù)責(zé)Region server的負(fù)載均衡
(3)發(fā)現(xiàn)失效的Region server并重新分配其上的region
(4)管理用戶對(duì)table的增刪改操作
RegionServer:
(1)Region server維護(hù)region雷滚,處理對(duì)這些region的IO請(qǐng)求
(2)Region server負(fù)責(zé)切分在運(yùn)行過程中變得過大的region
HLog(WAL log):
(1)HLog文件就是一個(gè)普通的Hadoop Sequence File需曾,Sequence File 的Key是 HLogKey對(duì)象,HLogKey中記錄了寫入數(shù)據(jù)的歸屬信息,除了table和 region名字外呆万,同時(shí)還包括sequence number和timestamp商源,timestamp是” 寫入時(shí)間”,sequence number的起始值為0谋减,或者是最近一次存入文件系 統(tǒng)中sequence number牡彻。
2)HLog SequeceFile的Value是HBase的KeyValue對(duì)象,即對(duì)應(yīng)HFile中的 KeyValue
Region:
(1)HBase自動(dòng)把表水平劃分成多個(gè)區(qū)域(region)出爹,每個(gè)region會(huì)保存一個(gè)表 里面某段連續(xù)的數(shù)據(jù)庄吼;每個(gè)表一開始只有一個(gè)region,隨著數(shù)據(jù)不斷插 入表严就,region不斷增大总寻,當(dāng)增大到一個(gè)閥值的時(shí)候,region就會(huì)等分會(huì) 兩個(gè)新的region(裂變)梢为;
(2)當(dāng)table中的行不斷增多渐行,就會(huì)有越來越多的region。這樣一張完整的表 被保存在多個(gè)Regionserver上铸董。
Memstore與 storefile:
(1)一個(gè)region由多個(gè)store組成祟印,一個(gè)store對(duì)應(yīng)一個(gè)CF(列族)
(2)store包括位于內(nèi)存中的memstore和位于磁盤的storefile寫操作先寫入 memstore,當(dāng)memstore中的數(shù)據(jù)達(dá)到某個(gè)閾值粟害,hregionserver會(huì)啟動(dòng) flashcache進(jìn)程寫入storefile蕴忆,每次寫入形成單獨(dú)的一個(gè)storefile
(3)當(dāng)storefile文件的數(shù)量增長(zhǎng)到一定閾值后,系統(tǒng)會(huì)進(jìn)行合并(minor我磁、 major compaction)孽文,在合并過程中會(huì)進(jìn)行版本合并和刪除工作 (majar),形成更大的storefile。
(4)當(dāng)一個(gè)region所有storefile的大小和超過一定閾值后夺艰,會(huì)把當(dāng)前的region 分割為兩個(gè)芋哭,并由hmaster分配到相應(yīng)的regionserver服務(wù)器,實(shí)現(xiàn)負(fù)載均衡郁副。
(5)客戶端檢索數(shù)據(jù)减牺,先在memstore找,找不到再找storefile
(6)HRegion是HBase中分布式存儲(chǔ)和負(fù)載均衡的最小單元存谎。最小單元就表 示不同的HRegion可以分布在不同的HRegion server上拔疚。
(7)HRegion由一個(gè)或者多個(gè)Store組成,每個(gè)store保存一個(gè)columns family既荚。
(8)每個(gè)Strore又由一個(gè)memStore和0至多個(gè)StoreFile組成稚失。
四、Hbase基本操作
Hbase中主要的客戶端接口是HTable類恰聘,HTable提供了對(duì)數(shù)據(jù)的所有CRUD操作句各。需要注意的是由于創(chuàng)建HTabe實(shí)例比較耗時(shí)吸占, 所以在實(shí)際使用中最好創(chuàng)建單例模式的HTable實(shí)例,不過如果需要多個(gè)HTable實(shí)例的話凿宾,可以考慮使用HBase的HTablePool特性(下面后講到)矾屯。Hbase不提供直接的update操作。由于Hbase中數(shù)據(jù)存儲(chǔ)有版本支持初厚。所以如果需要update一條記錄件蚕,一般是通過put操作,這樣歷史版本會(huì)在Compaction操作中被合并掉产禾,這樣就間接實(shí)現(xiàn)了更新排作。(在MemStore中有一個(gè)變量MemstoreTS,該變量是隨put操作而遞增的下愈。比如首先往列A纽绍,timeStamp為T1上put一條數(shù)據(jù)data1,假設(shè)此時(shí)MemstoreTS為1势似;之后如果想更新這條數(shù)據(jù),只需要往列A僧著,timeStamp為T1上put一條數(shù)據(jù)data2履因,此時(shí)MemstoreTS為2,Hbase會(huì)自動(dòng)會(huì)將MemstoreTS大的排在前面盹愚。MemstoreTS小的在Compaction過程中就被過濾掉了栅迄。)
4.1 put操作
Put操作就是講數(shù)據(jù)插入到Hbase中。有兩種模式皆怕,一種是對(duì)單行的操作(single put)毅舆;還有一種是對(duì)多行的操作(List of put)。針對(duì)單行操作的方式如下:
(一)創(chuàng)建put實(shí)例有如下構(gòu)造函數(shù):需要用戶指定某行愈腾,用戶也可以設(shè)定時(shí)間戳作為版本標(biāo)示憋活。此外,用戶還可以加入自定義的行鎖虱黄,以防其它用戶或者其它線程在變更期間訪問此行的數(shù)據(jù)悦即。
Put(byte[] row)
Put(byte[] row, RowLock rowLock)
Put(byte[] row, long ts)
Put(byte[] row, long ts, RowLock rowLock)
在Hbase中參數(shù)的傳遞大多是byte數(shù)組類型。Hbase提供了許多靜態(tài)方法將java類型轉(zhuǎn)換成byte數(shù)組類型橱乱。如下:
static byte[] toBytes(ByteBuffer bb)
static byte[] toBytes(String s)
static byte[] toBytes(boolean b)
static byte[] toBytes(long val)
static byte[] toBytes(float f)
static byte[] toBytes(int val)
(二)一旦創(chuàng)建好put實(shí)例后辜梳,就可以通過put類提供的方法插入數(shù)據(jù)了。插入數(shù)據(jù)的操作需要指定列族泳叠,所在列等作瞄。如下:
Put add(byte[] family, byte[] qualifier, byte[] value)
Put add(byte[] family, byte[] qualifier, long ts, byte[] value)
Put add(KeyValue kv) throws IOException
(三)put組裝完成后,就可以通過HTable提供的void put(Put put)throws IOException完成數(shù)據(jù)的插入操作危纫。
如果需要對(duì)多行進(jìn)行put操作宗挥,可以組裝一系列的put實(shí)例乌庶,然后調(diào)用HTable提供的void put(List puts) throws IOException來完成多行插入操作。不過需要指出的是:如果在這多個(gè)Put實(shí)例中存在一個(gè)put實(shí)例有誤(比如:往一個(gè)不存在的列族中插入數(shù)據(jù))属韧,那么該put實(shí)例會(huì)報(bào)錯(cuò)安拟,但是不影響其他的put實(shí)例。跟后面的get操作有點(diǎn)區(qū)別宵喂。
此外糠赦,Hbase還提供了一個(gè)原子型的put操作:Atomic compare-and-set?,方法如下:boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,byte[] value, Put put) throws IOException锅棕。只有校驗(yàn)成功后才會(huì)完成put操作.
需要注意的是拙泽,因?yàn)槊看蔚膒ut操作相當(dāng)于一個(gè)RPC,將數(shù)據(jù)從客戶端傳遞到服務(wù)端并返回裸燎。如果你的應(yīng)用中RPC非常頻繁顾瞻,比如一秒內(nèi)成千上萬次,可能會(huì)有隱患德绿。解決的辦法就是盡量降低RPC次數(shù)荷荤,Hbase提供了一個(gè)嵌入的客戶端寫緩存器(Client-side Write Buffer)。它會(huì)緩存所有的put操作移稳,然后再一次性提交蕴纳。默認(rèn)情況下Client-side Write Buffer是沒有激活的。用戶可以在創(chuàng)建HTable的時(shí)候通過調(diào)用table.setAutoFlush(false)方法來激活它个粱。并且可以通過isAutoFlush()來檢查是否已經(jīng)激活古毛。默認(rèn)是true,表示一旦有put操作會(huì)立即發(fā)送到服務(wù)器端都许。當(dāng)你想將所有put操作提交到服務(wù)器端時(shí)稻薇,可以調(diào)用flushCommits()操作。它會(huì)將緩存器中所有變更提交到遠(yuǎn)程服務(wù)器胶征。Client-side Write Buffer還會(huì)自動(dòng)對(duì)buffer中的所有變更進(jìn)行分組塞椎,同一個(gè)HRegionServer的分到同一個(gè)組。這樣每個(gè)HRegionServer通過一個(gè)RPC傳送.
4.2 get操作
Get操作就是從服務(wù)器端獲取數(shù)據(jù)弧烤。跟put操作一樣忱屑,get操作也分為兩種模式,一種是對(duì)單行的get操作(single get)暇昂,另一種是對(duì)多行進(jìn)行檢索操作(List of gets)莺戒。
1、HTable提供的get方法如下:其返回值為Result類急波,該類包含了列族从铲,列,keyvalue澄暮,
RowKey等信息名段。該類提供的豐富的方法供用戶獲取返回的各種信息阱扬。
Result get(Get get) throws IOException
2、Get類的構(gòu)造函數(shù)如下伸辟,需要用戶傳入指定的行及行鎖等參數(shù)麻惶。
Get(byte[] row)
Get(byte[] row, RowLock rowLock)
3、 一旦創(chuàng)建的get實(shí)例后信夫,用戶可以調(diào)用Get類提供的如下方法來框定你需要檢索的數(shù)據(jù)窃蹋。如下:用戶可以指定列族,列静稻,時(shí)間戳警没,最大版本號(hào)等。如果不設(shè)置版本號(hào)振湾,默認(rèn)是1杀迹,表示最大的版本。
Get addFamily(byte[] family)
Get addColumn(byte[] family, byte[] qualifier)
Get setTimeRange(long minStamp, long maxStamp) throws IOException
Get setTimeStamp(long timestamp)
Get setMaxVersions()
Get setMaxVersions(int maxVersions) throws IOException
跟List of put類似押搪,對(duì)于多行的檢索操作树酪,HTable也提供了類似的如下方法:用戶只要?jiǎng)?chuàng)建多個(gè)get實(shí)例,就可以通過如下方法獲取需要的數(shù)據(jù)大州。不過需要注意的是:跟List of put不同的是嗅回,如果Get實(shí)例列表中只要存在一個(gè)Get實(shí)例有誤(比如get一個(gè)不存在的列族的值),那么整體就會(huì)拋出一個(gè)異常.
Result[] get(List gets) throws IOException
4.3 delete操作
Delete操作也類似摧茴,HTable提供了兩種方法,支持單個(gè)delete實(shí)例和多個(gè)delete實(shí)例的操作埂陆。如下:
void delete(Delete delete) throws IOException
void delete(List deletes) throws IOException
1苛白、相應(yīng)的delete實(shí)例構(gòu)造函數(shù)有:
Delete(byte[] row)
Delete(byte[] row, long timestamp, RowLock rowLock)
2、如果你需要添加一些限制條件焚虱,可以使用delete類提供的相關(guān)方法购裙,支持指定列族,列鹃栽,時(shí)間戳等躏率。如果你指定了一個(gè)時(shí)間戳,則表示小于等于該時(shí)間戳的時(shí)間將被刪除民鼓。如果指定了列和行號(hào)薇芝,但沒有指定時(shí)間戳,則默認(rèn)會(huì)刪掉版本號(hào)最大的那個(gè)值丰嘉。
Delete deleteFamily(byte[] family)
Delete deleteFamily(byte[] family, long timestamp)
Delete deleteColumns(byte[] family, byte[] qualifier)
Delete deleteColumns(byte[] family, byte[] qualifier, long timestamp)
Delete deleteColumn(byte[] family, byte[] qualifier)
Delete deleteColumn(byte[] family, byte[] qualifier, long timestamp)
void setTimestamp(long timestamp)
3夯到、當(dāng)使用List of delete時(shí),如果有一個(gè)delete實(shí)例出錯(cuò)饮亏,那么會(huì)拋出異常耍贾。而且delete的實(shí)例列表中只會(huì)存在那個(gè)出問題的delete實(shí)例阅爽。Delete也支持原子型的Compare-and- Delete,如下:
boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,byte[] value, Delete delete) throws IOException
4.4 Batch操作
Hbase還支持批量操作荐开。其實(shí)上面所談到的List of puts,gets,deletes都是基于Batch操作來的付翁。不過List of puts,gets,deletes逐漸會(huì)被廢棄。推薦使用Batch操作晃听。HTable提供的batch操作方法如下:參數(shù)中Row類是Put百侧,Delete,Get類的父類杂伟。表示用戶可以同時(shí)傳入put移层,get及delete實(shí)例操作。不過在一個(gè)batch中赫粥,最好不要同時(shí)傳入針對(duì)同一行的put和delete實(shí)例观话。
(1) void batch(List actions, Object[] results) throws IOException, InterruptedException
(2) Object[] batch(List actions) throws IOException, InterruptedException上面這兩個(gè)batch方法比較類似,但有比較大的區(qū)別越平。第一個(gè)batch方法需要用戶傳遞一個(gè)數(shù)組频蛔,該數(shù)組用來填充batch操作中所有成功的操作的結(jié)果集。如果沒有指定這個(gè)數(shù)組秦叛,比如第二個(gè)方法晦溪。一旦batch操作中某一個(gè)實(shí)例出現(xiàn)問題,那么Hbase只會(huì)拋出一個(gè)異常挣跋。那些成功的操作的結(jié)果并不會(huì)返回三圆。而第一個(gè)方法則會(huì)將那些成功的操作的結(jié)果集返回給用戶。
此外Batch操作不支持Client-side write buffer避咆,Batch方法是同步的舟肉,會(huì)直接將其包含的操作發(fā)往服務(wù)器。這點(diǎn)需要注意查库!
Batch操作返回的結(jié)果可能的結(jié)果有如下幾種:
1路媚、null:表示那個(gè)操作操作連接遠(yuǎn)程服務(wù)器失敗。
2樊销、Empty Result:put和delete操作的返回結(jié)果整慎,表示操作成功。
3围苫、Result:get操作的返回結(jié)果集
4裤园、Throwable:異常結(jié)果
4.5 Scan操作
Scan操作類似于傳統(tǒng)的RDBMS中的游標(biāo)的概念。其目的跟get一樣够吩,也是檢索服務(wù)器端數(shù)據(jù)比然。Hbase也提供了一個(gè)Scan類。由于Scans類似于迭代器周循,所以你需要通過getScanner()方法獲取强法。HTable提供了如下方法:如果你看了源碼就會(huì)知道万俗,后面那兩個(gè)方法其實(shí)是先創(chuàng)建一個(gè)scan實(shí)例,并加入傳入的參數(shù)饮怯,然后再調(diào)用第一個(gè)方法闰歪。
ResultScanner getScanner(Scan scan) throws IOException
ResultScanner getScanner(byte[] family) throws IOException
ResultScanner getScanner(byte[] family, byte[] qualifier) throws IOException
1、Scan類提供了多個(gè)構(gòu)造函數(shù)蓖墅,如下:startRow和stopRow是左閉右開的库倘。從構(gòu)造函數(shù)中可以看出,用戶只需要指定rowKey的范圍论矾,或者添加相應(yīng)的過濾器教翩,Hbase能夠自動(dòng)檢索你指定的RowKey的范圍的數(shù)據(jù)。如果沒有指定startRow贪壳,默認(rèn)從第一行開始.
Scan()
Scan(byte[] startRow, Filter filter)
Scan(byte[] startRow)
Scan(byte[] startRow, byte[] stopRow)
2饱亿、當(dāng)創(chuàng)建好Scan實(shí)例后,如果想添加更多的限制條件闰靴,可以通過調(diào)用Scan提供的如下方法:允許添加列族彪笼,列,時(shí)間戳等.
Scan addFamily(byte [] family)
Scan addColumn(byte[] family, byte[] qualifier)
Scan setTimeRange(long minStamp, long maxStamp) throws IOException
Scan setTimeStamp(long timestamp)
Scan setMaxVersions()
Scan setMaxVersions(int maxVersions)
GetScanner()方法返回的是一個(gè)ResultScanner實(shí)例蚂且。需要注意的是:如果結(jié)果集存在多行配猫,Scans并不會(huì)一次性將所有行在一個(gè)RPC里面?zhèn)魉徒o客戶端,而是基于一行一行傳送杏死。這樣做主要是因?yàn)槎嘈行枰馁M(fèi)大量時(shí)間泵肄。
ResultScanner類包裝了Result類將其每行結(jié)果以迭代的方式輸出,使得Scan操作類似于get操作淑翼。此外ResultScanner類提供了如下方法供用戶進(jìn)行迭代使用:用戶可以選擇一次返回一行或者多行凡伊。不過不要認(rèn)為是服務(wù)器端一次性返回多行。其實(shí)是客戶端循環(huán)調(diào)用nbRows 次next()方法而已窒舟。服務(wù)器端在一個(gè)RPC里面還是只傳送一行數(shù)據(jù)。這個(gè)確實(shí)有點(diǎn)影響心情诵盼,但Hbase就喜歡惡心下你惠豺,不過它也提供的相應(yīng)的解決辦法:Scanner Caching,默認(rèn)是關(guān)閉的风宁。
Result next() throws IOException
Result[] next(int?nbRows) throws IOException
void close()
close()方法表示釋放ResultScanner實(shí)例洁墙。因?yàn)镽esultScanner實(shí)例持有了一定的資源,如果不及時(shí)釋放,可能隨著時(shí)間推移會(huì)占用很大的內(nèi)存空間戒财。此外热监,close()操作最好放在finally模塊,原因你懂得饮寞!
4.6?shell基本操作
1.進(jìn)入HBase客戶端命令行
[atguigu@hadoop102 hbase]$ bin/hbase shell
2.查看幫助命令
hbase(main):001:0> help
3.查看當(dāng)前數(shù)據(jù)庫中有哪些表
hbase(main):002:0> list
4.7?shell表的操作
1.創(chuàng)建表
hbase(main):002:0> create 'student','info'
2.插入數(shù)據(jù)到表
hbase(main):003:0> put 'student','1001','info:sex','male'
hbase(main):004:0> put 'student','1001','info:age','18'
hbase(main):005:0> put 'student','1002','info:name','Janna'
hbase(main):006:0> put 'student','1002','info:sex','female'
hbase(main):007:0> put 'student','1002','info:age','20'
3.掃描查看表數(shù)據(jù)
hbase(main):008:0> scan 'student'
hbase(main):009:0> scan 'student',{STARTROW => '1001', STOPROW ?=> '1001'}
hbase(main):010:0> scan 'student',{STARTROW => '1001'}
4.查看表結(jié)構(gòu)
hbase(main):011:0> describe ‘student’
5.更新指定字段的數(shù)據(jù)
hbase(main):012:0> put 'student','1001','info:name','Nick'
hbase(main):013:0> put 'student','1001','info:age','100'
6.查看“指定行”或“指定列族:列”的數(shù)據(jù)
hbase(main):014:0> get 'student','1001'
hbase(main):015:0> get 'student','1001','info:name'
7.統(tǒng)計(jì)表數(shù)據(jù)行數(shù)
hbase(main):021:0> count 'student'
8.刪除數(shù)據(jù)
刪除某rowkey的全部數(shù)據(jù):
hbase(main):016:0> deleteall 'student','1001'
刪除某rowkey的某一列數(shù)據(jù):
hbase(main):017:0> delete 'student','1002','info:sex'
9.清空表數(shù)據(jù)
hbase(main):018:0> truncate 'student'
提示:清空表的操作順序?yàn)橄萪isable孝扛,然后再truncate列吼。
10.刪除表
首先需要先讓該表為disable狀態(tài):
hbase(main):019:0> disable 'student'
然后才能drop這個(gè)表:
hbase(main):020:0> drop 'student'
提示:如果直接drop表,會(huì)報(bào)錯(cuò):ERROR: Table student is enabled. Disable it first.
11.變更表信息
將info列族中的數(shù)據(jù)存放3個(gè)版本:
hbase(main):022:0> alter 'student',{NAME=>'info',VERSIONS=>3}
hbase(main):022:0>?get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3}
五苦始、HBase原理
5.1讀流程
HBase讀數(shù)據(jù)流程如圖3所示
1)Client向HregionServer發(fā)送寫請(qǐng)求寞钥;
2)HregionServer將數(shù)據(jù)寫到HLog(write ahead log)。為了數(shù)據(jù)的持久化和恢復(fù)陌选;
3)HregionServer將數(shù)據(jù)寫到內(nèi)存(MemStore)理郑;
4)反饋Client寫成功。
1)當(dāng)MemStore數(shù)據(jù)達(dá)到閾值(默認(rèn)是128M咨油,老版本是64M)您炉,將數(shù)據(jù)刷到硬盤,將內(nèi)存中的數(shù)據(jù)刪除役电,同時(shí)刪除HLog中的歷史數(shù)據(jù)赚爵;
2)并將數(shù)據(jù)存儲(chǔ)到HDFS中;
3)在HLog中做標(biāo)記點(diǎn)。
5.4數(shù)據(jù)合并過程
1)當(dāng)數(shù)據(jù)塊達(dá)到4塊瞄摊,Hmaster觸發(fā)合并操作性湿,Region將數(shù)據(jù)塊加載到本地,進(jìn)行合并畸写;
2)當(dāng)合并的數(shù)據(jù)超過256M,進(jìn)行拆分氓扛,將拆分后的Region分配給不同的HregionServer管理枯芬;
3)當(dāng)HregionServer宕機(jī)后,將HregionServer上的hlog拆分采郎,然后分配給不同的HregionServer加載千所,修改.META.;
4)注意:HLog會(huì)同步到HDFS蒜埋。
六淫痰、HBase API操作
6.1環(huán)境準(zhǔn)備
新建項(xiàng)目后在pom.xml中添加依賴:
<dependency>
????<groupId>org.apache.hbase</groupId>
????<artifactId>hbase-server</artifactId>
????<version>1.3.1</version>
</dependency>
<dependency>
????<groupId>org.apache.hbase</groupId>
????<artifactId>hbase-client</artifactId>
????<version>1.3.1</version>
</dependency>
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
6.2 HBaseAPI
6.2.1獲取Configuration對(duì)象
public static Configuration conf;
static{
//使用HBaseConfiguration的單例方法實(shí)例化
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "192.168.9.102");
conf.set("hbase.zookeeper.property.clientPort", "2181");
}
6.2.2判斷表是否存在
public static boolean isTableExist(String tableName) throws MasterNotRunningException,
?ZooKeeperConnectionException, IOException{
//在HBase中管理、訪問表需要先創(chuàng)建HBaseAdmin對(duì)象
//Connection connection = ConnectionFactory.createConnection(conf);
//HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
HBaseAdmin admin = new HBaseAdmin(conf);
return admin.tableExists(tableName);
}
6.2.3創(chuàng)建表
public static void createTable(String tableName, String... columnFamily) throws
?MasterNotRunningException, ZooKeeperConnectionException, IOException{
HBaseAdmin admin = new HBaseAdmin(conf);
//判斷表是否存在
if(isTableExist(tableName)){
System.out.println("表" + tableName + "已存在");
//System.exit(0);
}else{
//創(chuàng)建表屬性對(duì)象,表名需要轉(zhuǎn)字節(jié)
HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));
//創(chuàng)建多個(gè)列族
for(String cf : columnFamily){
descriptor.addFamily(new HColumnDescriptor(cf));
}
//根據(jù)對(duì)表的配置整份,創(chuàng)建表
admin.createTable(descriptor);
System.out.println("表" + tableName + "創(chuàng)建成功待错!");
}
}
6.2.4刪除表
public static void dropTable(String tableName) throws MasterNotRunningException,
?ZooKeeperConnectionException, IOException{
HBaseAdmin admin = new HBaseAdmin(conf);
if(isTableExist(tableName)){
admin.disableTable(tableName);
admin.deleteTable(tableName);
System.out.println("表" + tableName + "刪除成功!");
}else{
System.out.println("表" + tableName + "不存在烈评!");
}
}
6.2.5向表中插入數(shù)據(jù)
public static void addRowData(String tableName, String rowKey, String columnFamily, String
?column, String value) throws IOException{
//創(chuàng)建HTable對(duì)象
HTable hTable = new HTable(conf, tableName);
//向表中插入數(shù)據(jù)
Put put = new Put(Bytes.toBytes(rowKey));
//向Put對(duì)象中組裝數(shù)據(jù)
put.add(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value));
hTable.put(put);
hTable.close();
System.out.println("插入數(shù)據(jù)成功");
}
6.2.6刪除多行數(shù)據(jù)
public static void deleteMultiRow(String tableName, String... rows) throws IOException{
HTable hTable = new HTable(conf, tableName);
List<Delete> deleteList = new ArrayList<Delete>();
for(String row : rows){
Delete delete = new Delete(Bytes.toBytes(row));
deleteList.add(delete);
}
hTable.delete(deleteList);
hTable.close();
}
6.2.7獲取所有數(shù)據(jù)
public static void getAllRows(String tableName) throws IOException{
HTable hTable = new HTable(conf, tableName);
//得到用于掃描region的對(duì)象
Scan scan = new Scan();
//使用HTable得到resultcanner實(shí)現(xiàn)類的對(duì)象
ResultScanner resultScanner = hTable.getScanner(scan);
for(Result result : resultScanner){
Cell[] cells = result.rawCells();
for(Cell cell : cells){
//得到rowkey
System.out.println("行鍵:"?+?Bytes.toString(CellUtil.cloneRow(cell)));
//得到列族
System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
}
6.2.8獲取某一行數(shù)據(jù)
public static void getRow(String tableName, String rowKey) throws IOException{
HTable table = new HTable(conf, tableName);
Get get = new Get(Bytes.toBytes(rowKey));
//get.setMaxVersions();顯示所有版本
????//get.setTimeStamp();顯示指定時(shí)間戳的版本
Result result = table.get(get);
for(Cell cell : result.rawCells()){
System.out.println("行鍵:" + Bytes.toString(result.getRow()));
System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell)));
System.out.println("時(shí)間戳:" + cell.getTimestamp());
}
}
6.2.9獲取某一行指定“列族:列”的數(shù)據(jù)
public static void getRowQualifier(String tableName, String rowKey, String family, String
?qualifier) throws IOException{
HTable table = new HTable(conf, tableName);
Get get = new Get(Bytes.toBytes(rowKey));
get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
Result result = table.get(get);
for(Cell cell : result.rawCells()){
System.out.println("行鍵:" + Bytes.toString(result.getRow()));
System.out.println("列族" + Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println("列:" + Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println("值:" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
6.3 MapReduce
通過HBase的相關(guān)JavaAPI火俄,我們可以實(shí)現(xiàn)伴隨HBase操作的MapReduce過程,比如使用MapReduce將數(shù)據(jù)從本地文件系統(tǒng)導(dǎo)入到HBase的表中讲冠,比如我們從HBase中讀取一些原始數(shù)據(jù)后使用MapReduce做數(shù)據(jù)分析瓜客。
6.3.1官方HBase-MapReduce
1.查看HBase的MapReduce任務(wù)的執(zhí)行
$ bin/hbase mapredcp
2.環(huán)境變量的導(dǎo)入
(1)執(zhí)行環(huán)境變量的導(dǎo)入(臨時(shí)生效,在命令行執(zhí)行下述操作)
$ export HBASE_HOME=/opt/module/hbase-1.3.1
$ export HADOOP_HOME=/opt/module/hadoop-2.7.2
$ export HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase mapredcp`
(2)永久生效:在/etc/profile配置
export HBASE_HOME=/opt/module/hbase-1.3.1
export HADOOP_HOME=/opt/module/hadoop-2.7.2
并在hadoop-env.sh中配置:(注意:在for循環(huán)之后配)
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/opt/module/hbase/lib/*
3.運(yùn)行官方的MapReduce任務(wù)
--案例一:統(tǒng)計(jì)Student表中有多少行數(shù)據(jù)
$ /opt/module/hadoop-2.7.2/bin/yarn jar lib/hbase-server-1.3.1.jar rowcounter student
--案例二:使用MapReduce將本地?cái)?shù)據(jù)導(dǎo)入到HBase
1)在本地創(chuàng)建一個(gè)tsv格式的文件:fruit.tsv
1001 Apple Red
1002 Pear Yellow
1003 Pineapple Yellow
2)創(chuàng)建HBase表
hbase(main):001:0> create 'fruit','info'
3)在HDFS中創(chuàng)建input_fruit文件夾并上傳fruit.tsv文件
$ /opt/module/hadoop-2.7.2/bin/hdfs dfs -mkdir /input_fruit/
$ /opt/module/hadoop-2.7.2/bin/hdfs dfs -put fruit.tsv /input_fruit/
[if !supportLists]4)[endif]執(zhí)行MapReduce到HBase的fruit表中
$ /opt/module/hadoop-2.7.2/bin/yarn jar lib/hbase-server-1.3.1.jar importtsv \
-Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:color fruit \
hdfs://hadoop102:9000/input_fruit
[if !supportLists]5)[endif]使用scan命令查看導(dǎo)入后的結(jié)果
hbase(main):001:0> scan?‘fruit’
6.3.2自定義HBase-MapReduce1
目標(biāo):將fruit表中的一部分?jǐn)?shù)據(jù),通過MR遷入到fruit_mr表中谱仪。
分步實(shí)現(xiàn):
1.構(gòu)建ReadFruitMapper類玻熙,用于讀取fruit表中的數(shù)據(jù)
package com.atguigu;
import java.io.IOException;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;
public class ReadFruitMapper extends TableMapper<ImmutableBytesWritable, Put> {
@Override
protected void map(ImmutableBytesWritable key, Result value, Context context)
throws IOException, InterruptedException {
//將fruit的name和color提取出來,相當(dāng)于將每一行數(shù)據(jù)讀取出來放入到Put對(duì)象中芽卿。
Put put = new Put(key.get());
//遍歷添加column行
for(Cell cell: value.rawCells()){
//添加/克隆列族:info
if("info".equals(Bytes.toString(CellUtil.cloneFamily(cell)))){
//添加/克隆列:name
if("name".equals(Bytes.toString(CellUtil.cloneQualifier(cell)))){
//將該列cell加入到put對(duì)象中
put.add(cell);
//添加/克隆列:color
}else if("color".equals(Bytes.toString(CellUtil.cloneQualifier(cell)))){
//向該列cell加入到put對(duì)象中
put.add(cell);
}
}
}
//將從fruit讀取到的每行數(shù)據(jù)寫入到context中作為map的輸出
context.write(key, put);
}
}
2. 構(gòu)建WriteFruitMRReducer類揭芍,用于將讀取到的fruit表中的數(shù)據(jù)寫入到fruit_mr表中
package com.atguigu.hbase_mr;
import java.io.IOException;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.NullWritable;
public class WriteFruitMRReducer extends TableReducer<ImmutableBytesWritable, Put, NullWritable> {
@Override
protected void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context)
throws IOException, InterruptedException {
//讀出來的每一行數(shù)據(jù)寫入到fruit_mr表中
for(Put put: values){
context.write(NullWritable.get(), put);
}
}
}
3.構(gòu)建Fruit2FruitMRRunner extends Configured implements Tool用于組裝運(yùn)行Job任務(wù)
//組裝Job
public int run(String[] args) throws Exception {
//得到Configuration
Configuration conf = this.getConf();
//創(chuàng)建Job任務(wù)
Job job = Job.getInstance(conf, this.getClass().getSimpleName());
job.setJarByClass(Fruit2FruitMRRunner.class);
//配置Job
Scan scan = new Scan();
scan.setCacheBlocks(false);
scan.setCaching(500);
//設(shè)置Mapper,注意導(dǎo)入的是mapreduce包下的卸例,不是mapred包下的称杨,后者是老版本
TableMapReduceUtil.initTableMapperJob(
"fruit", //數(shù)據(jù)源的表名
scan, //scan掃描控制器
ReadFruitMapper.class,//設(shè)置Mapper類
ImmutableBytesWritable.class,//設(shè)置Mapper輸出key類型
Put.class,//設(shè)置Mapper輸出value值類型
job//設(shè)置給哪個(gè)JOB
);
//設(shè)置Reducer
TableMapReduceUtil.initTableReducerJob("fruit_mr", WriteFruitMRReducer.class, job);
//設(shè)置Reduce數(shù)量,最少1個(gè)
job.setNumReduceTasks(1);
boolean isSuccess = job.waitForCompletion(true);
if(!isSuccess){
throw new IOException("Job running with error");
}
return isSuccess ? 0 : 1;
}
4.主函數(shù)中調(diào)用運(yùn)行該Job任務(wù)
public static void main( String[] args ) throws Exception{
Configuration conf = HBaseConfiguration.create();
int status = ToolRunner.run(conf, new Fruit2FruitMRRunner(), args);
System.exit(status);
}
5.打包運(yùn)行任務(wù)
$ /opt/module/hadoop-2.7.2/bin/yarn jar ~/softwares/jars/hbase-0.0.1-SNAPSHOT.jar
?com.z.hbase.mr1.Fruit2FruitMRRunner
提示:運(yùn)行任務(wù)前筷转,如果待數(shù)據(jù)導(dǎo)入的表不存在姑原,則需要提前創(chuàng)建。
提示:maven打包命令:-P local?clean package或-P dev?clean package install(將第三方j(luò)ar包一同打包呜舒,需要插件:maven-shade-plugin)
6.3.3自定義HBase-MapReduce2
目標(biāo):實(shí)現(xiàn)將HDFS中的數(shù)據(jù)寫入到HBase表中锭汛。
分步實(shí)現(xiàn):
1.構(gòu)建ReadFruitFromHDFSMapper于讀取HDFS中的文件數(shù)據(jù)
package com.atguigu;
import java.io.IOException;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class ReadFruitFromHDFSMapper extends Mapper<LongWritable, Text, ImmutableBytesWritable, Put> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//從HDFS中讀取的數(shù)據(jù)
String lineValue = value.toString();
//讀取出來的每行數(shù)據(jù)使用\t進(jìn)行分割,存于String數(shù)組
String[] values = lineValue.split("\t");
//根據(jù)數(shù)據(jù)中值的含義取值
String rowKey = values[0];
String name = values[1];
String color = values[2];
//初始化rowKey
ImmutableBytesWritable rowKeyWritable = new ImmutableBytesWritable(Bytes.toBytes(rowKey));
//初始化put對(duì)象
Put put = new Put(Bytes.toBytes(rowKey));
//參數(shù)分別:列族袭蝗、列唤殴、值 ?
????????put.add(Bytes.toBytes("info"), Bytes.toBytes("name"), ?Bytes.toBytes(name));
????????put.add(Bytes.toBytes("info"), Bytes.toBytes("color"), ?Bytes.toBytes(color));
????????context.write(rowKeyWritable, put);
}
}
2.構(gòu)建WriteFruitMRFromTxtReducer類
package com.z.hbase.mr2;
import java.io.IOException;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.NullWritable;
public class WriteFruitMRFromTxtReducer extends TableReducer<ImmutableBytesWritable, Put, NullWritable> {
@Override
protected void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context) throws IOException, InterruptedException {
//讀出來的每一行數(shù)據(jù)寫入到fruit_hdfs表中
for(Put put: values){
context.write(NullWritable.get(), put);
}
}
}
3.創(chuàng)建Txt2FruitRunner組裝Job
public int run(String[] args) throws Exception {
//得到Configuration
Configuration conf = this.getConf();
//創(chuàng)建Job任務(wù)
Job job = Job.getInstance(conf, this.getClass().getSimpleName());
job.setJarByClass(Txt2FruitRunner.class);
Path inPath = new Path("hdfs://hadoop102:9000/input_fruit/fruit.tsv");
FileInputFormat.addInputPath(job, inPath);
//設(shè)置Mapper
job.setMapperClass(ReadFruitFromHDFSMapper.class);
job.setMapOutputKeyClass(ImmutableBytesWritable.class);
job.setMapOutputValueClass(Put.class);
//設(shè)置Reducer
TableMapReduceUtil.initTableReducerJob("fruit_mr", WriteFruitMRFromTxtReducer.class, job);
//設(shè)置Reduce數(shù)量,最少1個(gè)
job.setNumReduceTasks(1);
boolean isSuccess = job.waitForCompletion(true);
if(!isSuccess){
throw new IOException("Job running with error");
}
return isSuccess ? 0 : 1;
}
4.調(diào)用執(zhí)行Job
public static void main(String[] args) throws Exception {
Configuration conf = HBaseConfiguration.create();
????int status = ToolRunner.run(conf, new Txt2FruitRunner(), args);
????System.exit(status);
}
5.打包運(yùn)行
$ /opt/module/hadoop-2.7.2/bin/yarn jar hbase-0.0.1-SNAPSHOT.jar?com.atguigu.hbase.mr2.Txt2FruitRunner
提示:運(yùn)行任務(wù)前到腥,如果待數(shù)據(jù)導(dǎo)入的表不存在朵逝,則需要提前創(chuàng)建之。
提示:maven打包命令:-P local?clean package或-P dev?clean package install(將第三方j(luò)ar包一同打包乡范,需要插件:maven-shade-plugin)
6.4與Hive的集成
6.4.1 HBase與Hive的對(duì)比
1.Hive
(1)數(shù)據(jù)倉庫
Hive的本質(zhì)其實(shí)就相當(dāng)于將HDFS中已經(jīng)存儲(chǔ)的文件在Mysql中做了一個(gè)雙射關(guān)系配名,以方便使用HQL去管理查詢。
(2)用于數(shù)據(jù)分析晋辆、清洗
Hive適用于離線的數(shù)據(jù)分析和清洗渠脉,延遲較高。
(3)基于HDFS瓶佳、MapReduce
Hive存儲(chǔ)的數(shù)據(jù)依舊在DataNode上芋膘,編寫的HQL語句終將是轉(zhuǎn)換為MapReduce代碼執(zhí)行。
2.HBase
(1)數(shù)據(jù)庫
是一種面向列存儲(chǔ)的非關(guān)系型數(shù)據(jù)庫霸饲。
(2)用于存儲(chǔ)結(jié)構(gòu)化和非結(jié)構(gòu)化的數(shù)據(jù)
適用于單表非關(guān)系型數(shù)據(jù)的存儲(chǔ)索赏,不適合做關(guān)聯(lián)查詢,類似JOIN等操作贴彼。
(3)基于HDFS
數(shù)據(jù)持久化存儲(chǔ)的體現(xiàn)形式是Hfile,存放于DataNode中埃儿,被ResionServer以region的形式進(jìn)行管理器仗。
(4)延遲較低,接入在線業(yè)務(wù)使用
面對(duì)大量的企業(yè)數(shù)據(jù),HBase可以直線單表大量數(shù)據(jù)的存儲(chǔ)精钮,同時(shí)提供了高效的數(shù)據(jù)訪問速度威鹿。
6.4.2 HBase與Hive集成使用
尖叫提示:HBase與Hive的集成在最新的兩個(gè)版本中無法兼容。所以轨香,我們只能含著淚勇敢的重新編譯:hive-hbase-handler-1.2.2.jar:瞿恪!好氣1廴荨科雳!
環(huán)境準(zhǔn)備
因?yàn)槲覀兒罄m(xù)可能會(huì)在操作Hive的同時(shí)對(duì)HBase也會(huì)產(chǎn)生影響,所以Hive需要持有操作HBase的Jar脓杉,那么接下來拷貝Hive所依賴的Jar包(或者使用軟連接的形式)糟秘。
export HBASE_HOME=/opt/module/hbase
export HIVE_HOME=/opt/module/hive
ln -s $HBASE_HOME/lib/hbase-common-1.3.1.jar ?$HIVE_HOME/lib/hbase-common-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-server-1.3.1.jar $HIVE_HOME/lib/hbase-server-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-client-1.3.1.jar $HIVE_HOME/lib/hbase-client-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-protocol-1.3.1.jar $HIVE_HOME/lib/hbase-protocol-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-it-1.3.1.jar $HIVE_HOME/lib/hbase-it-1.3.1.jar
ln -s $HBASE_HOME/lib/htrace-core-3.1.0-incubating.jar $HIVE_HOME/lib/htrace-core-3.1.0-incubating.jar
ln -s $HBASE_HOME/lib/hbase-hadoop2-compat-1.3.1.jar $HIVE_HOME/lib/hbase-hadoop2-compat-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-hadoop-compat-1.3.1.jar $HIVE_HOME/lib/hbase-hadoop-compat-1.3.1.jar
同時(shí)在hive-site.xml中修改zookeeper的屬性,如下:
<property>
??<name>hive.zookeeper.quorum</name>
??<value>hadoop102,hadoop103,hadoop104</value>
??<description>The list of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
<property>
??<name>hive.zookeeper.client.port</name>
??<value>2181</value>
??<description>The port of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
1.案例一
目標(biāo):建立Hive表球散,關(guān)聯(lián)HBase表尿赚,插入數(shù)據(jù)到Hive表的同時(shí)能夠影響HBase表。
分步實(shí)現(xiàn):
(1) 在Hive中創(chuàng)建表同時(shí)關(guān)聯(lián)HBase
CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
提示:完成之后蕉堰,可以分別進(jìn)入Hive和HBase查看凌净,都生成了對(duì)應(yīng)的表
(2)在Hive中創(chuàng)建臨時(shí)中間表,用于load文件中的數(shù)據(jù)
提示:不能將數(shù)據(jù)直接load進(jìn)Hive所關(guān)聯(lián)HBase的那張表中
CREATE TABLE emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';
(3)向Hive中間表中l(wèi)oad數(shù)據(jù)
hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;
(4)通過insert命令將中間表中的數(shù)據(jù)導(dǎo)入到Hive關(guān)聯(lián)HBase的那張表中
hive> insert into table hive_hbase_emp_table select * from emp;
(5)查看Hive以及關(guān)聯(lián)的HBase表中是否已經(jīng)成功的同步插入了數(shù)據(jù)
Hive:
hive> select?*?from?hive_hbase_emp_table;
HBase:
hbase> scan ‘hbase_emp_table’
2.案例二
目標(biāo):在HBase中已經(jīng)存儲(chǔ)了某一張表hbase_emp_table屋讶,然后在Hive中創(chuàng)建一個(gè)外部表來關(guān)聯(lián)HBase中的hbase_emp_table這張表冰寻,使之可以借助Hive來分析HBase這張表中的數(shù)據(jù)。
注:該案例2緊跟案例1的腳步丑婿,所以完成此案例前性雄,請(qǐng)先完成案例1。
分步實(shí)現(xiàn):
(1)在Hive中創(chuàng)建外部表
CREATE EXTERNAL TABLE relevance_hbase_emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY
'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" =
":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")?
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
(2) 關(guān)聯(lián)后就可以使用Hive函數(shù)進(jìn)行一些分析操作了
hive (default)> select * from relevance_hbase_emp;
七羹奉、HBase優(yōu)化
7.1高可用
在HBase中Hmaster負(fù)責(zé)監(jiān)控RegionServer的生命周期秒旋,均衡RegionServer的負(fù)載,如果Hmaster掛掉了诀拭,那么整個(gè)HBase集群將陷入不健康的狀態(tài)迁筛,并且此時(shí)的工作狀態(tài)并不會(huì)維持太久。所以HBase支持對(duì)Hmaster的高可用配置耕挨。
1.關(guān)閉HBase集群(如果沒有開啟則跳過此步)
[atguigu@hadoop102 hbase]$ bin/stop-hbase.sh
2.在conf目錄下創(chuàng)建backup-masters文件
[atguigu@hadoop102 hbase]$ touch conf/backup-masters
3.在backup-masters文件中配置高可用HMaster節(jié)點(diǎn)
[atguigu@hadoop102 hbase]$ echo hadoop103 > conf/backup-masters
4.將整個(gè)conf目錄scp到其他節(jié)點(diǎn)
[atguigu@hadoop102 hbase]$ scp -r conf/ hadoop103:/opt/module/hbase/
[atguigu@hadoop102 hbase]$ scp -r conf/ hadoop104:/opt/module/hbase/
5.打開頁面測(cè)試查看
7.2預(yù)分區(qū)
每一個(gè)region維護(hù)著startRow與endRowKey细卧,如果加入的數(shù)據(jù)符合某個(gè)region維護(hù)的rowKey范圍,則該數(shù)據(jù)交給這個(gè)region維護(hù)筒占。那么依照這個(gè)原則贪庙,我們可以將數(shù)據(jù)所要投放的分區(qū)提前大致的規(guī)劃好,以提高HBase性能翰苫。
1.手動(dòng)設(shè)定預(yù)分區(qū)
hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']
2.生成16進(jìn)制序列預(yù)分區(qū)
create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
3.按照文件中設(shè)置的規(guī)則預(yù)分區(qū)
創(chuàng)建splits.txt文件內(nèi)容如下:
aaaa
bbbb
cccc
dddd
然后執(zhí)行:
create 'staff3','partition3',SPLITS_FILE => 'splits.txt'
4.使用JavaAPI創(chuàng)建預(yù)分區(qū)
//自定義算法止邮,產(chǎn)生一系列Hash散列值存儲(chǔ)在二維數(shù)組中
byte[][] splitKeys =某個(gè)散列值函數(shù)
//創(chuàng)建HBaseAdmin實(shí)例
HBaseAdmin hAdmin = new HBaseAdmin(HBaseConfiguration.create());
//創(chuàng)建HTableDescriptor實(shí)例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通過HTableDescriptor實(shí)例和散列值二維數(shù)組創(chuàng)建帶有預(yù)分區(qū)的HBase表
hAdmin.createTable(tableDesc, splitKeys);
7.3 RowKey設(shè)計(jì)
一條數(shù)據(jù)的唯一標(biāo)識(shí)就是rowkey这橙,那么這條數(shù)據(jù)存儲(chǔ)于哪個(gè)分區(qū),取決于rowkey處于哪個(gè)一個(gè)預(yù)分區(qū)的區(qū)間內(nèi)导披,設(shè)計(jì)rowkey的主要目的 屈扎,就是讓數(shù)據(jù)均勻的分布于所有的region中,在一定程度上防止數(shù)據(jù)傾斜撩匕。接下來我們就談一談rowkey常用的設(shè)計(jì)方案鹰晨。
1.生成隨機(jī)數(shù)、hash止毕、散列值
比如:
原本rowKey為1001的模蜡,SHA1后變成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7
原本rowKey為3001的,SHA1后變成:49042c54de64a1e9bf0b33e00245660ef92dc7bd
原本rowKey為5001的滓技,SHA1后變成:7b61dec07e02c188790670af43e717f0f46e8913
在做此操作之前哩牍,一般我們會(huì)選擇從數(shù)據(jù)集中抽取樣本,來決定什么樣的rowKey來Hash后作為每個(gè)分區(qū)的臨界值令漂。
2.字符串反轉(zhuǎn)
20170524000001轉(zhuǎn)成10000042507102
20170524000002轉(zhuǎn)成20000042507102
這樣也可以在一定程度上散列逐步put進(jìn)來的數(shù)據(jù)膝昆。
3.字符串拼接
20170524000001_a12e
20170524000001_93i7
7.4內(nèi)存優(yōu)化
HBase操作過程中需要大量的內(nèi)存開銷,畢竟Table是可以緩存在內(nèi)存中的叠必,一般會(huì)分配整個(gè)可用內(nèi)存的70%給HBase的Java堆荚孵。但是不建議分配非常大的堆內(nèi)存,因?yàn)镚C過程持續(xù)太久會(huì)導(dǎo)致RegionServer處于長(zhǎng)期不可用狀態(tài)纬朝,一般16~48G內(nèi)存就可以了收叶,如果因?yàn)榭蚣苷加脙?nèi)存過高導(dǎo)致系統(tǒng)內(nèi)存不足,框架一樣會(huì)被系統(tǒng)服務(wù)拖死共苛。
7.5基礎(chǔ)優(yōu)化
1.允許在HDFS的文件中追加內(nèi)容
hdfs-site.xml判没、hbase-site.xml
屬性:dfs.support.append
解釋:開啟HDFS追加同步,可以優(yōu)秀的配合HBase的數(shù)據(jù)同步和持久化隅茎。默認(rèn)值為true澄峰。
2.優(yōu)化DataNode允許的最大文件打開數(shù)
hdfs-site.xml
屬性:dfs.datanode.max.transfer.threads
解釋:HBase一般都會(huì)同一時(shí)間操作大量的文件,根據(jù)集群的數(shù)量和規(guī)模以及數(shù)據(jù)動(dòng)作辟犀,設(shè)置為4096或者更高俏竞。默認(rèn)值:4096
3.優(yōu)化延遲高的數(shù)據(jù)操作的等待時(shí)間
hdfs-site.xml
屬性:dfs.image.transfer.timeout
解釋:如果對(duì)于某一次數(shù)據(jù)操作來講,延遲非常高堂竟,socket需要等待更長(zhǎng)的時(shí)間魂毁,建議把該值設(shè)置為更大的值(默認(rèn)60000毫秒),以確保socket不會(huì)被timeout掉出嘹。
4.優(yōu)化數(shù)據(jù)的寫入效率
mapred-site.xml
屬性:
mapreduce.map.output.compress
mapreduce.map.output.compress.codec
解釋:開啟這兩個(gè)數(shù)據(jù)可以大大提高文件的寫入效率席楚,減少寫入時(shí)間。第一個(gè)屬性值修改為true税稼,第二個(gè)屬性值修改為:org.apache.hadoop.io.compress.GzipCodec或者其他壓縮方式烦秩。
5.設(shè)置RPC監(jiān)聽數(shù)量
hbase-site.xml
屬性:hbase.regionserver.handler.count
解釋:默認(rèn)值為30刁赦,用于指定RPC監(jiān)聽的數(shù)量,可以根據(jù)客戶端的請(qǐng)求數(shù)進(jìn)行調(diào)整闻镶,讀寫請(qǐng)求較多時(shí),增加此值丸升。
6.優(yōu)化HStore文件大小
hbase-site.xml
屬性:hbase.hregion.max.filesize
解釋:默認(rèn)值10737418240(10GB)铆农,如果需要運(yùn)行HBase的MR任務(wù),可以減小此值狡耻,因?yàn)橐粋€(gè)region對(duì)應(yīng)一個(gè)map任務(wù)墩剖,如果單個(gè)region過大,會(huì)導(dǎo)致map任務(wù)執(zhí)行時(shí)間過長(zhǎng)夷狰。該值的意思就是岭皂,如果HFile的大小達(dá)到這個(gè)數(shù)值,則這個(gè)region會(huì)被切分為兩個(gè)Hfile沼头。
7.優(yōu)化hbase客戶端緩存
hbase-site.xml
屬性:hbase.client.write.buffer
解釋:用于指定HBase客戶端緩存爷绘,增大該值可以減少RPC調(diào)用次數(shù),但是會(huì)消耗更多內(nèi)存进倍,反之則反之土至。一般我們需要設(shè)定一定的緩存大小,以達(dá)到減少RPC次數(shù)的目的猾昆。
8.指定scan.next掃描HBase所獲取的行數(shù)
hbase-site.xml
屬性:hbase.client.scanner.caching
解釋:用于指定scan.next方法獲取的默認(rèn)行數(shù)陶因,值越大,消耗內(nèi)存越大垂蜗。
9.flush楷扬、compact、split機(jī)制
當(dāng)MemStore達(dá)到閾值贴见,將Memstore中的數(shù)據(jù)Flush進(jìn)Storefile烘苹;compact機(jī)制則是把flush出來的小文件合并成大的Storefile文件。split則是當(dāng)Region達(dá)到閾值蝇刀,會(huì)把過大的Region一分為二螟加。
涉及屬性:
即:128M就是Memstore的默認(rèn)閾值
hbase.hregion.memstore.flush.size:134217728
即:這個(gè)參數(shù)的作用是當(dāng)單個(gè)HRegion內(nèi)所有的Memstore大小總和超過指定值時(shí),flush該HRegion的所有memstore吞琐。RegionServer的flush是通過將請(qǐng)求添加一個(gè)隊(duì)列捆探,模擬生產(chǎn)消費(fèi)模型來異步處理的。那這里就有一個(gè)問題站粟,當(dāng)隊(duì)列來不及消費(fèi)黍图,產(chǎn)生大量積壓請(qǐng)求時(shí),可能會(huì)導(dǎo)致內(nèi)存陡增奴烙,最壞的情況是觸發(fā)OOM助被。
hbase.regionserver.global.memstore.upperLimit:0.4
hbase.regionserver.global.memstore.lowerLimit:0.38
即:當(dāng)MemStore使用內(nèi)存總量達(dá)到hbase.regionserver.global.memstore.upperLimit指定值時(shí)剖张,將會(huì)有多個(gè)MemStores flush到文件中,MemStore flush 順序是按照大小降序執(zhí)行的揩环,直到刷新到MemStore使用內(nèi)存略小于lowerLimit