HBase-api管理

简介:

列族管理

  • 在java中HColumnDescriptor代表列族,但是已经过时了,新代替的是ColumnFamilyDescriptorBuilder来创建列族描述符

    ...
    ColumnFamilyDescriptor newc = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("newc")).build();
    Admin admin = connection.getAdmin();
    TableName tableName = TableName.valueOf("test");
    admin.addColumnFamily(tableName,newc);
    ...

Admin

  • 是管理功能最重要的部分,HBaseAdmin是Admin接口的实现类,并实现了自动关闭资源的接口
  • 下面是一些比较重要的属性设置
  • 数据生存时间

    • 即数据插入后存在表中的时间,到时间时候该数据将被清理掉,是以秒来计时的
    ColumnFamilyDescriptor newc = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("newc"))
            .setTimeToLive(10).build();
    • 当数据插入十秒内,数据是存在的,之后数据就会被删除,Put也有一个设置存活时间的,不过单位是毫秒
    put.setTTL(12L);
  • 设置历史版本数

    setMinVersions(1);
    setMaxVersions(2);
  • 布隆过滤器

    • 之前我们说过,数据最终是以HFile形式存储在HDFS的,HFile数据一般比较大,那么在HFile中查询数据肯定是比较慢的,所以HFile使用了块索引机制,原理就是在HFile中增加一部分,单独存储该HFile中的所有行键,这样扫描器就可以通过块索引来找行键,当找到行键的时候再去具体的位置获取该行的其他信息

    markdown_img_paste_20181212095322996

    • 虽然引入了块索引,但是查询速度依旧是很慢的,因为要把所有的行键按顺序查找过去,还是需要很长时间的,所以引入了布隆过滤器
    • 布隆过滤器可以知道元素在结合中是否"不存在"或者"可能存在",也就是说如果布隆过滤器认为该元素不存在那么就是不存在,这样可以极大的加速检索速度,因为跳过了扫描不必要的块索引

    markdown_img_paste_20181212095923248

    • 如上图,结合布隆过滤器就直接滤过了前两个块索引,从而加快查询速度,布隆过滤器有两种工作方式

      • 行模式:针对行进行过滤
      • 行列模式:针对行列进行过滤
    • 行列模式要比行模式大,因为比起行模式,行列模式要额外存储列信息
    • 布隆过滤器默认是开启的,并且默认为行模式,可以通过ColumnFamilyDescriptor来设置
    setBloomFilterType(BloomType bt);
    • 可选枚举有:NONE:关闭布隆过滤器=>ROW:行模式=>ROWCOL:行列模式
  • 块缓存

    • BlockCache使用内存来记录数据,适用于提升读取性能,当开启块缓存后,HBase会优先从块缓存中查询是否有记录,如果没有采取检索硬盘上的HFile,详细的以后再说
  • 大字段

    • 在HBase中存储图片文档之类的较大文件的时候,它叫做MOB,即Medium Object,中等对象的意思,当文件大于100KB小于10MB就可以被视为MOB,Hbase存储MOB字段的时候也是把该文件存储到HDFS,而表中只是存储了该文件的链接
    • 该特性只有在HFile版本3以上才有,所以可以打开hbase-default.xml确认一下

      <property>
          <name>hfile.format.version</name>
          <value>3</value>
      </property>
    • 设置列族的MOB方式
    .setMobEnabled(true);   //默认关闭,开启MOB
    .setMobThreshold(..); // 设置Mob值,默认为100KB
    .setMobCompactPartitionPolicy(..);  // 开启MOB的分区策略

表管理

  • 大多数属性的设置都是在列族上,所以表管理设置的属性比列族要少,之前使用的HTableDescriptor一样过期了,现在推荐使用的是TableDescriptorBuilder来构建TableDescriptor对象
  • 最大文件尺寸

    • 即设置region的最大尺寸,如果region的大小超过了定义值,则会触发region拆分,默认是10GB才会拆分,设置方式为
    TableDescriptorBuilder.newBuilder(TableName.valueOf("test")).setMaxFileSize(1L).build();
  • 只读模式

    • 设置为只读模式后,如果尝试插入数据后会报错的
    builder.setReadOnly(true);
  • MemStore刷写值

    • 设置刷写的最大值,当MemStore存储的数据大于该值就会触发刷写flush,默认64MB
    builder.setMemStoreFlushSize(1L);
  • 操作列族

    • 即对列族的增删改
    builder.removeColumnFamily();
    builder.modifyColumnFamily();
    builder.setColumnFamily();
  • 还有一些方法可以尝试使用,这里就不列举了

