16. HBase高級(jí)應(yīng)用

1. HBase存儲(chǔ)中的3個(gè)核心機(jī)制

1.flush機(jī)制:
當(dāng)MemStore達(dá)到閾值之后,會(huì)flush成一個(gè)StoreFile (也就是內(nèi)存中的數(shù)據(jù)寫(xiě)入了磁盤(pán))。
2.compact機(jī)制:
當(dāng)StoreFile達(dá)到閾值時(shí),合并StoreFile。合并過(guò)程中cell版本合并和數(shù)據(jù)刪除。
3.split機(jī)制:
當(dāng)region不斷增大,達(dá)到閾值,region會(huì)分成兩個(gè)新的region。

2.HBase Java API使用

1. 為HBase Java編程準(zhǔn)備開(kāi)發(fā)環(huán)境

使用java進(jìn)行HBase編程,pom文件需要添加2個(gè)依賴,分別是hbase-client 、 hbase-server(可以沒(méi)有)、hadoop-client。

查看HBase的API文檔,以下幾個(gè)類是比較常用的,需要熟悉:
HBaseAdmin (管理操作、創(chuàng)建表等)
HTable (操作表、上傳數(shù)據(jù))
Configuration

HBase的java API開(kāi)發(fā)與HBase shell的命令基本上是一致的。例如shell中的put操作,對(duì)應(yīng)著API中的Put對(duì)象。

2. 添加IDE依賴的jar包:

HBase的開(kāi)發(fā),需要在pom.xml中引入 hbase-client、hbase-server和hadoop-client幾個(gè)依賴包(選取的版本是:hadoop: 2.5.0 ; hbase:0.98.6-hadoop2),如下是pom.xml定義:

<properties>
    <hadoop.version>2.5.0</hadoop.version>
    <hbase.version>0.98.6-hadoop2</hbase.version>
