天天看點

#CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化

CSDN軟體工程師能力認證是由CSDN制定并推出的一個能力認證标準,宗旨是讓一流的技術人才憑真才實學進大廠拿高薪,同時為企業節約大量招聘與培養成本,使命是提升高校大學生的技術能力,為行業提供人才儲備,為國家數字化戰略貢獻力量。我們每天将都會精選CSDN站内技術文章供大家學習,幫助大家系統化學習IT技術。

一 什麼是HBASE

HBASE是一個高可靠性、高性能、面向列、可伸縮的分布式存儲系統,利用HBASE技術可在廉價PC Server上搭建起大規模結構化存儲叢集。

HBASE的目标是存儲并處理大型的資料,更具體來說是僅需使用普通的硬體配置,就能夠處理由成千上萬的行和列所組成的大型資料。

HBASE是Google Bigtable的開源實作,但是也有很多不同之處。比如:Google Bigtable利用GFS作為其檔案存儲系統,HBASE利用Hadoop HDFS作為其檔案存儲系統;Google運作MAPREDUCE來處理Bigtable中的海量資料,HBASE同樣利用Hadoop MapReduce來處理HBASE中的海量資料;Google Bigtable利用Chubby作為協同服務,HBASE利用Zookeeper作為對應。

HBASE與mysql、oralce、db2、sqlserver等關系型資料庫不同,它是一個NoSQL資料庫(非關系型資料庫)

  1. Hbase的表模型與關系型資料庫的表模型不同:
  2. Hbase的表沒有固定的字段定義;
  3. Hbase的表中每行存儲的都是一些key-value對
  4. Hbase的表中有列族的劃分,使用者可以指定将哪些kv插入哪個列族
  5. Hbase的表在實體存儲上,是按照列族來分割的,不同列族的資料一定存儲在不同的檔案中
  6. Hbase的表中的每一行都固定有一個行鍵,而且每一行的行鍵在表中不能重複
  7. Hbase中的資料,包含行鍵,包含key,包含value,都是byte[ ]類型,hbase不負責為使用者維護資料類型
  8. HBASE對事務的支援很差

HBASE相比于其他nosql資料庫(mongodb、redis、cassendra、hazelcast)的特點:

Hbase的表資料存儲在HDFS檔案系統中

進而,hbase具備如下特性:存儲容量可以線性擴充; 資料存儲的安全性可靠性極高!

二 安裝HBASE

HBASE是一個分布式系統

其中有一個管理角色:  HMaster(一般2台,一台active,一台backup)

其他的資料節點角色:  HRegionServer(很多台,看資料容量)

2.1 安裝準備

需要先有一個java環境

首先,要有一個HDFS叢集,并正常運作; regionserver應該跟hdfs中的datanode在一起

其次,還需要一個zookeeper叢集,并正常運作

然後,安裝HBASE

角色配置設定如下:

Hdp01:  namenode  datanode  regionserver  hmaster  zookeeper

Hdp02:  datanode   regionserver  zookeeper

Hdp03:  datanode   regionserver  zookeeper

2.2 安裝步驟

解壓hbase安裝包

修改hbase-env.sh

export JAVA_HOME=/root/apps/jdk1.7.0_67

export HBASE_MANAGES_ZK=false

修改hbase-site.xml

<configuration>

<!-- 指定hbase在HDFS上存儲的路徑 -->

        <property>

                <name>hbase.rootdir</name>

                <value>hdfs://hdp01:9000/hbase</value>

        </property>

<!-- 指定hbase是分布式的 -->

        <property>

                <name>hbase.cluster.distributed</name>

                <value>true</value>

        </property>

<!-- 指定zk的位址,多個用“,”分割 -->

        <property>

                <name>hbase.zookeeper.quorum</name>

                <value>hdp01:2181,hdp02:2181,hdp03:2181</value>

        </property>

</configuration>

修改 regionservers

hdp01

hdp02

hdp03

2.3 啟動hbase叢集

bin/start-hbase.sh

啟動完後,還可以在叢集中找任意一台機器啟動一個備用的master

bin/hbase-daemon.sh start master

新啟的這個master會處于backup狀态

三 hbase初體驗

3.1 啟動hbase指令行用戶端

bin/hbase shell

Hbase> list     // 檢視表

Hbase> status   // 檢視叢集狀态

Hbase> version  // 檢視叢集版本

3.2 hbase表模型的特點

#CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化
  1. 一個表,有表名
  2. 一個表可以分為多個列族(不同列族的資料會存儲在不同檔案中)
  3. 表中的每一行有一個“行鍵rowkey”,而且行鍵在表中不能重複
  4. 表中的每一對kv資料稱作一個cell
  5. hbase可以對資料存儲多個曆史版本(曆史版本數量可配置)
  6. 整張表由于資料量過大,會被橫向切分成若幹個region(用rowkey範圍辨別),不同region的資料也存儲在不同檔案中
    #CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化
  7. hbase會對插入的資料按順序存儲:

     要點一:首先會按行鍵排序

     要點二:同一行裡面的kv會按列族排序,再按k排序

3.3 hbase的表中能存儲什麼資料類型

hbase中隻支援byte[]

此處的byte[] 包括了: rowkey,key,value,列族名,表名

3.4 hbase指令行用戶端操作

名稱 指令表達式
建立表 create '表名', '列族名1','列族名2','列族名N'
檢視所有表 list
描述表 describe  ‘表名’
判斷表存在 exists  '表名'
判斷是否禁用啟用表

is_enabled '表名'

is_disabled ‘表名’

添加記錄       put  ‘表名’, ‘rowKey’, ‘列族 : 列‘  ,  '值'
檢視記錄rowkey下的所有資料 get  '表名' , 'rowKey'
檢視表中的記錄總數 count  '表名'
擷取某個列族 get '表名','rowkey','列族'
擷取某個列族的某個列 get '表名','rowkey','列族:列’
删除記錄 delete  ‘表名’ ,‘行名’ , ‘列族:列'
删除整行 deleteall '表名','rowkey'
删除一張表

先要屏蔽該表,才能對該表進行删除

第一步 disable ‘表名’ ,第二步  drop '表名'

清空表 truncate '表名'
檢視所有記錄 scan "表名"  
檢視某個表某個列中所有資料 scan "表名" , {COLUMNS=>'列族名:列名'}
更新記錄 就是重寫一遍,進行覆寫,hbase沒有修改,都是追加

3.4.1 建表

create 't_user_info','base_info','extra_info'

                      表名      列族名   列族名

3.4.2 插入資料

hbase(main):011:0> put 't_user_info','001','base_info:username','zhangsan'

0 row(s) in 0.2420 seconds

hbase(main):012:0> put 't_user_info','001','base_info:age','18'

0 row(s) in 0.0140 seconds

hbase(main):013:0> put 't_user_info','001','base_info:sex','female'

0 row(s) in 0.0070 seconds

hbase(main):014:0> put 't_user_info','001','extra_info:career','it'

0 row(s) in 0.0090 seconds

hbase(main):015:0> put 't_user_info','002','extra_info:career','actoress'

0 row(s) in 0.0090 seconds

hbase(main):016:0> put 't_user_info','002','base_info:username','liuyifei'

0 row(s) in 0.0060 seconds