Region管理

  • 关闭Region

    • 关闭Region之前,我们要知道数据存放在哪个Region上面,进入hbase shell,然后执行
    hbase(main):010:0> scan 'hbase:meta',{FILTER=>"(PrefixFilter('test'))"}
    • 输出

markdown_img_paste_20181212122944898

  • 如上可以看出,表只占用了一个Region,并且得知了红框标识的region的信息,比如
  • region的name:test,,1544507358220.596ec67dce5ce39adc1654f50c82e4f8.
  • 所在服务器:hd4
  • 服务器端口:16020
  • 启动码(serverstartcode):1544588644294等一些其他信息
  • 知道了这些,我们就可以用这些信息来关闭指定的region
Admin admin = connection.getAdmin();
admin.unassign(Bytes.toBytes("test,,1544507358220.596ec67dce5ce39adc1654f50c82e4f8."),true);
  • 在执行完毕后,这张表将不能再进行数据查询,会报错:RetriesExhaustedException
  • 既然是假un的方法,那么肯定有相反的方法使其region上线
admin.assign(Bytes.toBytes("test,,1544507358220.596ec67dce5ce39adc1654f50c82e4f8."))
  • 在进行查询就可以出数据了
  • 查询所有RegionServer列表

    Map<ServerName, ServerMetrics> liveServerMetrics = admin.getClusterMetrics().getLiveServerMetrics();
    admin.getClusterMetrics().getDeadServerNames().forEach(System.out::println);
    • admin.getClusterMetrics()返回的ClusterMetrics对象可以get到很多东西,比如集群id之类的信息
  • 查询regionserver下所有region列表

    List<RegionInfo> test = admin.getRegions(TableName.valueOf("test"));
    List<RegionInfo> test2 = admin.getRegions(ServerName.parseServerName("hd4,16020,1544588644294"));
    • 这个方法可以获取属于一个表的所有region和一个regionserver上的所有region,第二个方法的ServerName字符串是由:所在服务器:所在服务器端口,启动码(serverstartcode)组成的,上面ServerName使用的方法也可以换为ServerName.valueof
  • 对于admin操作region其他api还有很多,包括移动region,切分region,强制刷新region到hdfs上等一系列方法,可以用到的时候在查

快照管理

  • 快照就是某一时刻的结构和数据,可以使用快照来将某个表回复到某个时刻的结构和数据,而且不需要担心创建和恢复的过程会很慢,这个过程只需要数秒就可以完成
  • 是怎么做到这么快恢复的?,快照只是保存了一份文件列表,通过修改表示所连接的文件来改变表的数据,这样做会相当快并且不消耗额外的磁盘空间
  • 使用:首先要确认是否开启了快照功能,检查hbase-site.xml和hbase-default.xml文件

    <property>
      <name>hbase.snapshot.enabled</name>
      <value>true</value>
    </property>
  • 下面将是列出数据库中的快照列表的操作

    List<SnapshotDescription> snapshotDescriptions = admin.listSnapshots();
  • 也可以使用listSnapshots(Pattern pattern)来匹配快照
  • 目前hbase中是没有快照的,现在我们新建一个表,并插入数据

    hbase(main):007:0> put 'test','row1','cf:name','wzq'
  • 然后我们创建此表的快照

    admin.snapshot("mytest_snapshot",TableName.valueOf("test"));
  • 这时候再次查看将出现一个新建快照,快照的作用是恢复数据,现在我们来重新插入一条cf:name以覆盖原来的值

    hbase(main):012:0> put 'test','row1','cf:name','wangziqiang'
  • 好了我们现在用快照恢复一下,在使用快照恢复的时候需要先将表禁用掉,然后才能进行快照恢复,否则会就爆 TableNotDisabledException

    admin.disableTable(tableName);
    admin.restoreSnapshot("mytest_snapshot");
    admin.enableTable(tableName);
  • 当执行完毕,数据就已经恢复原样了,快照的操作还有删除快照等方法,用到的时候直接查询就行了