</properties>
<dependencies>
    <!-- hbase client -->
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-client</artifactId>
      <version>${hbase.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-server</artifactId>
      <version>${hbase.version}</version>
    </dependency>
    
    <!-- hadoop client -->
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-client</artifactId>
      <version>${hadoop.version}</version>
    </dependency>
</dependencies>

3. 添加配置文件:

需要將HBase和Hadoop的配置文件,添加到項(xiàng)目的Classpath。新建“Source Folder”:src/main/resources,將hadoop和hbase安裝目錄下的配置文件挪到這個(gè)目錄下(主要是core-site.xml、hdfs-site.xml和hbase-site.xml):


Resources文件.png

4. 獲取HBase配置環(huán)境信息:

在使用Java API時(shí),Client端需要知道HBase的環(huán)境配置,使用Configuration類來(lái)封裝該信息。

Configuration conf = HBaseConfiguration.create();

在創(chuàng)建該對(duì)象時(shí),首先在classpath中尋找hbase-site.xml文件來(lái)讀取配置,如果不存在該文件,則尋找hbase-default.xml文件來(lái)讀取配置(也就是默認(rèn)配置)。

5. Get獲取數(shù)據(jù):

使用Get對(duì)象獲取數(shù)據(jù):

      // 抽象的獲取HTable對(duì)象的靜態(tài)方法,返回HTable對(duì)象
    public static HTable getTable (String tablename) throws IOException {
        Configuration conf = HBaseConfiguration.create();
        HTable table = new HTable(conf,tablename);
        return table;
    }
    
    //根據(jù)row_key返回這條記錄中的信息
    public static void getByRowKey(String tablename,String rowkey) 
            throws IOException
    {
        HTable table = HBaseAPIOper.getTable(tablename);
        
        //Get Object is bound to one row(identified by rowkey)
        Get get = new Get(Bytes.toBytes(rowkey));
        
        Result rs = table.get(get);
        
        Cell[] cells = rs.rawCells();
        for (Cell cell : cells){
            System.out.print( Bytes.toString(CellUtil.cloneFamily(cell)) + ":" );
            System.out.print( Bytes.toString(CellUtil.cloneQualifier(cell)) + "=>" );
            System.out.print( Bytes.toString(CellUtil.cloneValue(cell)) + "\n"  );
        }
        
        table.close();
    }
    
    //返回某個(gè)row_key、某個(gè)列族、某個(gè)列的數(shù)據(jù)(只返回指定列的信息)
    public static void getByColumns (String tablename,String rowkey,
            String family,String qualifier) throws IOException{
        HTable table = HBaseAPIOper.getTable(tablename);
        
        //Get Object is bound to one row(identified by rowkey)
        Get get = new Get(Bytes.toBytes(rowkey));
        
        get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
        
        Result rs = table.get(get);
        
        Cell[] cells = rs.rawCells();
        for (Cell cell : cells){
            System.out.print( Bytes.toString(CellUtil.cloneFamily(cell)) + ":" );
            System.out.print( Bytes.toString(CellUtil.cloneQualifier(cell)) + "=>" );
            System.out.print( Bytes.toString(CellUtil.cloneValue(cell)) + "\n"  );
        }
        
        table.close();
    }

Get get = new Get(rowkey的字節(jié)數(shù)組)。 Get對(duì)象和rowkey進(jìn)行綁定。Result result = HTable對(duì)象.get(Get對(duì)象)。下面遍歷結(jié)果集,使用rawCells()方法,獲取所有查到的單元格信息。CellUtil類,是用于操作單元格的工具類,CellUtil.cloneFamily()獲取列族信息,CellUtil.cloneQualifier()獲取列信息,CellUtil.cloneValue()獲取對(duì)應(yīng)的值。為了防止資源使用崩潰,一定要記得關(guān)閉table對(duì)象。
同時(shí),也可以通過(guò)操作Get對(duì)象,來(lái)限定只顯示部分列。get.addColumn("列族","列名")

6. Put插入數(shù)據(jù):

實(shí)體信息的插入,通過(guò)put操作完成。

// Put rows by rowkey (Auto Generated!!)
    public static void putRows(String tablename) throws IOException{        
        HTable table = HBaseAPIOper.getTable(tablename);
        long rowkey = System.currentTimeMillis();
        // The Integer rowkey must be cast to String.
        Put put0 = new Put(Bytes.toBytes(Long.toString(rowkey)));
        put0.add(
                Bytes.toBytes("info"), 
                Bytes.toBytes("name"), 
                Bytes.toBytes("natty") 
                )   ;
        put0.add(
                Bytes.toBytes("info"), 
                Bytes.toBytes("age"), 
                Bytes.toBytes("31") 
                )   ;
        
        // The Integer rowkey must be cast to String.
        Put put1 = new Put(Bytes.toBytes(Long.toString(rowkey + 1)));
        put1.add(
                Bytes.toBytes("info"), 
                Bytes.toBytes("name"), 
                Bytes.toBytes("natty") 
                )   ;
        put1.add(
                Bytes.toBytes("info"), 
                Bytes.toBytes("age"), 
                Bytes.toBytes("31") 
                )   ;
        
        ArrayList<Put> list = new ArrayList<Put>();
        list.add(put0);
        list.add(put1);
        table.put(list);
        table.close();
    }

put操作對(duì)應(yīng)于Put對(duì)象。創(chuàng)建Put對(duì)象, Put put = new Put(rowkey對(duì)應(yīng)的字節(jié)數(shù)組);之后添加列信息,put.add("列族","列名","列值"),通過(guò)多次put.add()可以一次添加多個(gè)列值信息。將列信息添加到表格,表格對(duì)象.put(Put對(duì)象),或者添加多個(gè)put對(duì)象,表格對(duì)象.put(含有多個(gè)Put對(duì)象的list集合)。

7. Delete刪除數(shù)據(jù)和Update數(shù)據(jù):

刪除數(shù)據(jù)需要使用Delete對(duì)象, Delete delete = new Delete(行鍵對(duì)應(yīng)的字節(jié)數(shù)組)。指定要?jiǎng)h除的列(列族),delete.deleteColumn("列族","列名")

    public static void deleteByRowkey(String tablename,String rowkey) 
            throws IOException{
        HTable table = HBaseAPIOper.getTable(tablename);
        Delete del = new Delete(Bytes.toBytes(rowkey));
        
        //delete all the family
        del.deleteFamily(Bytes.toBytes("info"));
        //delete just one column
        del.deleteColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
        table.delete(del);
        table.close();
    }

HBase中Update操作也使用Put對(duì)象完成,操作方法與插入操作完全一致。