3.4.3 查詢方式一 scan掃描

hbase(main):017:0> scan 't_user_info'

ROW                               COLUMN+CELL                                                                                     

 001                              column=base_info:age, timestamp=1496567924507, value=18                                         

 001                              column=base_info:sex, timestamp=1496567934669, value=female                                     

 001                              column=base_info:username, timestamp=1496567889554, value=zhangsan                              

 001                              column=extra_info:career, timestamp=1496567963992, value=it                                     

 002                              column=base_info:username, timestamp=1496568034187, value=liuyifei                              

 002                              column=extra_info:career, timestamp=1496568008631, value=actoress    

3.4.4 查詢方式二 get單行資料

hbase(main):020:0> get 't_user_info','001'

COLUMN                            CELL                                                                                            

 base_info:age                    timestamp=1496568160192, value=19                                                               

 base_info:sex                    timestamp=1496567934669, value=female                                                           

 base_info:username               timestamp=1496567889554, value=zhangsan                                                         

 extra_info:career                timestamp=1496567963992, value=it                                                               

4 row(s) in 0.0770 seconds

3.4.5 删除一個kv資料

hbase(main):021:0> delete 't_user_info','001','base_info:sex'

0 row(s) in 0.0390 seconds

删除整行資料

hbase(main):024:0> deleteall 't_user_info','001'

0 row(s) in 0.0090 seconds

hbase(main):025:0> get 't_user_info','001'

COLUMN                            CELL                                                                                            

0 row(s) in 0.0110 seconds

3.4.6 删除整個表

hbase(main):028:0> disable 't_user_info'

0 row(s) in 2.3640 seconds

hbase(main):029:0> drop 't_user_info'

0 row(s) in 1.2950 seconds

hbase(main):030:0> list

TABLE                                                                                                                             

0 row(s) in 0.0130 seconds

=> []

3.5 Hbase重要特性-排序特性(行鍵)

與nosql資料庫們一樣,row key是用來檢索記錄的主鍵。通路HBASE table中的行,隻有三種方式:

1.通過單個row key通路

2.通過row key的range(正則)

3.全表掃描

Row key行鍵 (Row key)可以是任意字元串(最大長度 是 64KB,實際應用中長度一般為 10-100bytes),在HBASE内部,row key儲存為位元組數組。存儲時,資料按照Row key的字典序(byte order)排序存儲。設計key時,要充分排序存儲這個特性,将經常一起讀取的行存儲放到一起。(位置相關性)

插入到hbase中去的資料,hbase會自動排序存儲:

排序規則:  首先看行鍵,然後看列族名,然後看列(key)名; 按字典順序

Hbase的這個特性跟查詢效率有極大的關系

比如:一張用來存儲使用者資訊的表,有名字,戶籍,年齡,職業....等資訊

然後,在業務系統中經常需要:

查詢某個省的所有使用者

經常需要查詢某個省的指定姓的所有使用者

思路:如果能将相同省的使用者在hbase的存儲檔案中連續存儲,并且能将相同省中相同姓的使用者連續存儲,那麼,上述兩個查詢需求的效率就會提高!!!

做法:将查詢條件拼到rowkey内

四 HBASE用戶端API操作

4.1 簡潔版

HbaseClientDDL 

  1. package cn.hbase.demo;

  2. import org.apache.hadoop.conf.Configuration;

  3. import org.apache.hadoop.hbase.HBaseConfiguration;

  4. import org.apache.hadoop.hbase.HColumnDescriptor;

  5. import org.apache.hadoop.hbase.HTableDescriptor;

  6. import org.apache.hadoop.hbase.TableName;

  7. import org.apache.hadoop.hbase.client.Admin;

  8. import org.apache.hadoop.hbase.client.Connection;

  9. import org.apache.hadoop.hbase.client.ConnectionFactory;

  10. import org.apache.hadoop.hbase.regionserver.BloomType;

  11. import org.junit.Before;

  12. import org.junit.Test;

  13. public class HbaseClientDDL {

  14. Connection conn = null;

  15. @Before

  16. public void getConn() throws Exception{

  17. // 建構一個連接配接對象

  18. Configuration conf = HBaseConfiguration.create(); // 會自動加載hbase-site.xml

  19. conf.set("hbase.zookeeper.quorum", "hdp-01:2181,hdp-02:2181,hdp-03:2181");

  20. conn = ConnectionFactory.createConnection(conf);

  21. }

  22. @Test

  23. public void testCreateTable() throws Exception{

  24. // 從連接配接中構造一個DDL操作器

  25. Admin admin = conn.getAdmin();

  26. // 建立一個表定義描述對象

  27. HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("user_info"));

  28. // 建立列族定義描述對象

  29. HColumnDescriptor hColumnDescriptor_1 = new HColumnDescriptor("base_info");

  30. hColumnDescriptor_1.setMaxVersions(3); // 設定該列族中存儲資料的最大版本數,預設是1

  31. HColumnDescriptor hColumnDescriptor_2 = new HColumnDescriptor("extra_info");

  32. // 将列族定義資訊對象放入表定義對象中

  33. hTableDescriptor.addFamily(hColumnDescriptor_1);

  34. hTableDescriptor.addFamily(hColumnDescriptor_2);

  35. // 用ddl操作器對象:admin 來建表

  36. admin.createTable(hTableDescriptor);

  37. // 關閉連接配接

  38. admin.close();

  39. conn.close();

  40. }

  41. @Test

  42. public void testDropTable() throws Exception{

  43. Admin admin = conn.getAdmin();

  44. // 停用表

  45. admin.disableTable(TableName.valueOf("user_info"));

  46. // 删除表

  47. admin.deleteTable(TableName.valueOf("user_info"));

  48. admin.close();

  49. conn.close();

  50. }

  51. // 修改表定義--添加一個列族

  52. @Test

  53. public void testAlterTable() throws Exception{

  54. Admin admin = conn.getAdmin();

  55. // 取出舊的表定義資訊

  56. HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf("user_info"));

  57. // 新構造一個列族定義

  58. HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("other_info");

  59. hColumnDescriptor.setBloomFilterType(BloomType.ROWCOL); // 設定該列族的布隆過濾器類型

  60. // 将列族定義添加到表定義對象中

  61. tableDescriptor.addFamily(hColumnDescriptor);

  62. // 将修改過的表定義交給admin去送出

  63. admin.modifyTable(TableName.valueOf("user_info"), tableDescriptor);

  64. admin.close();

  65. conn.close();

  66. }

  67. }