均衡器

  • 当hbase遇到负载均衡的问题的时候,hbase提供了一个均衡器用于自动均衡各个RegionServer之间的压力,方法就是移动Region到不同的RegionServer上以平摊压力
  • 最早的内置均衡器是SimpleLoadBalancer,之后被StochasticLoadBalancer替代,现在是RegionServer Group 技术,不过参考资料中的是StochasticLoadBalancer,所以在这简单的记一下,之后再去了解RegionServer Group
  • StochasticLoadBalancer在做负载均衡的时候同时考虑了以下5个因 素

    • Region Load:Region的负载
    • Table Load:表的负载
    • DataLocality:数据本地化
    • MemStore Sizes:MemStore的大小
    • StoreFile Size:StoreFile大小
  • 下面是均衡器的相关参数

    • hbase.balancer.period:均衡器的执行周期,默认5分钟执行一次,均衡器会启动一个叫BalancerChore的线程,该线程会定时去扫描是否有RegionServer需要做重均衡rebalancer
    • hbase.regions.slop:负载容忍值,默认0.01,这个参数是有关于判断RegionServer是否需要被均衡的,计算公式是avg+(avg*slop)regions,其中avg就是每个regionserver上region的平均数,如果超过了这个结果值,那么就开始进行负载均衡
    • hbase.master.loadbalancer.class:均衡器的实现类,默认为StochasticLoadBalancer
  • 下面是admin中balancer的几个方法

    //调用平衡器.将运行平衡器,如果区域要移动,它将继续执行并执行重新分配
    admin.balance();
    //打开或关闭balancer,异步还是同步
    admin.balancerSwitch(boolean onOrOff, boolean synchronous);

标准化器

  • 用来标准化Region的尺寸的,如果该Region不是标准的Region,那么标准化器就会改变它
  • 怎么才算是不标准的region?是否标准是指region的大小,标准化器首先会计算出某个表的平均region大小,当某个region太大或太小了就成为不标准的region,所以最终是把region的大小控制在一个相对稳定的大小范围
  • 如果遇到大region肯定要拆分region,而小region就需要合并,所以就会引发拆分合并风暴

    • 拆分/合并风暴(split/merge storms)指在某种情况下拆分了某 几个Region后,系统达到了某个阈值,这个阈值会触发Region的合并,于是Region开始合并,但是合并后又触发了另一个阈值,该阈值导致 HBase开始拆分Region,如此循环往复,造成了一个不断拆分/合并的死 循环,大量地消耗HBase的性能
  • 有很多因素可以影响region的拆分和合并

    • 均衡器定义的hbase.region.slop偏移量
    • 拆分region的策略定义
    <property>
      <name>hbase.regionserver.region.split.policy</name>
      <value>
      org.apache.hadoop.hbase.regionserver.SteppingSplitPolicy
      </value>
    </property>
    • 单个region定义的最大文件大小
    <property>
      <name>hbase.hregion.max.filesize</name>
      <value>10737418240</value>
    </property>
  • 那么标准化器到底是做什么呢

    • 获取该表的所有region
    • 计算出region的平均大小
    • 如果region大小大于平均大小的两倍,就会被拆分
    • 不断合并最小的两个region,只要最小的两个region大小之和小于平均大小,这两个region就会被合并
    • 空region不参与标准化过程,即size<1MB

markdown_img_paste_20181212195325773

  • Admin操作标准化器的方法

    //如果标准化器程序运行,返回true,否则返回false。
    admin.normalize();
    admin.normalizerSwitch(boolean);//打开或者关闭标准化器
    admin.isNormalizerEnabled();//是否开启

目录管理器

  • 目录是指hbase:meta表中存储的region信息,当hbase在拆分或者合并的时候,为了确保数据不丢失都会保留原来的region信息,等拆分或者合并过程结束后,再使用目录管理器catalog janitor来清理这些旧region信息
  • 现在有一个region需要拆分,拆分过程如下

    • 创建两个子region
    • 将数据分成两份复制到子region中
    • 删除父region
  • 由于region的创建需要在hbase:meta表中有对应的信息,所以当子region创建出来后,hbase:meta表的数据数据会多出两个子region信息来,当父region被切分完之后,目录管理器就将父region的信息删除到了,然后就是两个region上线使用
  • admin操作目录管理器使用

    //开启或者关闭
    admin.catalogJanitorSwitch(boolean);
    //目录管理是否可用
    admin.isCatalogJanitorEnabled();
    //执行目录管理操作
    admin.runCatalogJanitor();