8. Scan操作:

ResultScanner是由查詢結(jié)果Result對(duì)象組成的,可以通過(guò)2次遍歷獲取數(shù)據(jù)。getRow()獲得行鍵。另外,也可以使用IOUtils.closeStream()來(lái)關(guān)閉table對(duì)象等資源。通過(guò)setStartRow()和setStopRow()方法,限定scan的查詢范圍。通過(guò)scan.addFamily()或者scan.addColumn()增加通過(guò)列族/列篩選數(shù)據(jù)。

    public static void scanByTable(String tablename) throws IOException
    {
        HTable table = HBaseAPIOper.getTable(tablename);
        
        Scan scan = new Scan();
        //make the scope of scan.
        // >= setStartRow()  AND  < setStopRow() 
        scan.setStartRow(Bytes.toBytes("10001"));
        scan.setStopRow(Bytes.toBytes("10004"));
        
        //filter the data through Family or Column
        scan.addFamily(Bytes.toBytes("info"));
        scan.addColumn(Bytes.toBytesBinary("info"), Bytes.toBytes("name"));
        
        ResultScanner resultscanner = table.getScanner(scan);
        
        for (Result result:resultscanner)
        {
            // getRow() method can get the rowkey.
            System.out.println(Bytes.toString(result.getRow()));
            Cell[] cells = result.rawCells();
            for (Cell cell : cells){
                System.out.print( Bytes.toString(CellUtil.cloneFamily(cell)) + ":" );
                System.out.print( Bytes.toString(CellUtil.cloneQualifier(cell)) + "=>" );
                System.out.print( Bytes.toString(CellUtil.cloneValue(cell)) + "\n"  );
            }
        }
        IOUtils.closeStream(resultscanner);
        IOUtils.closeStream(table);
    }

3.HBase架構(gòu)深入總結(jié)

1.客戶端作用:

1.整個(gè)HBase集群的訪問(wèn)入口;
2.使用HBase RPC機(jī)制與HMaster 和 HRegionServer通信。
3.與HMaser通信進(jìn)行管理類操作。
4.與HRegionServer通信進(jìn)行數(shù)據(jù)讀寫(xiě)類操作。

2.Zookeeper作用:

1.實(shí)現(xiàn)HMaster的HA,保證集群中只有一個(gè)HMaster。
2.保存root region的位置(meta表),Region的尋址入口。
客戶端在訪問(wèn)表時(shí),需要找到表的每個(gè)region對(duì)應(yīng)的RegionServer(管理Region的角色)。Root(新版本是meta)表存儲(chǔ)了Region的分布情況以及每個(gè)Region的詳細(xì)信息。
3.實(shí)時(shí)監(jiān)控RegionServer的上下線信息,并及時(shí)通知Master。
4.存儲(chǔ)HBase的schema和table元數(shù)據(jù)(有哪些表、每個(gè)表有哪些列族)。

3.HMaster作用和特點(diǎn):

1.HMaster作用:
(1). HMaster負(fù)責(zé)Table和Region的管理工作,為RegionServer分配Region。
(2). 管理Region Server的負(fù)載均衡(為每一個(gè)Region Server分配多少Region),調(diào)整Region分布。
(3). 當(dāng)某一個(gè)Region Server停機(jī)下線后,負(fù)責(zé)失效Region Server上的Region的遷移。
(4). 監(jiān)聽(tīng)zookeeper,基于zookeeper來(lái)得知Region Server上下線。
(5). 監(jiān)聽(tīng)zookeeper,基于zookeeper來(lái)保證Master的HA
2.HMaster的特點(diǎn):
(1)HMaster沒(méi)有單點(diǎn)故障問(wèn)題(SPOF:Single Point Of Failure)。HBase可以啟動(dòng)多個(gè)HMaster,Zookeeper保證只有一個(gè)HMaster運(yùn)行。
啟動(dòng)backup master節(jié)點(diǎn)方法:在conf下修改配置文件backup-masters,通過(guò)hbase-daemons.sh腳本啟動(dòng)backup master。

$bin/hbase-daemons.sh start master-backup

(2)不參與客戶端數(shù)據(jù)讀寫(xiě)
(3)HMaster的負(fù)載很低(在同一個(gè)主機(jī)上可以和NN、SNN等服務(wù)共同運(yùn)行)。