HbaseClientDML

  1. package cn.hbase.demo;

  2. import java.util.ArrayList;

  3. import java.util.Iterator;

  4. import org.apache.hadoop.conf.Configuration;

  5. import org.apache.hadoop.hbase.Cell;

  6. import org.apache.hadoop.hbase.CellScanner;

  7. import org.apache.hadoop.hbase.HBaseConfiguration;

  8. import org.apache.hadoop.hbase.TableName;

  9. import org.apache.hadoop.hbase.client.Connection;

  10. import org.apache.hadoop.hbase.client.ConnectionFactory;

  11. import org.apache.hadoop.hbase.client.Delete;

  12. import org.apache.hadoop.hbase.client.Get;

  13. import org.apache.hadoop.hbase.client.Put;

  14. import org.apache.hadoop.hbase.client.Result;

  15. import org.apache.hadoop.hbase.client.ResultScanner;

  16. import org.apache.hadoop.hbase.client.Scan;

  17. import org.apache.hadoop.hbase.client.Table;

  18. import org.apache.hadoop.hbase.util.Bytes;

  19. import org.junit.Before;

  20. import org.junit.Test;

  21. public class HbaseClientDML {

  22. Connection conn = null;

  23. @Before

  24. public void getConn() throws Exception{

  25. // 建構一個連接配接對象

  26. Configuration conf = HBaseConfiguration.create(); // 會自動加載hbase-site.xml

  27. conf.set("hbase.zookeeper.quorum", "hdp-01:2181,hdp-02:2181,hdp-03:2181");

  28. conn = ConnectionFactory.createConnection(conf);

  29. }

  30. @Test

  31. public void testPut() throws Exception{

  32. // 擷取一個操作指定表的table對象,進行DML操作

  33. Table table = conn.getTable(TableName.valueOf("user_info"));

  34. // 構造要插入的資料為一個Put類型(一個put對象隻能對應一個rowkey)的對象

  35. Put put = new Put(Bytes.toBytes("001"));

  36. put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("張三"));

  37. put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("18"));

  38. put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));

  39. Put put2 = new Put(Bytes.toBytes("002"));

  40. put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("李四"));

  41. put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("28"));

  42. put2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("上海"));

  43. ArrayList<Put> puts = new ArrayList<>();

  44. puts.add(put);

  45. puts.add(put2);

  46. // 插進去

  47. table.put(puts);

  48. table.close();

  49. conn.close();

  50. }

  51. @Test

  52. public void testManyPuts() throws Exception{

  53. Table table = conn.getTable(TableName.valueOf("user_info"));

  54. ArrayList<Put> puts = new ArrayList<>();

  55. for(int i=0;i<100000;i++){

  56. Put put = new Put(Bytes.toBytes(""+i));

  57. put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("張三"+i));

  58. put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes((18+i)+""));

  59. put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));

  60. puts.add(put);

  61. }

  62. table.put(puts);

  63. }

  64. @Test

  65. public void testDelete() throws Exception{

  66. Table table = conn.getTable(TableName.valueOf("user_info"));

  67. // 構造一個對象封裝要删除的資料資訊

  68. Delete delete1 = new Delete(Bytes.toBytes("001"));

  69. Delete delete2 = new Delete(Bytes.toBytes("002"));

  70. delete2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"));

  71. ArrayList<Delete> dels = new ArrayList<>();

  72. dels.add(delete1);

  73. dels.add(delete2);

  74. table.delete(dels);

  75. table.close();

  76. conn.close();

  77. }

  78. @Test

  79. public void testGet() throws Exception{

  80. Table table = conn.getTable(TableName.valueOf("user_info"));

  81. Get get = new Get("002".getBytes());

  82. Result result = table.get(get);

  83. // 從結果中取使用者指定的某個key的value

  84. byte[] value = result.getValue("base_info".getBytes(), "age".getBytes());

  85. System.out.println(new String(value));

  86. System.out.println("-------------------------");

  87. // 周遊整行結果中的所有kv單元格

  88. CellScanner cellScanner = result.cellScanner();

  89. while(cellScanner.advance()){

  90. Cell cell = cellScanner.current();

  91. byte[] rowArray = cell.getRowArray(); //本kv所屬的行鍵的位元組數組

  92. byte[] familyArray = cell.getFamilyArray(); //列族名的位元組數組

  93. byte[] qualifierArray = cell.getQualifierArray(); //列名的位元組資料

  94. byte[] valueArray = cell.getValueArray(); // value的位元組數組

  95. System.out.println("行鍵: "+new String(rowArray,cell.getRowOffset(),cell.getRowLength()));

  96. System.out.println("列族名: "+new String(familyArray,cell.getFamilyOffset(),cell.getFamilyLength()));

  97. System.out.println("列名: "+new String(qualifierArray,cell.getQualifierOffset(),cell.getQualifierLength()));

  98. System.out.println("value: "+new String(valueArray,cell.getValueOffset(),cell.getValueLength()));

  99. }

  100. table.close();

  101. conn.close();

  102. }

  103. @Test

  104. public void testScan() throws Exception{

  105. Table table = conn.getTable(TableName.valueOf("user_info"));

  106. // 包含起始行鍵,不包含結束行鍵,但是如果真的想查詢出末尾的那個行鍵,那麼,可以在末尾行鍵上拼接一個不可見的位元組(\000)

  107. Scan scan = new Scan("10".getBytes(), "10000\001".getBytes());

  108. ResultScanner scanner = table.getScanner(scan);

  109. Iterator<Result> iterator = scanner.iterator();

  110. while(iterator.hasNext()){

  111. Result result = iterator.next();

  112. // 周遊整行結果中的所有kv單元格

  113. CellScanner cellScanner = result.cellScanner();

  114. while(cellScanner.advance()){

  115. Cell cell = cellScanner.current();

  116. byte[] rowArray = cell.getRowArray(); //本kv所屬的行鍵的位元組數組

  117. byte[] familyArray = cell.getFamilyArray(); //列族名的位元組數組

  118. byte[] qualifierArray = cell.getQualifierArray(); //列名的位元組資料

  119. byte[] valueArray = cell.getValueArray(); // value的位元組數組

  120. System.out.println("行鍵: "+new String(rowArray,cell.getRowOffset(),cell.getRowLength()));

  121. System.out.println("列族名: "+new String(familyArray,cell.getFamilyOffset(),cell.getFamilyLength()));

  122. System.out.println("列名: "+new String(qualifierArray,cell.getQualifierOffset(),cell.getQualifierLength()));

  123. System.out.println("value: "+new String(valueArray,cell.getValueOffset(),cell.getValueLength()));

  124. }

  125. System.out.println("----------------------");

  126. }

  127. }

  128. @Test

  129. public void test(){

  130. String a = "000";

  131. String b = "000\0";

  132. System.out.println(a);

  133. System.out.println(b);

  134. byte[] bytes = a.getBytes();

  135. byte[] bytes2 = b.getBytes();

  136. System.out.println("");

  137. }

  138. }