ClusterStatus & ServerLoad

  • 之前我们已经获得过ClusterStatus对象,这个类可以获取关于集群了所有状态信息,比如regionserver的数量,region的数量等,api无非就是getxxxSize或者getxxxCount,这里就不贴代码了
  • ServerLoad是服务器负载对象,可以通过这个对象获得内存使用情况,磁盘使用情况等,如果想获取更详细的信息可以访问http://192.168.230.201:60010/jmx,端口是下面属性配置的

    <property>
      <name>hbase.master.info.port</name>
      <value>60010</value>
    </property>
  • 对于Admin其他的操作,以后用到了在总结

可见性标签管理

  • 可见性标签(Visibility Labels)是一串逻辑表达式字符串,用 于标定数据的访问可见,即对数据的简单权限限制

    • developer:只有拥有developer标签的用户可见该数据
    • !developer:拥有developer标签的用户看不见该数据
    • (manager|developer)&!market:拥有manager标签或者 developer标签,并且同时要没有market标签的用户,才看得见 该数据
  • 确认HFile在版本3之上才可以,并且这个功能默认是关闭的,所以需要打开此功能,编辑hbase-site.xml

    <property>
      <name>hbase.security.authorization</name>
      <value>true</value>
    </property>
    <property>
      <name>hbase.coprocessor.region.classes</name>
      <value>org.apache.hadoop.hbase.security.visibility.VisibilityController</value>
    </property>
    <property>
      <name>hbase.coprocessor.master.classes</name>
      <value>org.apache.hadoop.hbase.security.visibility.VisibilityController</value>
    </property>
  • 首先我们看一下系统内是否有自带的标签

    VisibilityLabelsProtos.ListLabelsResponse response = VisibilityClient.listLabels(connection,".*");
    response.getLabelList().forEach(System.out::println);
  • 什么都没输出,说明是没有自带的标签的,所以这些标签都需要我们去添加,既然是涉及到了hbase中的信息修改,就必须有权限才可以进行修改labels表,如果不信可以尝试进行添加labels

    VisibilityClient.addLabel(connection,"myLabel");
  • 上面执行完毕并不会报错,上面代码会返回一个VisibilityLabelsProtos.VisibilityLabelsResponse对象,输出他你将得到一段错误信息

    result {
      exception {
        name: "org.apache.hadoop.hbase.security.AccessDeniedException"
        value: "org.apache.hadoop.hbase.security.AccessDeniedException: User \'qidai\' is not authorized to perform this action.\n\tat org.apache.hadoop.hbase.security.visibility.VisibilityController.checkCallingUserAuth(VisibilityControll...
      }
    }
  • 所以就必须要有权限才可以,使用权限你当然要有身份,当你调用api时你会产生一个身份,在hbase shell的时候,可以通过whoami来看自己是谁

    hbase(main):006:0> whoami
    root (auth:SIMPLE)
        groups: root
    Took 0.0191 seconds
  • 而当java调用的使用,是取的系统的用户名

    System.getProperty("user.name");
  • 当操作标签库等ACL一系列的安全相关的内容时,需要超级用户才可以,所以现在需要将自己的用户名添加到超级用户组,编辑hbase-site.xml

    <property>
         <name>hbase.superuser</name>
         <value>qidai</value>
      </property>
  • 设置完毕后重启hbase,然后再执行添加

    result {
    }
  • 上面是原来返回错误的那个对象输出的结果,看到里面已经没有出错了,所以现在来看一下labels是否添加进去了,在hbase shell 中这样查看

    hbase(main):002:0> list_labels
    myLabel                                                                                                     
    Took 1.8542
    seconds                                                                                                     
      => #<Java::JavaUtil::Collections::UnmodifiableRandomAccessList:0x5855b0ed>
  • 到这就说明添加成功了
  • 好了到这我们规划三个角色,tom,wzq,sam

    • tom有developer标签
    • wzq有manager标签
    • sam没有标签
  • 最后我们添加带有标签的单元格,然后分别用三个用户查看数据观察效果

    • 添加tom,wzq,sam用户
    [root@hd1 ~]# useradd tom
    [root@hd1 ~]# useradd wzq
    [root@hd1 ~]# useradd sam
  • 如果你搭建环境的时候使用的是root的话,那么你新建的用户是不能使用hbase的因为有linux权限,简单方式是可以chmod 一下,然后就可以了,就去之后执行whoami,发现我就是tom,角色没问题后,往下继续
  • 为用户添加标签,首先要有这个label所以先添加developer和manager标签

    VisibilityClient.addLabel(connection,"developer");
    VisibilityClient.addLabel(connection,"manager");
  • 为用户添加developer和manager标签

    VisibilityClient.setAuths(connection,new String[]{"developer"},"tom");
    VisibilityClient.setAuths(connection,new String[]{"manager"},"wzq");
  • 执行完之后我们可以查看一下用户的标签

    for (ByteString bytes : tom) {
        System.out.println("tom=>"+bytes.toStringUtf8());
    }
    System.out.println("*********************");
    List<ByteString> wzq = VisibilityClient.getAuths(connection, "wzq").getAuthList();
    for (ByteString bytes : wzq) {
        System.out.println("wzq=>"+bytes.toStringUtf8());
    }
  • 执行结果为

    tom=>developer
    *********************
    wzq=>manager
  • 到这已经添加成功了,然后我们用不同身份添加cell,目前test表中有列族cf,数据为空

    Put tom = new Put(Bytes.toBytes("row1"));
    CellVisibility tomCellExpression = new CellVisibility("developer");
    tom.setCellVisibility(tomCellExpression);
    tom.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("name"),Bytes.toBytes("tom"));
    
    Put wzq = new Put(Bytes.toBytes("row2"));
    CellVisibility wzqCellExpression = new CellVisibility("manager");
    wzq.setCellVisibility(wzqCellExpression);
    wzq.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("name"),Bytes.toBytes("wzq"));
    
    Put sam = new Put(Bytes.toBytes("row3"));
    sam.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("name"),Bytes.toBytes("sam"));
  • 现在表中数据为

