• Hbase Java API原理介绍


    1.0 Hbase原理及基本说明

    ​HBase 数据模型的关键在于稀疏、分布式、多维、排序的映射。其中映射 map指代非关系型数据库的 key-Value 结构。

    Hbase存储数据的原貌:

    1. <pre class="prettyprint hljs ruby" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">"office_info":{ #列族
    2. "tel":"010-1111111", #tel列
    3. "address":"atguigu" #address
    4. }

    数据模型介绍

    (1)Name Spase数据模型:相当于Mysql中的database,下面可以存放多张表

    (2)Table:相当于数据库中的表

    (3)Row:HBase 表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey

    ​ 的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以 RowKey 的设计十分重要。

    (4)Column:每个列都由 Column Family(列族)和 Column Qualifier(列限定符)进行限定,例如 info: name,info:age。建表时,只需指明列族,而列限定符无需预先定义。

    (5)Time Stamp:用于标识数据的不同版本(version),每条数据写入时,系统会自动为其加上该字段,

    ​ 其值为写入 HBase 的时间。

    (6)Cell:由{rowkey, column Family:column Qualifier, timestamp} 唯一确定的单元。cell 中的数

    ​ 据全部是字节码形式存贮。

    架构说明:

    1)Master

    实现类为 HMaster,负责监控集群中所有的 RegionServer 实例。主要作用如下:

    (1)管理元数据表格 hbase:meta,接收用户对表格创建修改删除的命令并执行

    (2)监控 region 是否需要进行负载均衡,故障转移和 region 的拆分。

    通过启动多个后台线程监控实现上述功能:

    ①LoadBalancer 负载均衡器

    ​ 周期性监控 region 分布在 regionServer 上面是否均衡,由参数 hbase.balancer.period 控制周期时间,默认 5 分钟。

    ②CatalogJanitor 元数据管理器

    ​ 定期检查和清理 hbase:meta 中的数据。meta 表内容在进阶中介绍。

    ③MasterProcWAL master 预写日志处理器

    ​ 把 master 需要执行的任务记录到预写日志 WAL 中,如果 master 宕机,让 backupMaster读取日志继续干。

    2)Region Server

    Region Server 实现类为 HRegionServer,主要作用如下:

    (1)负责数据 cell 的处理,例如写入数据 put,查询数据 get 等

    (2)拆分合并 region 的实际执行者,有 master 监控,有 regionServer 执行。

    3)Zookeeper

    ​ HBase 通过 Zookeeper 来做 master 的高可用、记录 RegionServer 的部署信息、并且存储有 meta 表的位置信息。 HBase 对于数据的读写操作时直接访问 Zookeeper 的,在 2.3 版本推出 Master Registry模式,客户端可以直接访问 master。使用此功能,会加大对 master 的压力,减轻对 Zookeeper的压力。

    4)HDFS

    ​ HDFS 为 Hbase 提供最终的底层数据存储服务,同时为 HBase 提供高容错的支持。

    2.0HbaseAPI的使用

    2.1创建连接

    ​ HBase 的客户端连接由 ConnectionFactory 类来创建,用户使用完成之后需要 手动关闭连接 。同时连接是一个重量级的,推荐 一个进程使用一个连接 ,对 HBase的命令通过连接中的两个属性 Admin 和 Table 来实现 。使用类 单例模式 ,确保使用一个连接, 可以同时用于多个线程 。

    1. "prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;
    2. import org.apache.hadoop.conf.Configuration;
    3. import org.apache.hadoop.hbase.HBaseConfiguration;
    4. import org.apache.hadoop.hbase.client.Connection;
    5. import org.apache.hadoop.hbase.client.ConnectionFactory;
    6. import java.io.IOException;
    7. public class HbaseConnection{
    8. public static Connection connection=null; //声明一个静态属性
    9. static {
    10. //1.创建连接
    11. //默认使用同步连接
    12. try {
    13. //使用读取本地文件的方式添加参数
    14. connection=ConnectionFactory.createConnection();
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. public static void closeConnection() throws IOException{
    20. //判断连接是否为null
    21. if (connection!=null){
    22. connection.close();
    23. }
    24. }
    25. public static void main(String[] args) throws IOException {
    26. //直接使用创建好的连接,不要在main线程里面单独创建
    27. System.out.println(HbaseConnection.connection);
    28. //在main线程的最后记得关闭连接
    29. HbaseConnection.closeConnection();
    30. }
    31. }

    还记得静态代码块的特点吗? 随着类的加载而执行,而且只执行一次

    ​ 静态代码块 :执行优先级高于非静态的初始化块,它会在类初始化的时候执行一次,执行完成便销毁,它仅能初始化类变量

    2.2创建命名空间

    在同一个包下创建HbaseDDL类,执行创建命名空间的功能,使用建造者模式

    1. <pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;
    2. import org.apache.hadoop.hbase.NamespaceDescriptor;
    3. import org.apache.hadoop.hbase.client.Admin;
    4. import org.apache.hadoop.hbase.client.Connection;
    5. import java.io.IOException;
    6. public class HBaseDDL {
    7. //声明一个静态属性,获取连接
    8. public static Connection connection = HbaseConnection.connection;
    9. /**
    10. * 创建命名空间,命名空间名称
    11. * @param namespase
    12. * admin的连接是轻量级的,不是线程安全的,不推荐池化或者缓存连接
    13. */
    14. public static void createNamespace(String namespace) throws IOException {
    15. //1.获取admin
    16. Admin admin = connection.getAdmin();
    17. //2.调用方法创建命名空间,给一个描述
    18. //代码相对shell更加底层,shell实现的功能,代码一定能实现
    19. //2.1创建命名空间描述建造者=》设计师
    20. NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);
    21. //2.2给命名空间添加需求
    22. builder.addConfiguration("user","fang");
    23. //2.3使用builder构造出对饮的创建一个命名空间描述
    24. admin.createNamespace(builder.build());
    25. //3.关闭admin
    26. admin.close();
    27. }
    28. public static void main(String[] args) throws IOException {
    29. //测试创建命名空间
    30. createNamespace("fang");
    31. System.out.println("创建成功");
    32. //关闭Hbase连接
    33. HbaseConnection.closeConnection();
    34. }
    35. }

    执行情况:

    在命令行中查看,创建过程,表示创建成功!!!

    看这里,前面的代码你会发现,如果你再次执行代码就会发现会出现问题,原因是,创建的命名空间已经存在理论来说这个问题应该自己解决,并不是将异常直接抛出,可参考如下代码

    1. <pre class="prettyprint hljs swift" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;
    2. import org.apache.hadoop.hbase.NamespaceDescriptor;
    3. import org.apache.hadoop.hbase.client.Admin;
    4. import org.apache.hadoop.hbase.client.Connection;
    5. import java.io.IOException;
    6. public class HBaseDDL {
    7. //声明一个静态属性,获取连接
    8. public static Connection connection = HbaseConnection.connection;
    9. /**
    10. * 创建命名空间,命名空间名称
    11. * @param namespase
    12. * admin的连接是轻量级的,不是线程安全的,不推荐池化或者缓存连接
    13. */
    14. public static void createNamespace(String namespace) throws IOException {
    15. //1.获取admin
    16. Admin admin = connection.getAdmin();
    17. //2.调用方法创建命名空间,给一个描述
    18. //代码相对shell更加底层,shell实现的功能,代码一定能实现
    19. //2.1创建命名空间描述建造者=》设计师
    20. NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);
    21. //2.2给命名空间添加需求
    22. builder.addConfiguration("user","fang");
    23. //2.3使用builder构造出对饮的创建一个命名空间描述
    24. //创建命名空间出现的问题,都属于
    25. try {
    26. admin.createNamespace(builder.build());
    27. } catch (IOException e) {
    28. System.out.println("命名空间已经存在");
    29. e.printStackTrace();
    30. }
    31. //3.关闭admin
    32. admin.close();
    33. }
    34. public static void main(String[] args) throws IOException {
    35. //测试创建命名空间
    36. createNamespace("fang");
    37. System.out.println("执行完成");
    38. //关闭Hbase连接
    39. HbaseConnection.closeConnection();
    40. }
    41. }
    42. package com.fang.hbase;
    43. import org.apache.hadoop.hbase.NamespaceDescriptor;
    44. import org.apache.hadoop.hbase.client.Admin;
    45. import org.apache.hadoop.hbase.client.Connection;
    46. import java.io.IOException;
    47. public class HBaseDDL {
    48. //声明一个静态属性,获取连接
    49. public static Connection connection = HbaseConnection.connection;
    50. /**
    51. * 创建命名空间,命名空间名称
    52. * @param namespase
    53. * admin的连接是轻量级的,不是线程安全的,不推荐池化或者缓存连接
    54. */
    55. public static void createNamespace(String namespace) throws IOException {
    56. //1.获取admin
    57. Admin admin = connection.getAdmin();
    58. //2.调用方法创建命名空间,给一个描述
    59. //代码相对shell更加底层,shell实现的功能,代码一定能实现
    60. //2.1创建命名空间描述建造者=》设计师
    61. NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(namespace);
    62. //2.2给命名空间添加需求
    63. builder.addConfiguration("user","fang");
    64. //2.3使用builder构造出对饮的创建一个命名空间描述
    65. //创建命名空间出现的问题,都属于
    66. try {
    67. admin.createNamespace(builder.build());
    68. } catch (IOException e) {
    69. System.out.println("命名空间已经存在");
    70. e.printStackTrace();
    71. }
    72. //3.关闭admin
    73. admin.close();
    74. }
    75. public static void main(String[] args) throws IOException {
    76. //测试创建命名空间
    77. createNamespace("fang");
    78. System.out.println("执行完成");
    79. //关闭Hbase连接
    80. HbaseConnection.closeConnection();
    81. }
    82. }

    2.3判断表格是否存在

    自行将本代码块,放入上方代码中进行测试即可

    1. <pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">/**
    2. * 创建表格是否存在
    3. * @param namespace
    4. * @return
    5. * @throws IOException
    6. * trur表示存在 false表示不存在
    7. */
    8. public static boolean isTableExists(String namespace,String tableName) throws IOException {
    9. //1.获取admin
    10. Admin admin = connection.getAdmin();
    11. //2.使用方法判断表格是否存在
    12. boolean b = false;
    13. try {
    14. b = admin.tableExists(TableName.valueOf(namespace,tableName));
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }
    18. admin.close();
    19. //3.返回结果
    20. return b;
    21. }

    执行结果:

    2.5创建表格(使用HBase1.3.1版本和2.4版本有所区别)

    1. <pre class="prettyprint hljs typescript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">/**
    2. * @param tableName 表格名称
    3. * @param families 列族名称,可以有多个
    4. */
    5. public static void createTable(String tableName,String... families) throws IOException {
    6. //1.获取admin
    7. Admin admin = connection.getAdmin();
    8. //2.调用方法创建表格
    9. //2.1创建表格描述的建造者
    10. TableName tableName1 = TableName.valueOf(tableName);
    11. HTableDescriptor tableDescriptor=new HTableDescriptor(tableName); //表格描述器
    12. if (families==null||families.length==0){
    13. //如果没有填写列族,给一个info
    14. families=new String[1];
    15. families[0]="info";
    16. }
    17. for (String family : families) {
    18. HColumnDescriptor columnDescriptor= new HColumnDescriptor(family);//列族描述器
    19. tableDescriptor.addFamily(columnDescriptor);
    20. }
    21. try {
    22. admin.createTable(tableDescriptor);
    23. } catch (IOException e) {
    24. System.out.println("表格已存在");
    25. e.printStackTrace();
    26. }
    27. //3.关闭admin
    28. admin.close();
    29. }

    2.6插入数据

    1. <pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">package com.fang.hbase;
    2. import org.apache.hadoop.hbase.HBaseConfiguration;
    3. import org.apache.hadoop.hbase.TableName;
    4. import org.apache.hadoop.hbase.client.Connection;
    5. import org.apache.hadoop.hbase.client.Put;
    6. import org.apache.hadoop.hbase.client.Table;
    7. import org.apache.hadoop.hbase.util.Bytes;
    8. import java.io.IOException;
    9. public class HBaseDML {
    10. public static Connection connection=HbaseConnection.connection; //声明一个静态属性
    11. /**
    12. * @param tableName 表名
    13. * @param rowKey 主键
    14. * @param family 列族名
    15. * @param columnName 列名
    16. * @param value 值
    17. */
    18. public static void putCell(String tableName,String rowKey,String family,String columnName,String value) throws IOException {
    19. //1.获取table
    20. Table table = connection.getTable(TableName.valueOf(tableName));
    21. //2.调用相关方法添加数据
    22. Put put = new Put(Bytes.toBytes(rowKey));
    23. //3.给put对象添加属性
    24. put.addColumn(Bytes.toBytes(family),Bytes.toBytes(columnName),Bytes.toBytes(value));
    25. //4.将对象写入方法
    26. table.put(put);
    27. //5.关闭table
    28. try {
    29. table.close();
    30. } catch (IOException e) {
    31. System.out.println("表格是否存在");
    32. e.printStackTrace();
    33. }
    34. }
    35. public static void main(String[] args) throws IOException {
    36. //测试添加数据
    37. putCell("shuju:huahua","1000","age","agga","43");
    38. System.out.println("其他代码");
    39. //关闭连接
    40. HbaseConnection.closeConnection();
    41. }
    42. }

    测试成功!

  • 相关阅读:
    对比Flink、Storm、Spark Streaming 的反压机制
    Vue3 el-tooltip 根据内容控制宽度大小换行和并且内容太短不显示
    【三维目标检测】Part-A2(二)
    K线形态识别_T字线和倒T字线
    向前迈进!走入GC世界:G1 GC原理深入解析
    【数据结构】二叉树--链式结构的实现 (遍历)
    【C++程序员必修第一课】C++基础课程-05:运算符(上)
    以字节跳动内部 Data Catalog 架构升级为例聊业务系统的性能优化
    vulnhub靶机DC5
    for-in与不可枚举
  • 原文地址:https://blog.csdn.net/Java_ttcd/article/details/126522319