4.2 完整版

  1. package com.zgcbank.hbase;

  2. import java.util.ArrayList;

  3. import org.apache.hadoop.conf.Configuration;

  4. import org.apache.hadoop.hbase.Cell;

  5. import org.apache.hadoop.hbase.CellUtil;

  6. import org.apache.hadoop.hbase.HBaseConfiguration;

  7. import org.apache.hadoop.hbase.HColumnDescriptor;

  8. import org.apache.hadoop.hbase.HTableDescriptor;

  9. import org.apache.hadoop.hbase.MasterNotRunningException;

  10. import org.apache.hadoop.hbase.TableName;

  11. import org.apache.hadoop.hbase.ZooKeeperConnectionException;

  12. import org.apache.hadoop.hbase.client.Connection;

  13. import org.apache.hadoop.hbase.client.ConnectionFactory;

  14. import org.apache.hadoop.hbase.client.Delete;

  15. import org.apache.hadoop.hbase.client.Get;

  16. import org.apache.hadoop.hbase.client.HBaseAdmin;

  17. import org.apache.hadoop.hbase.client.HConnection;

  18. import org.apache.hadoop.hbase.client.HConnectionManager;

  19. import org.apache.hadoop.hbase.client.Put;

  20. import org.apache.hadoop.hbase.client.Result;

  21. import org.apache.hadoop.hbase.client.ResultScanner;

  22. import org.apache.hadoop.hbase.client.Scan;

  23. import org.apache.hadoop.hbase.client.Table;

  24. import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;

  25. import org.apache.hadoop.hbase.filter.CompareFilter;

  26. import org.apache.hadoop.hbase.filter.FilterList;

  27. import org.apache.hadoop.hbase.filter.FilterList.Operator;

  28. import org.apache.hadoop.hbase.filter.RegexStringComparator;

  29. import org.apache.hadoop.hbase.filter.RowFilter;

  30. import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;

  31. import org.apache.hadoop.hbase.util.Bytes;

  32. import org.junit.After;

  33. import org.junit.Before;

  34. import org.junit.Test;

  35. public class HbaseTest {

  36. static Configuration config = null;

  37. private Connection connection = null;

  38. private Table table = null;

  39. @Before

  40. public void init() throws Exception {

  41. config = HBaseConfiguration.create();// 配置

  42. config.set("hbase.zookeeper.quorum", "master,work1,work2");// zookeeper位址

  43. config.set("hbase.zookeeper.property.clientPort", "2181");// zookeeper端口

  44. connection = ConnectionFactory.createConnection(config);

  45. table = connection.getTable(TableName.valueOf("user"));

  46. }

  47. @Test

  48. public void createTable() throws Exception {

  49. // 建立表管理類

  50. HBaseAdmin admin = new HBaseAdmin(config); // hbase表管理

  51. // 建立表描述類

  52. TableName tableName = TableName.valueOf("test3"); // 表名稱

  53. HTableDescriptor desc = new HTableDescriptor(tableName);

  54. // 建立列族的描述類

  55. HColumnDescriptor family = new HColumnDescriptor("info"); // 列族

  56. // 将列族添加到表中

  57. desc.addFamily(family);

  58. HColumnDescriptor family2 = new HColumnDescriptor("info2"); // 列族

  59. // 将列族添加到表中

  60. desc.addFamily(family2);

  61. // 建立表

  62. admin.createTable(desc); // 建立表

  63. }

  64. @Test

  65. @SuppressWarnings("deprecation")

  66. public void deleteTable() throws MasterNotRunningException,

  67. ZooKeeperConnectionException, Exception {

  68. HBaseAdmin admin = new HBaseAdmin(config);

  69. admin.disableTable("test3");

  70. admin.deleteTable("test3");

  71. admin.close();

  72. }

  73. @SuppressWarnings({ "deprecation", "resource" })

  74. @Test

  75. public void insertData() throws Exception {

  76. table.setAutoFlushTo(false);

  77. table.setWriteBufferSize(534534534);

  78. ArrayList<Put> arrayList = new ArrayList<Put>();

  79. for (int i = 21; i < 50; i++) {

  80. Put put = new Put(Bytes.toBytes("1234"+i));

  81. put.add(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("wangwu"+i));

  82. put.add(Bytes.toBytes("info"), Bytes.toBytes("password"), Bytes.toBytes(1234+i));

  83. arrayList.add(put);

  84. }

  85. //插入資料

  86. table.put(arrayList);

  87. //送出

  88. table.flushCommits();

  89. }

  90. @Test

  91. public void uodateData() throws Exception {

  92. Put put = new Put(Bytes.toBytes("1234"));

  93. put.add(Bytes.toBytes("info"), Bytes.toBytes("namessss"), Bytes.toBytes("lisi1234"));

  94. put.add(Bytes.toBytes("info"), Bytes.toBytes("password"), Bytes.toBytes(1234));

  95. //插入資料

  96. table.put(put);

  97. //送出

  98. table.flushCommits();

  99. }

  100. @Test

  101. public void deleteDate() throws Exception {

  102. Delete delete = new Delete(Bytes.toBytes("1234"));

  103. table.delete(delete);

  104. table.flushCommits();

  105. }

  106. @Test

  107. public void queryData() throws Exception {

  108. Get get = new Get(Bytes.toBytes("1234"));

  109. Result result = table.get(get);

  110. System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));

  111. System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("namessss"))));

  112. System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("sex"))));

  113. }

  114. @Test

  115. public void scanData() throws Exception {

  116. Scan scan = new Scan();

  117. //scan.addFamily(Bytes.toBytes("info"));

  118. //scan.addColumn(Bytes.toBytes("info"), Bytes.toBytes("password"));

  119. scan.setStartRow(Bytes.toBytes("wangsf_0"));

  120. scan.setStopRow(Bytes.toBytes("wangwu"));

  121. ResultScanner scanner = table.getScanner(scan);

  122. for (Result result : scanner) {

  123. System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));

  124. System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))));

  125. //System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("password"))));

  126. //System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"))));

  127. }

  128. }

  129. @Test

  130. public void scanDataByFilter1() throws Exception {

  131. // 建立全表掃描的scan

  132. Scan scan = new Scan();

  133. //過濾器:列值過濾器

  134. SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("info"),

  135. Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL,

  136. Bytes.toBytes("zhangsan2"));

  137. // 設定過濾器

  138. scan.setFilter(filter);

  139. // 列印結果集

  140. ResultScanner scanner = table.getScanner(scan);

  141. for (Result result : scanner) {

  142. System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));

  143. System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))));

  144. //System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("password"))));

  145. //System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"))));

  146. }

  147. }

  148. @Test

  149. public void scanDataByFilter2() throws Exception {

  150. // 建立全表掃描的scan

  151. Scan scan = new Scan();

  152. //比對rowkey以wangsenfeng開頭的

  153. RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^12341"));

  154. // 設定過濾器

  155. scan.setFilter(filter);

  156. // 列印結果集

  157. ResultScanner scanner = table.getScanner(scan);

  158. for (Result result : scanner) {

  159. System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));

  160. System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))));

  161. //System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("password"))));

  162. //System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"))));

  163. }

  164. }

  165. @Test

  166. public void scanDataByFilter3() throws Exception {

  167. // 建立全表掃描的scan

  168. Scan scan = new Scan();

  169. //比對rowkey以wangsenfeng開頭的

  170. ColumnPrefixFilter filter = new ColumnPrefixFilter(Bytes.toBytes("na"));

  171. // 設定過濾器

  172. scan.setFilter(filter);

  173. // 列印結果集

  174. ResultScanner scanner = table.getScanner(scan);

  175. for (Result result : scanner) {

  176. System.out.println("rowkey:" + Bytes.toString(result.getRow()));

  177. System.out.println("info:name:"

  178. + Bytes.toString(result.getValue(Bytes.toBytes("info"),

  179. Bytes.toBytes("name"))));

  180. // 判斷取出來的值是否為空

  181. if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")) != null) {

  182. System.out.println("info:age:"

  183. + Bytes.toInt(result.getValue(Bytes.toBytes("info"),

  184. Bytes.toBytes("age"))));

  185. }

  186. // 判斷取出來的值是否為空

  187. if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("sex")) != null) {

  188. System.out.println("infi:sex:"

  189. + Bytes.toInt(result.getValue(Bytes.toBytes("info"),

  190. Bytes.toBytes("sex"))));

  191. }

  192. // 判斷取出來的值是否為空

  193. if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name")) != null) {

  194. System.out

  195. .println("info2:name:"

  196. + Bytes.toString(result.getValue(

  197. Bytes.toBytes("info2"),

  198. Bytes.toBytes("name"))));

  199. }

  200. // 判斷取出來的值是否為空

  201. if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("age")) != null) {

  202. System.out.println("info2:age:"

  203. + Bytes.toInt(result.getValue(Bytes.toBytes("info2"),

  204. Bytes.toBytes("age"))));

  205. }

  206. // 判斷取出來的值是否為空

  207. if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("sex")) != null) {

  208. System.out.println("info2:sex:"

  209. + Bytes.toInt(result.getValue(Bytes.toBytes("info2"),

  210. Bytes.toBytes("sex"))));

  211. }

  212. }

  213. }

  214. @Test

  215. public void scanDataByFilter4() throws Exception {

  216. // 建立全表掃描的scan

  217. Scan scan = new Scan();

  218. //過濾器集合:MUST_PASS_ALL(and),MUST_PASS_ONE(or)

  219. FilterList filterList = new FilterList(Operator.MUST_PASS_ONE);

  220. //比對rowkey以wangsenfeng開頭的

  221. RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^wangsenfeng"));

  222. //比對name的值等于wangsenfeng

  223. SingleColumnValueFilter filter2 = new SingleColumnValueFilter(Bytes.toBytes("info"),

  224. Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL,

  225. Bytes.toBytes("zhangsan"));

  226. filterList.addFilter(filter);

  227. filterList.addFilter(filter2);

  228. // 設定過濾器

  229. scan.setFilter(filterList);

  230. // 列印結果集

  231. ResultScanner scanner = table.getScanner(scan);

  232. for (Result result : scanner) {

  233. System.out.println("rowkey:" + Bytes.toString(result.getRow()));

  234. System.out.println("info:name:"

  235. + Bytes.toString(result.getValue(Bytes.toBytes("info"),

  236. Bytes.toBytes("name"))));

  237. // 判斷取出來的值是否為空

  238. if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")) != null) {

  239. System.out.println("info:age:"

  240. + Bytes.toInt(result.getValue(Bytes.toBytes("info"),

  241. Bytes.toBytes("age"))));

  242. }

  243. // 判斷取出來的值是否為空

  244. if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("sex")) != null) {

  245. System.out.println("infi:sex:"

  246. + Bytes.toInt(result.getValue(Bytes.toBytes("info"),

  247. Bytes.toBytes("sex"))));

  248. }

  249. // 判斷取出來的值是否為空

  250. if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name")) != null) {

  251. System.out

  252. .println("info2:name:"

  253. + Bytes.toString(result.getValue(

  254. Bytes.toBytes("info2"),

  255. Bytes.toBytes("name"))));

  256. }

  257. // 判斷取出來的值是否為空

  258. if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("age")) != null) {

  259. System.out.println("info2:age:"

  260. + Bytes.toInt(result.getValue(Bytes.toBytes("info2"),

  261. Bytes.toBytes("age"))));

  262. }

  263. // 判斷取出來的值是否為空

  264. if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("sex")) != null) {

  265. System.out.println("info2:sex:"

  266. + Bytes.toInt(result.getValue(Bytes.toBytes("info2"),

  267. Bytes.toBytes("sex"))));

  268. }

  269. }

  270. }

  271. @After

  272. public void close() throws Exception {

  273. table.close();

  274. connection.close();

  275. }

  276. }