markdown_img_paste_20181212225116549

  • 然后我们用不同的用户进入hbase shell 查看test表

    • tom身份进入

markdown_img_paste_20181212225354783

  • wzq身份进入

markdown_img_paste_20181212225536675

  • sam身份进入

markdown_img_paste_20181212225653688

  • 从上面看出,自己只能查看没有标志其他label的cell和自己的cell,所以到这可见性标签操作就算成功了
  • 对于删除label可以像删除一行数据那样就可以了

    Table table = connection.getTable(TableName.valueOf("hbase:labels"));
    Delete delete = new Delete(Bytes.toBytes(2));
  • hbase:labels表中的数据只对超级用户提供查看权限,我用两个不同的用户一个是root一个是wzq分别scan label表

markdown_img_paste_20181212230111885

markdown_img_paste_20181212230131817

相关实践学习
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
28天前
|
Java API Maven
HDFS的API操作
HDFS的API操作
25 0
|
4月前
|
Java 分布式数据库 API
|
存储 缓存 负载均衡
HBase 详细API操作
HBase 详细API操作
166 0
|
SQL 存储 NoSQL
【HBase】(7)-HBase常用API
【HBase】(7)-HBase常用API
101 0
【HBase】(7)-HBase常用API
|
存储 安全 分布式数据库
【HBase】(七)Hbase 常用API(增删改查)
【HBase】(七)Hbase 常用API(增删改查)
622 0
|
SQL 监控 Java
通过Java API获取Hive Metastore中的元数据信息
本文以Java API为例,介绍如何获取hive standalone metastore中的catalog、database、table等信息,通过该方式,我们可以方便地对元数据中心进行监控与管理。
|
分布式计算 Hadoop Java
Hadoop06【API操作】
将hadoop在Linux中的安装文件解压缩一份。并将此bin目录中的文件覆盖掉解压缩文件
Hadoop06【API操作】
|
API 分布式数据库 Hbase
|
Shell API 分布式数据库