4.Region Server的作用:

  1. 維護(hù)Region(HMaster分配的),響應(yīng)客戶端的IO訪問(wèn)請(qǐng)求(讀寫(xiě)),向HDFS讀寫(xiě)數(shù)據(jù)。
  2. 負(fù)責(zé)處理region的 flush、compact、split 幾個(gè)過(guò)程。
  3. 維護(hù)region的cache
HBase與Zookeeper的關(guān)系.png

4.HBase數(shù)據(jù)檢索三種方式

HBase的數(shù)據(jù)檢索,主要提供了3種方式,分別是:Get方式檢索、Scan范圍檢索、Scan全表掃描。

  1. Get方式:
    Get需要使用rowkey作為參數(shù)檢索。
    在hbase shell中使用get命令
    在java API中使用Get對(duì)象。
  2. Scan 范圍搜索:
    依據(jù)rowkey匹配查找,默認(rèn)根據(jù)rowkey匹配
    在hbase shell中使用scan命令
    在java API中使用Scan對(duì)象。
  3. Scan 全部掃描:
    全表掃描
    和MapReduce/Spark一起使用。

5.HBase與MapReduce集成

1.HBase和MapReduce的整合場(chǎng)景:

第一種應(yīng)用場(chǎng)景: 文本文檔txt或者csv文件導(dǎo)入到HBase中。
第二種應(yīng)用場(chǎng)景: HBase的表導(dǎo)成另外一個(gè)表。
Data Source(數(shù)據(jù)源): 。本地、HBASE表、HDFS
Data Sink: 數(shù)據(jù)寫(xiě)進(jìn)哪個(gè)地方。
Data Source & Data Sink:

2.HBase和MapReduce的原因和方法:

  1. 為什么使用MapReduce導(dǎo)入:
    MapReduce是并行處理框架,比較快。
  2. HBase和MapReduce整合的方法:
    使用如下命令可以返回hbase的classpath的jar包:
$ bin/hbase mapredcp

查看命令的具體含義:

$ bin/hbase 

3.HBase的默認(rèn)MapReduce程序:

HBase默認(rèn)集成了一些mapreduce程序。這些程序存放在這個(gè)jar包(HBase的安裝目錄下)中 :
/opt/modules/hbase-0.98.6-cdh5.3.6/lib/hbase-server-0.98.6-cdh5.3.6.jar
下面,我們執(zhí)行這個(gè)jar包:
(1) 導(dǎo)入HBASE_CLASS path環(huán)境變量:

export HADOOP_HOME=/opt/modules/hadoop-2.5.0-cdh5.3.6
export HBASE_HOME=/opt/modules/hbase-0.98.6-cdh5.3.6
export HADOOP_CLASSPATH=`$HBASE_HOME/bin/hbase mapredcp`

上邊步驟設(shè)置HBase的CLASSPATH。變量引入,一般寫(xiě)進(jìn)shell腳本,跟隨job任務(wù)執(zhí)行的命令一起。如果要寫(xiě)入/etc/profile 會(huì)永久生效,并且需要加export。

(2)通過(guò)yarn執(zhí)行mapreduce的jar包:
查看整個(gè)jar包所提供的所有功能:

$ /opt/modules/hadoop-2.5.0-cdh5.3.6/bin/yarn jar /opt/modules/hbase-0.98.6-cdh5.3.6/lib/hbase-server-0.98.6-cdh5.3.6.jar 
Paste_Image.png

(3)通過(guò)mapreduce查看某個(gè)表的行數(shù)(rowkey的個(gè)數(shù)):
$ /opt/modules/hadoop-2.5.0-cdh5.3.6/bin/yarn jar /opt/modules/hbase-0.98.6-cdh5.3.6/lib/hbase-server-0.98.6-cdh5.3.6.jar rowcounter 'user'

4.自定義HBase的MapReduce程序:

5.HBase數(shù)據(jù)遷移工具importTsv:

HBase存在較多數(shù)據(jù)遷移的場(chǎng)景:例如,需要將一個(gè)數(shù)據(jù)文件直接導(dǎo)入到HBase表中,還有將生產(chǎn)集群的數(shù)據(jù)遷移到測(cè)試集群等等。
ImportTsv是HBase官方提供的基于MapReduce的批量數(shù)據(jù)導(dǎo)入工具。ImportTsv是一個(gè)命令行工具,可以將存儲(chǔ)在HDFS上的自定義分隔符(默認(rèn)\t)的數(shù)據(jù)文件,通過(guò)一條命令導(dǎo)入到HBase表中,非常適合大數(shù)據(jù)量導(dǎo)入。
下面運(yùn)行一個(gè)實(shí)例來(lái)演示導(dǎo)入過(guò)程:
(1)創(chuàng)建一個(gè)將要導(dǎo)入的測(cè)試文件:
(2)上傳該文件到HDFS上的指定目錄:
(3)HBase建表:
(4)開(kāi)始運(yùn)行MapReduce執(zhí)行導(dǎo)入。
(5)驗(yàn)證結(jié)果。

6. 使用BulkLoad加載數(shù)據(jù):

6.創(chuàng)建HBase表

創(chuàng)建HBase有常見(jiàn)的三種方式:
1.創(chuàng)建表時(shí),指定region劃分方式(根據(jù)rowkey)

create 'tb1','fa1',SPLITS => ['10','20','30','40']

tb1表有五個(gè)Region。SPLITS根據(jù)rowkey來(lái)將記錄分配到各自的region中:


Region劃分.png

2.創(chuàng)建表時(shí),通過(guò)文件來(lái)將表劃分為多分區(qū)(最常用方式):
將分區(qū)范圍放在一個(gè)物理文件中,然后在創(chuàng)建表時(shí)指定這個(gè)文件。例如定義下面一個(gè)regions.txt文件:

20170605
20170606
20170607
20170608
20170609
20170610

下面創(chuàng)建表,根據(jù)這個(gè)文件指定劃分region。

create table 'tb2','fa2',SPLITS_FILE => '/home/natty/hbase/regions.txt',OWNER => 'natty'

需要注意,這里建議使用絕對(duì)路徑來(lái)指定文件。
3.指定分區(qū)的數(shù)量,創(chuàng)建表:

create table 'tb3','fa3',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

如果指定region的起止范圍,系統(tǒng)可以自動(dòng)定義。

7. HBase的RowKey設(shè)計(jì)

1.表結(jié)構(gòu)設(shè)計(jì):

最核心的內(nèi)容是設(shè)計(jì)rowkey。設(shè)計(jì)rowkey的要點(diǎn):
1.根據(jù)需求設(shè)計(jì),查詢速度快。
2.盡量覆蓋更多業(yè)務(wù)場(chǎng)景,增加復(fù)用的可能性。
3.離線設(shè)計(jì),避免熱點(diǎn)

2.案例設(shè)計(jì):

下面介紹一個(gè)實(shí)例,訂單歷史表。這個(gè)表有以下的查詢場(chǎng)景。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 上一篇:101-BigData-29Azkaban 一、HBaes介紹 1.1、HBase簡(jiǎn)介HBase是一個(gè)分布...
    AncientMing閱讀 744評(píng)論 0 1
  • 一、HBase簡(jiǎn)介 1.1 HBase是什么 HBase是一個(gè)分布式的、面向列的開(kāi)源數(shù)據(jù)庫(kù),Hadoop 數(shù)據(jù)庫(kù)。...
    這一刻_776b閱讀 1,027評(píng)論 0 0
  • 簡(jiǎn)介 HBase是高可靠性,高性能,面向列,可伸縮的分布式存儲(chǔ)系統(tǒng),利用HBase技術(shù)可在廉價(jià)PC Serve...
    九世的貓閱讀 2,388評(píng)論 1 6
  • 1. hbase 的特點(diǎn)是什么? (1) Hbase一個(gè)分布式的基于列式存儲(chǔ)的數(shù)據(jù)庫(kù),基于Hadoop的hdfs存...
    Tim在路上閱讀 773評(píng)論 0 9
  • 01-Hbase的特點(diǎn) 以下五點(diǎn)需要準(zhǔn)確說(shuō)出的,如果可以還可以將一下Hbase的寫(xiě)入比讀取快的原因(1) Hbas...
    李小李的路閱讀 880評(píng)論 0 1

友情鏈接更多精彩內(nèi)容