4.3 MapReduce操作Hbase

4.3.1 實作方法

Hbase對MapReduce提供支援,它實作了TableMapper類和TableReducer類,我們隻需要繼承這兩個類即可。

1、寫個mapper繼承TableMapper<Text, IntWritable>

參數:Text:mapper的輸出key類型; IntWritable:mapper的輸出value類型。

      其中的map方法如下:

map(ImmutableBytesWritable key, Result value,Context context)

 參數:key:rowKey;value: Result ,一行資料; context上下文

2、寫個reduce繼承TableReducer<Text, IntWritable, ImmutableBytesWritable>

參數:Text:reducer的輸入key; IntWritable:reduce的輸入value;

 ImmutableBytesWritable:reduce輸出到hbase中的rowKey類型。

      其中的reduce方法如下:

reduce(Text key, Iterable<IntWritable> values,Context context)

參數: key:reduce的輸入key;values:reduce的輸入value;

4.3.2 準備表

1、建立資料來源表‘word’,包含一個列族‘content’

向表中添加資料,在列族中放入列‘info’,并将短文資料放入該列中,如此插入多行,行鍵為不同的資料即可

2、建立輸出表‘stat’,包含一個列族‘content’

3、通過Mr操作Hbase的‘word’表,對‘content:info’中的短文做詞頻統計,并将統計結果寫入‘stat’表的‘content:info中’,行鍵為單詞

4.3.3 實作

  1. package com.zgcbank.hbase;

  2. import java.io.IOException;

  3. import java.util.ArrayList;

  4. import java.util.List;

  5. import org.apache.hadoop.conf.Configuration;

  6. import org.apache.hadoop.hbase.HBaseConfiguration;

  7. import org.apache.hadoop.hbase.HColumnDescriptor;

  8. import org.apache.hadoop.hbase.HTableDescriptor;

  9. import org.apache.hadoop.hbase.client.HBaseAdmin;

  10. import org.apache.hadoop.hbase.client.HTable;

  11. import org.apache.hadoop.hbase.client.Put;

  12. import org.apache.hadoop.hbase.client.Result;

  13. import org.apache.hadoop.hbase.client.Scan;

  14. import org.apache.hadoop.hbase.io.ImmutableBytesWritable;

  15. import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;

  16. import org.apache.hadoop.hbase.mapreduce.TableMapper;

  17. import org.apache.hadoop.hbase.mapreduce.TableReducer;

  18. import org.apache.hadoop.hbase.util.Bytes;

  19. import org.apache.hadoop.io.IntWritable;

  20. import org.apache.hadoop.io.Text;

  21. import org.apache.hadoop.mapreduce.Job;

  22. public class HBaseMr {

  23. static Configuration config = null;

  24. static {

  25. config = HBaseConfiguration.create();

  26. config.set("hbase.zookeeper.quorum", "slave1,slave2,slave3");

  27. config.set("hbase.zookeeper.property.clientPort", "2181");

  28. }

  29. public static final String tableName = "word";//表名1

  30. public static final String colf = "content";//列族

  31. public static final String col = "info";//列

  32. public static final String tableName2 = "stat";//表名2

  33. public static void initTB() {

  34. HTable table=null;

  35. HBaseAdmin admin=null;

  36. try {

  37. admin = new HBaseAdmin(config);//建立表管理

  38. if (admin.tableExists(tableName)||admin.tableExists(tableName2)) {

  39. System.out.println("table is already exists!");

  40. admin.disableTable(tableName);

  41. admin.deleteTable(tableName);

  42. admin.disableTable(tableName2);

  43. admin.deleteTable(tableName2);

  44. }

  45. HTableDescriptor desc = new HTableDescriptor(tableName);

  46. HColumnDescriptor family = new HColumnDescriptor(colf);

  47. desc.addFamily(family);

  48. admin.createTable(desc);

  49. HTableDescriptor desc2 = new HTableDescriptor(tableName2);

  50. HColumnDescriptor family2 = new HColumnDescriptor(colf);

  51. desc2.addFamily(family2);

  52. admin.createTable(desc2);

  53. table = new HTable(config,tableName);

  54. table.setAutoFlush(false);

  55. table.setWriteBufferSize(500);

  56. List<Put> lp = new ArrayList<Put>();

  57. Put p1 = new Put(Bytes.toBytes("1"));

  58. p1.add(colf.getBytes(), col.getBytes(), ("The Apache Hadoop software library is a framework").getBytes());

  59. lp.add(p1);

  60. Put p2 = new Put(Bytes.toBytes("2"));p2.add(colf.getBytes(),col.getBytes(),("The common utilities that support the other Hadoop modules").getBytes());

  61. lp.add(p2);

  62. Put p3 = new Put(Bytes.toBytes("3"));

  63. p3.add(colf.getBytes(), col.getBytes(),("Hadoop by reading the documentation").getBytes());

  64. lp.add(p3);

  65. Put p4 = new Put(Bytes.toBytes("4"));

  66. p4.add(colf.getBytes(), col.getBytes(),("Hadoop from the release page").getBytes());

  67. lp.add(p4);

  68. Put p5 = new Put(Bytes.toBytes("5"));

  69. p5.add(colf.getBytes(), col.getBytes(),("Hadoop on the mailing list").getBytes());

  70. lp.add(p5);

  71. table.put(lp);

  72. table.flushCommits();

  73. lp.clear();

  74. } catch (Exception e) {

  75. e.printStackTrace();

  76. } finally {

  77. try {

  78. if(table!=null){

  79. table.close();

  80. }

  81. } catch (IOException e) {

  82. e.printStackTrace();

  83. }

  84. }

  85. }

  86. public static class MyMapper extends TableMapper<Text, IntWritable> {

  87. private static IntWritable one = new IntWritable(1);

  88. private static Text word = new Text();

  89. @Override

  90. //輸入的類型為:key:rowKey; value:一行資料的結果集Result

  91. protected void map(ImmutableBytesWritable key, Result value,

  92. Context context) throws IOException, InterruptedException {

  93. //擷取一行資料中的colf:col

  94. String words = Bytes.toString(value.getValue(Bytes.toBytes(colf), Bytes.toBytes(col)));// 表裡面隻有一個列族,是以我就直接擷取每一行的值

  95. //按空格分割

  96. String itr[] = words.toString().split(" ");

  97. //循環輸出word和1

  98. for (int i = 0; i < itr.length; i++) {

  99. word.set(itr[i]);

  100. context.write(word, one);

  101. }

  102. }

  103. }

  104. public static class MyReducer extends

  105. TableReducer<Text, IntWritable, ImmutableBytesWritable> {

  106. @Override

  107. protected void reduce(Text key, Iterable<IntWritable> values,

  108. Context context) throws IOException, InterruptedException {

  109. //對mapper的資料求和

  110. int sum = 0;

  111. for (IntWritable val : values) {//疊加

  112. sum += val.get();

  113. }

  114. // 建立put,設定rowkey為單詞

  115. Put put = new Put(Bytes.toBytes(key.toString()));

  116. // 封裝資料

  117. put.add(Bytes.toBytes(colf), Bytes.toBytes(col),Bytes.toBytes(String.valueOf(sum)));

  118. //寫到hbase,需要指定rowkey、put

  119. context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())),put);

  120. }

  121. }

  122. public static void main(String[] args) throws IOException,

  123. ClassNotFoundException, InterruptedException {

  124. config.set("df.default.name", "hdfs://master:9000/");//設定hdfs的預設路徑

  125. config.set("hadoop.job.ugi", "hadoop,hadoop");//使用者名,組

  126. config.set("mapred.job.tracker", "master:9001");//設定jobtracker在哪

  127. //初始化表

  128. initTB();//初始化表

  129. //建立job

  130. Job job = new Job(config, "HBaseMr");//job

  131. job.setJarByClass(HBaseMr.class);//主類

  132. //建立scan

  133. Scan scan = new Scan();

  134. //可以指定查詢某一列

  135. scan.addColumn(Bytes.toBytes(colf), Bytes.toBytes(col));

  136. //建立查詢hbase的mapper,設定表名、scan、mapper類、mapper的輸出key、mapper的輸出value

  137. TableMapReduceUtil.initTableMapperJob(tableName, scan, MyMapper.class,Text.class, IntWritable.class, job);

  138. //建立寫入hbase的reducer,指定表名、reducer類、job

  139. TableMapReduceUtil.initTableReducerJob(tableName2, MyReducer.class, job);

  140. System.exit(job.waitForCompletion(true) ? 0 : 1);

  141. }

  142. }

五 HBASE運作原理

5.1 master職責

1.管理監控HRegionServer,實作其負載均衡。

2.處理region的配置設定或轉移,比如在HRegion split時配置設定新的HRegion;在HRegionServer退出時遷移其負責的HRegion到其他        HRegionServer上。

3.進行中繼資料的變更

4.管理namespace和table的中繼資料(實際存儲在HDFS上)。

5.權限控制(ACL)。

6.監控叢集中所有HRegionServer的狀态(通過Heartbeat和監聽ZooKeeper中的狀态)。

5.2 Region Server 職責

  1. 管理自己所負責的region資料的讀寫。
  2. 讀寫HDFS,管理Table中的資料。
  3. Client直接通過HRegionServer讀寫資料(從HMaster中擷取中繼資料,找到RowKey所在的HRegion/HRegionServer後)。
  4. 重新整理緩存到HDFS
  5. 維護Hlog
  6. 執行壓縮
  7. 負責處理Region分片

5.3 zookeeper叢集所起作用

  1. 存放整個HBase叢集的中繼資料以及叢集的狀态資訊。
  2. 實作HMaster主從節點的failover。

注: HMaster通過監聽ZooKeeper中的Ephemeral節點(預設:/hbase/rs/*)來監控HRegionServer的加入和當機。

在第一個HMaster連接配接到ZooKeeper時會建立Ephemeral節點(預設:/hbasae/master)來表示Active的HMaster,其後加進來的HMaster則監聽該Ephemeral節點

如果目前Active的HMaster當機,則該節點消失,因而其他HMaster得到通知,而将自身轉換成Active的HMaster,在變為Active的HMaster之前,它會在/hbase/masters/下建立自己的Ephemeral節點。

5.4 HBASE讀寫資料流程

5.4.1 寫資料流程

用戶端現在要插入一條資料,rowkey=r000001, 這條資料應該寫入到table表中的那個region中呢?

1/ 用戶端要連接配接zookeeper, 從zk的

/hbase

節點找到

hbase:meta

表所在的regionserver(

host:port

);

2/ 

regionserver

掃描

hbase:meta

中的每個region的起始行健,對比

r000001

這條資料在那個region的範圍内;

3/ 從對應的 

info:server

 key中存儲了region是有哪個regionserver(

host:port

)在負責的;

4/ 用戶端直接請求對應的regionserver;

5/ regionserver接收到用戶端發來的請求之後,就會将資料寫入到region中

#CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化

5.4.2 讀資料流程

用戶端現在要查詢rowkey=r000001這條資料,那麼這個流程是什麼樣子的呢?

#CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化

1/ 首先Client連接配接zookeeper, 找到hbase:meta表所在的regionserver;

2/ 請求對應的regionserver,掃描hbase:meta表,根據namespace、表名和rowkey在meta表中找到r00001所在的region是由那個regionserver負責的;

3/找到這個region對應的regionserver

4/ regionserver收到了請求之後,掃描對應的region傳回資料到Client

(先從MemStore找資料,如果沒有,再到BlockCache裡面讀;BlockCache還沒有,再到StoreFile上讀(為了讀取的效率);

如果是從StoreFile裡面讀取的資料,不是直接傳回給用戶端,而是先寫入BlockCache,再傳回給用戶端。)

注:客戶會緩存這些位置資訊,然而第二步它隻是緩存目前RowKey對應的HRegion的位置,因而如果下一個要查的RowKey不在同一個HRegion中,則需要繼續查詢hbase:meta所在的HRegion,然而随着時間的推移,用戶端緩存的位置資訊越來越多,以至于不需要再次查找hbase:meta Table的資訊,除非某個HRegion因為當機或Split被移動,此時需要重新查詢并且更新緩存。

5.4.3 資料flush過程

1)當MemStore資料達到門檻值(預設是128M,老版本是64M),将資料刷到硬碟,将記憶體中的資料删除,同時删除HLog中的曆史資料;

2)并将資料存儲到HDFS中;

3)在HLog中做标記點。

5.4.4 資料合并過程

1)當資料塊達到3塊,Hmaster觸發合并操作,Region将資料塊加載到本地,進行合并;

2)當合并的資料超過256M,進行拆分,将拆分後的Region配置設定給不同的HregionServer管理;

3)當HregionServer當機後,将HregionServer上的hlog拆分,然後配置設定給不同的HregionServer加載,修改.META.;

4)注意:HLog會同步到HDFS。

5.5 hbase:meta表

hbase:meta表存儲了所有使用者HRegion的位置資訊:

Rowkey:tableName,regionStartKey,regionId,replicaId等;

info列族:這個列族包含三個列,他們分别是:

info:regioninfo列:

regionId,tableName,startKey,endKey,offline,split,replicaId;

info:server列:HRegionServer對應的server:port;

info:serverstartcode列:HRegionServer的啟動時間戳。

#CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化

5.6 Region Server内部機制

#CSDN軟體工程師能力認證學習精選# Hbase從入門到入坑一 什麼是HBASE二 安裝HBASE三 hbase初體驗四 HBASE用戶端API操作五 HBASE運作原理六.HBASE優化
  • WAL即Write Ahead Log,在早期版本中稱為HLog,它是HDFS上的一個檔案,如其名字所表示的,所有寫操作都會先保證将資料寫入這個Log檔案後,才會真正更新MemStore,最後寫入HFile中。WAL檔案存儲在/hbase/WALs/${HRegionServer_Name}的目錄中
  • BlockCache是一個讀緩存,即“引用局部性”原理(也應用于CPU,分空間局部性和時間局部性,空間局部性是指CPU在某一時刻需要某個資料,那麼有很大的機率在一下時刻它需要的資料在其附近;時間局部性是指某個資料在被通路過一次後,它有很大的機率在不久的将來會被再次的通路),将資料預讀取到記憶體中,以提升讀的性能。
  • HRegion是一個Table中的一個Region在一個HRegionServer中的表達。一個Table可以有一個或多個Region,他們可以在一個相同的HRegionServer上,也可以分布在不同的HRegionServer上,一個HRegionServer可以有多個HRegion,他們分别屬于不同的Table。HRegion由多個Store(HStore)構成,每個HStore對應了一個Table在這個HRegion中的一個Column Family,即每個Column Family就是一個集中的存儲單元,因而最好将具有相近IO特性的Column存儲在一個Column Family,以實作高效讀取(資料局部性原理,可以提高緩存的命中率)。HStore是HBase中存儲的核心,它實作了讀寫HDFS功能,一個HStore由一個MemStore 和0個或多個StoreFile組成。
  • MemStore是一個寫緩存(In Memory Sorted Buffer),所有資料的寫在完成WAL日志寫後,會 寫入MemStore中,由MemStore根據一定的算法将資料Flush到地層HDFS檔案中(HFile),通常每個HRegion中的每個 Column Family有一個自己的MemStore。
  • HFile(StoreFile) 用于存儲HBase的資料(Cell/KeyValue)。在HFile中的資料是按RowKey、Column Family、Column排序,對相同的Cell(即這三個值都一樣),則按timestamp倒序排列。
  • FLUSH詳述
  1. 每一次Put/Delete請求都是先寫入到MemStore中,當MemStore滿後會Flush成一個新的StoreFile(底層實作是HFile),即一個HStore(Column Family)可以有0個或多個StoreFile(HFile)。
  2. 當一個HRegion中的所有MemStore的大小總和超過了hbase.hregion.memstore.flush.size的大小,預設128MB。此時目前的HRegion中所有的MemStore會Flush到HDFS中。
  3. 當全局MemStore的大小超過了hbase.regionserver.global.memstore.upperLimit的大小,預設40%的記憶體使用量。此時目前HRegionServer中所有HRegion中的MemStore都會Flush到HDFS中,Flush順序是MemStore大小的倒序(一個HRegion中所有MemStore總和作為該HRegion的MemStore的大小還是選取最大的MemStore作為參考?有待考證),直到總體的MemStore使用量低于hbase.regionserver.global.memstore.lowerLimit,預設38%的記憶體使用量。
  4. 目前HRegionServer中WAL的大小超過了hbase.regionserver.hlog.blocksize * hbase.regionserver.max.logs的數量,目前HRegionServer中所有HRegion中的MemStore都會Flush到HDFS中,Flush使用時間順序,最早的MemStore先Flush直到WAL的數量少于hbase.regionserver.hlog.blocksize * hbase.regionserver.max.logs這裡說這兩個相乘的預設大小是2GB,查代碼,hbase.regionserver.max.logs預設值是32,而hbase.regionserver.hlog.blocksize預設是32MB。但不管怎麼樣,因為這個大小超過限制引起的Flush不是一件好事,可能引起長時間的延遲

六.HBASE優化

6.1 高可用

在HBase中Hmaster負責監控RegionServer的生命周期,均衡RegionServer的負載,如果Hmaster挂掉了,那麼整個HBase叢集将陷入不健康的狀态,并且此時的工作狀态并不會維持太久。是以HBase支援對Hmaster的高可用配置。

1.關閉HBase叢集(如果沒有開啟則跳過此步)

[[email protected] hbase]$ bin/stop-hbase.sh

2.在conf目錄下建立backup-masters檔案

[[email protected] hbase]$ touch conf/backup-masters

3.在backup-masters檔案中配置高可用HMaster節點

[a[email protected] hbase]$ echo hadoop103 > conf/backup-masters

4.将整個conf目錄scp到其他節點

[atg[email protected] hbase]$ scp -r conf/ hadoop103:/opt/module/hbase/

[atg[email protected] hbase]$ scp -r conf/ hadoop104:/opt/module/hbase/

6.2 預分區

每一個region維護着startRow與endRowKey,如果加入的資料符合某個region維護的rowKey範圍,則該資料交給這個region維護。那麼依照這個原則,我們可以将資料所要投放的分區提前大緻的規劃好,以提高HBase性能。

1.手動設定預分區

hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']

2.生成16進制序列預分區

create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

3.按照檔案中設定的規則預分區

建立splits.txt檔案内容如下:

aaaa

bbbb

cccc

dddd

然後執行:

create 'staff3','partition3',SPLITS_FILE => 'splits.txt'

4.使用JavaAPI建立預分區

//自定義算法,産生一系列Hash散列值存儲在二維數組中

byte[][] splitKeys = 某個散列值函數

//建立HBaseAdmin執行個體

HBaseAdmin hAdmin = new HBaseAdmin(HBaseConfiguration.create());

//建立HTableDescriptor執行個體

HTableDescriptor tableDesc = new HTableDescriptor(tableName);

//通過HTableDescriptor執行個體和散列值二維數組建立帶有預分區的HBase表

hAdmin.createTable(tableDesc, splitKeys);

6.3 RowKey設計

一條資料的唯一辨別就是rowkey,那麼這條資料存儲于哪個分區,取決于rowkey處于哪個一個預分區的區間内,設計rowkey的主要目的 ,就是讓資料均勻的分布于所有的region中,在一定程度上防止資料傾斜。接下來我們就談一談rowkey常用的設計方案。

1.生成随機數、hash、散列值

比如:

原本rowKey為1001的,SHA1後變成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7

原本rowKey為3001的,SHA1後變成:49042c54de64a1e9bf0b33e00245660ef92dc7bd

原本rowKey為5001的,SHA1後變成:7b61dec07e02c188790670af43e717f0f46e8913

在做此操作之前,一般我們會選擇從資料集中抽取樣本,來決定什麼樣的rowKey來Hash後作為每個分區的臨界值。

2.字元串反轉

20170524000001轉成10000042507102

20170524000002轉成20000042507102

3.字元串拼接

20170524000001_a12e

20170524000001_93i7

6.4 記憶體優化

HBase操作過程中需要大量的記憶體開銷,畢竟Table是可以緩存在記憶體中的,一般會配置設定整個可用記憶體的70%給HBase的Java堆。但是不建議配置設定非常大的堆記憶體,因為GC過程持續太久會導緻RegionServer處于長期不可用狀态,一般16~48G記憶體就可以了,如果因為架構占用記憶體過高導緻系統記憶體不足,架構一樣會被系統服務拖死。

6.5 基礎優化

1.允許在HDFS的檔案中追加内容

hdfs-site.xml、hbase-site.xml

屬性:dfs.support.append

解釋:開啟HDFS追加同步,可以優秀的配合HBase的資料同步和持久化。預設值為true。

2.優化DataNode允許的最大檔案打開數

hdfs-site.xml

屬性:dfs.datanode.max.transfer.threads

解釋:HBase一般都會同一時間操作大量的檔案,根據叢集的數量和規模以及資料動作,設定為4096或者更高。預設值:4096

3.優化延遲高的資料操作的等待時間

hdfs-site.xml

屬性:dfs.image.transfer.timeout

解釋:如果對于某一次資料操作來講,延遲非常高,socket需要等待更長的時間,建議把該值設定為更大的值(預設60000毫秒),以確定socket不會被timeout掉。

4.優化資料的寫入效率

mapred-site.xml

屬性:

mapreduce.map.output.compress

mapreduce.map.output.compress.codec

解釋:開啟這兩個資料可以大大提高檔案的寫入效率,減少寫入時間。第一個屬性值修改為true,第二個屬性值修改為:org.apache.hadoop.io.compress.GzipCodec或者其他壓縮方式。

5.設定RPC監聽數量

hbase-site.xml

屬性:hbase.regionserver.handler.count

解釋:預設值為30,用于指定RPC監聽的數量,可以根據用戶端的請求數進行調整,讀寫請求較多時,增加此值。

6.優化HStore檔案大小

hbase-site.xml

屬性:hbase.hregion.max.filesize

解釋:預設值10737418240(10GB),如果需要運作HBase的MR任務,可以減小此值,因為一個region對應一個map任務,如果單個region過大,會導緻map任務執行時間過長。該值的意思就是,如果HFile的大小達到這個數值,則這個region會被切分為兩個Hfile。

7.優化hbase用戶端緩存

hbase-site.xml

屬性:hbase.client.write.buffer

解釋:用于指定HBase用戶端緩存,增大該值可以減少RPC調用次數,但是會消耗更多記憶體,反之則反之。一般我們需要設定一定的緩存大小,以達到減少RPC次數的目的。

8.指定scan.next掃描HBase所擷取的行數

hbase-site.xml

屬性:hbase.client.scanner.caching

解釋:用于指定scan.next方法擷取的預設行數,值越大,消耗記憶體越大。

9.flush、compact、split機制

當MemStore達到門檻值,将Memstore中的資料Flush進Storefile;compact機制則是把flush出來的小檔案合并成大的Storefile檔案。split則是當Region達到門檻值,會把過大的Region一分為二。

涉及屬性:

即:128M就是Memstore的預設門檻值

hbase.hregion.memstore.flush.size:134217728

即:這個參數的作用是當單個HRegion内所有的Memstore大小總和超過指定值時,flush該HRegion的所有memstore。RegionServer的flush是通過将請求添加一個隊列,模拟生産消費模型來異步處理的。那這裡就有一個問題,當隊列來不及消費,産生大量積壓請求時,可能會導緻記憶體陡增,最壞的情況是觸發OOM。

hbase.regionserver.global.memstore.upperLimit:0.4

hbase.regionserver.global.memstore.lowerLimit:0.38

即:當MemStore使用記憶體總量達到hbase.regionserver.global.memstore.upperLimit指定值時,将會有多個MemStores flush到檔案中,MemStore flush 順序是按照大小降序執行的,直到重新整理到MemStore使用記憶體略小于lowerLimit

關于CSDN軟體工程師能力認證

      CSDN軟體工程師能力認證(以下簡稱C系列認證)是由中國軟體開發者網CSDN制定并推出的一個能力認證标準。C系列認證曆經近一年的實際線下調研、考察、疊代、測試,并梳理出軟體工程師開發過程中所需的各項技術技能,結合企業招聘需求和人才應聘痛點,基于公開、透明、公正的原則,甑别人才時確定真實業務場景、全部上機實操、所有過程留痕、存檔不可篡改。C系列認證的宗旨是讓一流的技術人才憑真才實學進大廠拿高薪,同時為企業節約大量招聘與培養成本,使命是提升高校大學生的技術能力,為行業提供人才儲備,為國家數字化戰略貢獻力量。

了解詳情可點選:CSDN軟體工程師能力認證介紹

本文出處:https://blog.csdn.net/zuochang_liu/article/details/81452124?ops_request_misc=&request_id=&biz_id=102&utm_term=Hbase&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-81452124.pc_search_result_before_js&spm=1018.2226.3001.4187

繼續閱讀