Hbase原理

目录:

一、Hbase介绍

二、HbaseRegion

三、Hbase的读写流程

四、Hbase主键设计

五、Hbase预分区

六、Hbase Java API

--------------------

一、Hbase介绍

1、Hbase简介

Hbase是分布式、面向列的开源数据库(其实准确的说是面向列族)。HDFS为Hbase提供可靠的底层数据存储服务,MapReduce为Hbase提供高性能的计算能力,Zookeeper为Hbase提供稳定服务和Failover机制,因此我们说Hbase是一个通过大量廉价的机器解决海量数据的高速存储和读取的分布式数据库解决方案。

2、Hbase几个特点介绍

2.1、海量存储

Hbase适合存储PB级别的海量数据,在PB级别的数据以及采用廉价PC存储的情况下,能在几十到百毫秒内返回数据。这与Hbase的极易扩展性息息相关。正式因为Hbase良好的扩展性,才为海量数据的存储提供了便利。

2.2、列式存储

这里的列式存储其实说的是列族存储,Hbase是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定。为了加深对Hbase列族的理解,下面是一个简单的关系型数据库的表和Hbase数据库的表:

RDBMS的表:

Hbase的表:

下图是针对Hbase和关系型数据库的基本的一个比较:

2.3、极易扩展

Hbase的扩展性主要体现在两个方面,一个是基于上层处理能力(RegionServer)的扩展,一个是基于存储的扩展(HDFS)。
通过横向添加RegionSever的机器,进行水平扩展,提升Hbase上层的处理能力,提升Hbsae服务更多Region的能力。

2.4、稀疏

稀疏主要是针对Hbase列的灵活性,在列族中,你可以指定任意多的列,在列数据为null的情况下,是不会占用存储空间的。

3、Hbase的几个概念介绍

在我学习Hbase的时候有几个概念需要重点理解一下,列出4个基础概念如下图所示:

3.1、Column Family的概念

Column Family又叫列族,Hbase通过列族划分数据的存储,列族下面可以包含任意多的列,实现灵活的数据存取。

Hbase表的创建的时候就必须指定列族。就像关系型数据库创建的时候必须指定具体的列是一样的。

Hbase的列族不是越多越好,官方推荐的是列族最好小于或者等于3。我们使用的场景一般是1个列族。

3.2、Rowkey的概念

Rowkey的概念和mysql中的主键是完全一样的,Hbase使用Rowkey来唯一的区分某一行的数据。

由于Hbase只支持3中查询方式:

  • 基于Rowkey的单行查询
  • 基于Rowkey的范围扫描
  • 全表扫描

因此,Rowkey对Hbase的性能影响非常大,Rowkey的设计就显得尤为的重要。设计的时候要兼顾基于Rowkey的单行查询也要键入Rowkey的范围扫描。

3.3、Region的概念

Region的概念和关系型数据库的分区或者分片差不多。
Hbase会将一个大表的数据基于Rowkey的不同范围分配到不通的Region中,每个Region负责一定范围的数据访问和存储。这样即使是一张巨大的表,由于被切割到不通的region,访问起来的时延也很低。

3.4、TimeStamp的概念

TimeStamp对Hbase来说至关重要,因为它是实现Hbase多版本的关键。在Hbase中使用不同的timestame来标识相同rowkey行对应的不同版本的数据。

在写入数据的时候,如果用户没有指定对应的timestamp,Hbase会自动添加一个timestamp,timestamp和服务器时间保持一致。
在Hbase中,相同rowkey的数据按照timestamp倒序排列。默认查询的是最新的版本,用户可同指定timestamp的值来读取旧版本的数据。

4、Hbase的架构

Hbase的架构图如下图所示:

hbase

从图中可以看出Hbase是由Client、Zookeeper、Master、HRegionServer、HDFS等几个组建组成,下面来介绍一下几个组建的相关功能:

4.1、Client

Client包含了访问Hbase的接口,另外Client还维护了对应的cache来加速Hbase的访问,比如cache的.META.元数据的信息。

4.2、Zookeeper

Hbase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。具体工作如下:

通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务

通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知Master RegionServer上下限的信息

通过Zoopkeeper存储元数据的统一入口地址

4.3、Hmaster

master节点的主要职责如下:
为RegionServer分配Region
维护整个集群的负载均衡
维护集群的元数据信息
发现失效的Region,并将失效的Region分配到正常的RegionServer上
当RegionSever失效的时候,协调对应Hlog的拆分

4.4、HregionServer

HregionServer直接对接用户的读写请求,是真正的“干活”的节点。它的功能概括如下:
管理master为其分配的Region
处理来自客户端的读写请求
负责和底层HDFS的交互,存储数据到HDFS
负责Region变大以后的拆分
负责Storefile的合并工作

4.5、HDFS

HDFS为Hbase提供最终的底层数据存储服务,同时为Hbase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:
提供元数据和表数据的底层分布式存储服务
数据多副本,保证的高可靠和高可用性

5、Hbase的使用场景

Hbase是一个通过廉价PC机器集群来存储海量数据的分布式数据库解决方案。它比较适合的场景概括如下:

  • 海量数据存储(百T、PB级别)
  • 查询简单(基于rowkey或者rowkey范围查询)
  • 不涉及到复杂的关联

有几个典型的场景特别适合使用Hbase来存储:
海量订单流水数据(长久保存)
交易记录

数据库历史数据


二、Hbase的Region介绍

前面已经介绍了Region类似于数据库的分片和分区的概念,每个Region负责一小部分Rowkey范围的数据的读写和维护,Region包含了对应的起始行到结束行的所有信息。master将对应的region分配给不同的RergionServer,由RegionSever来提供Region的读写服务和相关的管理工作。这部分主要介绍Region实例以及Rgeion的寻找路径:

1、region实例

上图模拟了一个Hbase的表是如何拆分成region,以及分配到不同的RegionServer中去。上面是1个Userinfo表,里面有7条记录,其中rowkey为0001到0002的记录被分配到了Region1上,Rowkey为0003到0004的记录被分配到了Region2上,而rowkey为0005、0006和0007的记录则被分配到了Region3上。region1和region2被master分配给了RegionServer1(RS1),Region3被master配分给了RegionServer2(RS2)

备注:这里只是为了更容易的说明拆分的规则,其实真实的场景并不会几条记录拆分到不通的Region上,而是到一定的数据量才会拆分,具体的在Region的拆分那部分再具体的介绍。

2、Region的寻址

既然读写都在RegionServer上发生,每个RegionSever为一定数量的region服务,那么client要对某一行数据做读写的时候如何能知道具体要去访问哪个RegionServer呢?那就是接下来我们要讨论的问题

2.1、老的Region寻址方式

在Hbase 0.96版本以前,Hbase有两个特殊的表,分别是-ROOT-表和.META.表,其中-ROOT-的位置存储在ZooKeeper中,-ROOT-本身存储了 .META. Table的RegionInfo信息,并且-ROOT-不会分裂,只有一个region。而.META.表可以被切分成多个region。读取的流程如下图所示:

第1步:client请求ZK获得-ROOT-所在的RegionServer地址

第2步:client请求-ROOT-所在的RS地址,获取.META.表的地址,client会将-ROOT-的相关信息cache下来,以便下一次快速访问

第3步:client请求 .META.表的RS地址,获取访问数据所在RegionServer的地址,client会将.META.的相关信息cache下来,以便下一次快速访问

第4步:client请求访问数据所在RegionServer的地址,获取对应的数据

从上面的路径我们可以看出,用户需要3次请求才能直到用户Table真正的位置,这在一定程序带来了性能的下降。在0.96之前使用3层设计的主要原因是考虑到元数据可能需要很大。但是真正集群运行,元数据的大小其实很容易计算出来。在BigTable的论文中,每行METADATA数据存储大小为1KB左右,如果按照一个Region为128M的计算,3层设计可以支持的Region个数为2^34个,采用2层设计可以支持2^17(131072)。那么2层设计的情况下一个 集群可以存储4P的数据。这仅仅是一个Region只有128M的情况下。如果是10G呢? 因此,通过计算,其实2层设计就可以满足集群的需求。因此在0.96版本以后就去掉了-ROOT-表了。

2.2、新的Region寻址方式

如上面的计算,2层结构其实完全能满足业务的需求,因此0.96版本以后将-ROOT-表去掉了。如下图所示:

访问路径变成了3步:

第1步:Client请求ZK获取.META.所在的RegionServer的地址。

第2步:Client请求.META.所在的RegionServer获取访问数据所在的RegionServer地址,client会将.META.的相关信息cache下来,以便下一次快速访问。

第3步:Client请求数据所在的RegionServer,获取所需要的数据。

总结去掉-ROOT-的原因有如下2点:

其一:提高性能
其二:2层结构已经足以满足集群的需求

这里还有一个问题需要说明,那就是Client会缓存.META.的数据,用来加快访问,既然有缓存,那它什么时候更新?如果.META.更新了,比如Region1不在RerverServer2上了,被转移到了RerverServer3上。client的缓存没有更新会有什么情况?

其实,Client的元数据缓存不更新,当.META.的数据发生更新。如上面的例子,由于Region1的位置发生了变化,Client再次根据缓存去访问的时候,会出现错误,当出现异常达到重试次数后就会去.META.所在的RegionServer获取最新的数据,如果.META.所在的RegionServer也变了,Client就会去ZK上获取.META.所在的RegionServer的最新地址。


三、Hbase的读写逻辑

Hbase的写逻辑涉及到写内存、写log、刷盘等操作。

1、Hbase写操作流程

Hbase的写入流程如下图所示:

从上图可以看出氛围3步骤:

第1步:Client获取数据写入的Region所在的RegionServer
第2步:请求写Hlog
第3步:请求写MemStore

只有当写Hlog和写MemStore都成功了才算请求写入完成。MemStore后续会逐渐刷到HDFS中。

备注:Hlog存储在HDFS,当RegionServer出现异常,需要使用Hlog来恢复数据。

2、读操作流程

步骤1client访问Zookeeper,查找-ROOT-表,获取.META.表信息。

步骤2:从.META.表查找,获取存放目标数据的HRegion信息,从而找到对应的HRegionServer

步骤3:通过HRegionServer获取需要查找的数据。

步骤4HRegionserver的内存分为MemStoreBlockCache两部分,MemStore主要用于写数据,BlockCache主要用于读数据。读请求先到MemStore中查数据,查不到就到BlockCache中查,再查不到就会到StoreFile上读,并把读的结果放入BlockCache

3、MemStore刷盘

为了提高Hbase的写入性能,当写请求写入MemStore后,不会立即刷盘。而是会等到一定的时候进行刷盘的操作。具体是哪些场景会触发刷盘的操作呢?总结成如下的几个场景:

3.1、全局内存控制

这个全局的参数是控制内存整体的使用情况,当所有memstore占整个heap的最大比例的时候,会触发刷盘的操作。这个参数是hbase.regionserver.global.memstore.upperLimit,默认为整个heap内存的40%。但这并不意味着全局内存触发的刷盘操作会将所有的MemStore都进行输盘,而是通过另外一个参数hbase.regionserver.global.memstore.lowerLimit来控制,默认是整个heap内存的35%。当flush到所有memstore占整个heap内存的比率为35%的时候,就停止刷盘。这么做主要是为了减少刷盘对业务带来的影响,实现平滑系统负载的目的。

3.2、MemStore达到上限

当MemStore的大小达到hbase.hregion.memstore.flush.size大小的时候会触发刷盘,默认128M大小

3.3、RegionServer的Hlog数量达到上限

前面说到Hlog为了保证Hbase数据的一致性,那么如果Hlog太多的话,会导致故障恢复的时间太长,因此Hbase会对Hlog的最大个数做限制。当达到Hlog的最大个数的时候,会强制刷盘。这个参数是hase.regionserver.max.logs,默认是32个。

3.4、手工触发

可以通过hbase shell或者java api手工触发flush的操作。

3.5、关闭RegionServer触发

在正常关闭RegionServer会触发刷盘的操作,全部数据刷盘后就不需要再使用Hlog恢复数据。

3.6、Region使用HLOG恢复完数据后触发

当RegionServer出现故障的时候,其上面的Region会迁移到其他正常的RegionServer上,在恢复完Region的数据后,会触发刷盘,当刷盘完成后才会提供给业务访问。

4、Hlog

4.1、Hlog简介

Hlog是Hbase实现WAL(Write ahead log)方式产生的日志信息,内部是一个简单的顺序日志。每个RegionServer对应1个Hlog(备注:1.x版本的可以开启MultiWAL功能,允许多个Hlog),所有对于该RegionServer的写入都被记录到Hlog中。Hlog实现的功能就是我们前面讲到的保证数据安全。当RegionServer出现问题的时候,能跟进Hlog来做数据恢复。此外为了保证恢复的效率,Hbase会限制最大保存的Hlog数量,如果达到Hlog的最大个数(hase.regionserver.max.logs参数控制)的时候,就会触发强制刷盘操作。对于已经刷盘的数据,其对应的Hlog会有一个过期的概念,Hlog过期后,会被监控线程移动到 .oldlogs,然后会被自动删除掉。

Hbase是如何判断Hlog过期的呢?要找到这个答案,我们就必须了解Hlog的详细结构。

4.2、Hlog结构

下图是Hlog的详细结构(图片来源 http://hbasefly.com/ ):

从上图我们可以看出都个Region共享一个Hlog文件,单个Region在Hlog中是按照时间顺序存储的,但是多个Region可能并不是完全按照时间顺序。

每个Hlog最小单元由Hlogkey和WALEdit两部分组成。Hlogky由sequenceid、timestamp、cluster ids、regionname以及tablename等组成,WALEdit是由一系列的KeyValue组成,对一行上所有列(即所有KeyValue)的更新操作,都包含在同一个WALEdit对象中,这主要是为了实现写入一行多个列时的原子性。

注意,图中有个sequenceid。sequenceid是一个store级别的自增序列号,这个非常重要,region的数据恢复和Hlog过期清除都要依赖它。下面就来简单描述一下sequenceid的相关逻辑。

  • Memstore在达到一定的条件会触发刷盘的操作,刷盘的时候会获取刷新到最新的一个sequenceid的下一个sequenceid,并将新的sequenceid赋给oldestUnflushedSequenceId,并刷到Ffile中。有点绕,举个例子来说明:比如对于某一个store,开始的时候oldestUnflushedSequenceId为NULL,此时,如果触发flush的操作,假设初始刷盘到sequenceid为10,那么hbase会在10的基础上append一个空的Entry到HLog,最新的sequenceid为11,然后将sequenceid为11的号赋给oldestUnflushedSequenceId,并将oldestUnflushedSequenceId的值刷到Hfile文件中进行持久化。
  • Hlog文件对应所有Region的store中最大的sequenceid如果已经刷盘,就认为Hlog文件已经过期,就会移动到.oldlogs,等待被移除。
  • 当RegionServer出现故障的时候,需要对Hlog进行回放来恢复数据。回放的时候会读取Hfile的oldestUnflushedSequenceId中的sequenceid和Hlog中的sequenceid进行比较,小于sequenceid的就直接忽略,但与或者等于的就进行重做。回放完成后,就完成了数据的恢复工作。

4.3、Hlog的生命周期

Hlog从产生到最后删除需要经历如下几个过程:

  • 产生
    所有涉及到数据的变更都会先写Hlog,除非是你关闭了Hlog

  • 滚动
    Hlog的大小通过参数hbase.regionserver.logroll.period控制,默认是1个小时,时间达到hbase.regionserver.logroll.period 设置的时间,Hbase会创建一个新的Hlog文件。这就实现了Hlog滚动的目的。Hbase通过hbase.regionserver.maxlogs参数控制Hlog的个数。滚动的目的,为了控制单个Hlog文件过大的情况,方便后续的过期和删除。

  • 过期
    前面我们有讲到sequenceid这个东东,Hlog的过期依赖于对sequenceid的判断。Hbase会将Hlog的sequenceid和Hfile最大的sequenceid(刷新到的最新位置)进行比较,如果该Hlog文件中的sequenceid比刷新的最新位置的sequenceid都要小,那么这个Hlog就过期了,过期了以后,对应Hlog会被移动到.oldlogs目录。
    这里有个问题,为什么要将过期的Hlog移动到.oldlogs目录,而不是直接删除呢?
    答案是因为Hbase还有一个主从同步的功能,这个依赖Hlog来同步Hbase的变更,有一种情况不能删除Hlog,那就是Hlog虽然过期,但是对应的Hlog并没有同步完成,因此比较好的做好是移动到别的目录。再增加对应的检查和保留时间。

  • 删除
    如果Hbase开启了replication,当replication执行完一个Hlog的时候,会删除Zoopkeeper上的对应Hlog节点。在Hlog被移动到.oldlogs目录后,Hbase每隔hbase.master.cleaner.interval(默认60秒)时间会去检查.oldlogs目录下的所有Hlog,确认对应的Zookeeper的Hlog节点是否被删除,如果Zookeeper 上不存在对应的Hlog节点,那么就直接删除对应的Hlog。
    hbase.master.logcleaner.ttl(默认10分钟)这个参数设置Hlog在.oldlogs目录保留的最长时间。

四、Hbase主键设计

HBase是三维有序存储的,通过rowkey(行键),column keycolumn familyqualifier)和TimeStamp(时间戳)这个三个维度可以对HBase中的数据进行快速定位。

HBaserowkey可以唯一标识一行记录,在HBase查询的时候,有以下几种方式:

1>通过get方式,指定rowkey获取唯一一条记录

2>通过scan方式,设置startRowstopRow参数进行范围匹配

3>全表扫描,即直接扫描整张表中所有行记录 

rowkey长度原则

rowkey是一个二进制的,可以是任意字符串,最大长度 64kb ,实际应用中一般为10-100bytes,以byte[] 形式保存,一般设计成定长。 

建议越短越好,不要超过16个字节,原因如下:

1>数据的持久化文件HFile中是按照KeyValue存储的,如果rowkey过长,比如超过100字节,1000w行数据,光rowkey就要占用100*1000w=10亿个字节,将近1G数据,这样会极大影响HFile的存储效率;

2>MemStore将缓存部分数据到内存,如果rowkey字段过长,内存的有效利用率就会降低,系统不能缓存更多的数据,这样会降低检索效率。

3>目前操作系统都是64位系统,内存8字节对齐,控制在16个字节,8字节的整数倍利用了操作系统的最佳特性。

rowkey散列原则

如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率。

rowkey唯一原则

必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。

什么是热点 

HBase中的行是按照rowkey的字典顺序排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存取在临近位置,便于scan。然而糟糕的rowkey设计是热点的源头。 热点发生在大量的client直接访问集群的一个或极少数个节点(访问可能是读,写或者其他操作)。大量访问会使热点region所在的单个机器超出自身承受能力,引起性能下降甚至region不可用,这也会影响同一个RegionServer上的其他region,由于主机无法服务其他region的请求。 设计良好的数据访问模式以使集群被充分,均衡的利用。

为了避免写热点,设计rowkey使得不同行在同一个region,但是在更多数据情况下,数据应该被写入集群的多个region,而不是一个。

一些常见的避免热点的方法以及它们的优缺点:

加盐 

这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。

哈希 

哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据

反转

第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。

反转rowkey的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题

其他一些建议

  • 尽量减少行和列的大小在HBase中,value永远和它的key一起传输的。当具体的值在系统间传输时,它的rowkey,列名,时间戳也会一起传输。如果你的rowkey和列名很大,甚至可以和具体的值相比较,那么你将会遇到一些有趣的问题。HBase storefiles中的索引(有助于随机访问)最终占据了HBase分配的大量内存,因为具体的值和它的key很大。可以增加block大小使得storefiles索引再更大的时间间隔增加,或者修改表的模式以减小rowkey和列名的大小。压缩也有助于更大的索引。

  • 列族尽可能越短越好,最好是一个字符

  • 冗长的属性名虽然可读性好,但是更短的属性名存储在HBase中会更好


五、预分区

背景:HBase默认建表时有一个region,这个region的rowkey是没有边界的,即没有startkey和endkey,在数据写入时,所有数据都会写入这个默认的region,随着数据量的不断  增加,此region已经不能承受不断增长的数据量,会进行split,分成2个region。在此过程中,会产生两个问题:1.数据往一个region上写,会有写热点问题。2.region split会消耗宝贵的集群I/O资源。基于此我们可以控制在建表的时候,创建多个空region,并确定每个region的起始和终止rowky,这样只要我们的rowkey设计能均匀的命中各个region,就不会存在写热点问题。自然split的几率也会大大降低。当然随着数据量的不断增长,该split的还是要进行split。像这样预先创建hbase表分区的方式,称之为预分区,下面给出一种预分区的实现方式:
首先看没有进行预分区的表,startkey和endkey为空。

要进行预分区,首先要明确rowkey的取值范围或构成逻辑,以我的rowkey组成为例:两位随机数+时间戳+客户号,两位随机数的范围从00-99,于是我划分了10个region来存储数据,每个region对应的rowkey范围如下:
-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80,80-90,90-
在使用HBase API建表的时候,需要产生splitkeys二维数组,这个数组存储的rowkey的边界值。下面是java 代码实现:

private   byte [][] getSplitKeys() {  
  1.         String[] keys = new String[] { "10|""20|""30|""40|""50|", "60|""70|""80|""90|" };  
  2.         byte[][] splitKeys = new byte[keys.length][];  
  3.         TreeSet<byte[]> rows = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);//升序排序  
  4.         for (int i = 0; i < keys.length; i++) {  
  5.             rows.add(Bytes.toBytes(keys[i]));  
  6.         }  
  7.         Iterator<byte[]> rowKeyIter = rows.iterator();  
  8.         int i=0;  
  9.         while (rowKeyIter.hasNext()) {  
  10.             byte[] tempRow = rowKeyIter.next();  
  11.             rowKeyIter.remove();  
  12.             splitKeys[i] = tempRow;  
  13.             i++;  
  14.         }  
  15.         return splitKeys;  
  16. }

需要注意的是,在上面的代码中用treeset对rowkey进行排序,必须要对rowkey排序,否则在调用admin.createTable(tableDescriptor,splitKeys)的时候会出错。创建表的代码如下:

     /**  
  1.      * 创建预分区hbase表 
  2.      * @param tableName 表名 
  3.      * @param columnFamily 列簇 
  4.      * @return 
  5.      */  
  6.     @SuppressWarnings("resource")  
  7.     public boolean createTableBySplitKeys(String tableName, List<String> columnFamily) {  
  8.         try {  
  9.             if (StringUtils.isBlank(tableName) || columnFamily == null  || columnFamily.size() < 0) {  
  10.                 log.error("Parameters tableName|columnFamily should not be null,Please check!");  
  11.             }  
  12.             HBaseAdmin admin = new HBaseAdmin(conf);  
  13.             if (admin.tableExists(tableName)) {  
  14.                 return true;  
  15.             } else {  
  16.                 HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));  
  17.                 for (String cf : columnFamily) {  
  18.                     tableDescriptor.addFamily(new HColumnDescriptor(cf));  
  19.                 }  
  20.                 byte[][] splitKeys = getSplitKeys();  
  21.                 admin.createTable(tableDescriptor,splitKeys);//指定splitkeys  
  22.                 log.info("Create Table " + tableName "Success!columnFamily:" + columnFamily.toString());  
  23.             }  
  24.         } catch (MasterNotRunningException e) {    
  25.             log.error(e);  
  26.             return false;  
  27.         } catch (ZooKeeperConnectionException e) {   
  28.             log.error(e);  
  29.             return false;  
  30.         } catch (IOException e) {   
  31.             log.error(e);  
  32.             return false;  
  33.         }  
  34.         return true;  
  35.     }

在hbase shell中输入命令san 'hbase:meta'查看建表结果:

从上图可看出10个region均匀的分布在了3台regionserver上(集群就3台机器regionserver),达到预期效果。还可以在hbase的web UI界面中更加直观的查看建表的预分区信息。

再看看写数据是否均匀的命中各个region,是否能够做到对写请求的负载均衡

  1. public static void main(String[] args) throws Exception{  
  2.    HBaseAdmin admin = new HBaseAdmin(conf);  
  3.    HTable table = new HTable(conf, "testhbase");  
  4.    table.put(batchPut());  
  5. }  
  6.   
  7. private static String getRandomNumber(){  
  8.         String ranStr = Math.random()+"";  
  9.         int pointIndex = ranStr.indexOf(".");  
  10.         return ranStr.substring(pointIndex+1, pointIndex+3);  
  11.     }  
  12.       
  13.     private static List<Put> batchPut(){  
  14.         List<Put> list = new ArrayList<Put>();  
  15.         for(int i=1;i<=10000;i++){  
  16.             byte[] rowkey = Bytes.toBytes(getRandomNumber()+"-"+System.currentTimeMillis()+"-"+i);  
  17.             Put put = new Put(rowkey);  
  18.             put.add(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("zs"+i));  
  19.             list.add(put);  
  20.         }  
  21.         return list;  
  22.     }  
  23. }

六、Hbase Java API

一、几个主要 Hbase API 类和数据模型之间的对应关系:

1、 HBaseAdmin
关系: org.apache.hadoop.hbase.client.HBaseAdmin
作用:提供了一个接口来管理 HBase 数据库的表信息。它提供的方法包括:创建表,删 除表,列出表项,使表有效或无效,以及添加或删除表列族成员等。

2、 HBaseConfiguration
关系: org.apache.hadoop.hbase.HBaseConfiguration
作用:对 HBase 进行配置

3、 HTableDescriptor
关系: org.apache.hadoop.hbase.HTableDescriptor
作用:包含了表的名字极其对应表的列族

4、 HColumnDescriptor
关系: org.apache.hadoop.hbase.HColumnDescriptor
作用:维护着关于列族的信息,例如版本号,压缩设置等。它通常在创建表或者为表添 加列族的时候使用。列族被创建后不能直接修改,只能通过删除然后重新创建的方式。
列族被删除的时候,列族里面的数据也会同时被删除。

5、 HTable
关系: org.apache.hadoop.hbase.client.HTable
作用:可以用来和 HBase 表直接通信。此方法对于更新操作来说是非线程安全的。

6、 Put
关系: org.apache.hadoop.hbase.client.Put
作用:用来对单个行执行添加操作

7、 Get
关系: org.apache.hadoop.hbase.client.Get
作用:用来获取单个行的相关信息

8、 Result
关系: org.apache.hadoop.hbase.client.Result
作用:存储 Get 或者 Scan 操作后获取表的单行值。使用此类提供的方法可以直接获取值 或者各种 Map 结构( key-value 对)

 二、具体增删改查    代码具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
package  HbaseDome;
 
 
 
import  java.util.List;
 
import  org.apache.hadoop.conf.Configuration;
import  org.apache.hadoop.hbase.Cell;
import  org.apache.hadoop.hbase.HBaseConfiguration;
import  org.apache.hadoop.hbase.HColumnDescriptor;
import  org.apache.hadoop.hbase.HTableDescriptor;
import  org.apache.hadoop.hbase.KeyValue;
import  org.apache.hadoop.hbase.TableName;
import  org.apache.hadoop.hbase.client.Delete;
import  org.apache.hadoop.hbase.client.Get;
import  org.apache.hadoop.hbase.client.HBaseAdmin;
import  org.apache.hadoop.hbase.client.HTable;
import  org.apache.hadoop.hbase.client.Put;
import  org.apache.hadoop.hbase.client.Result;
import  org.apache.hadoop.hbase.client.ResultScanner;
import  org.apache.hadoop.hbase.client.Scan;
import  org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.Table;
import  org.apache.hadoop.hbase.util.Bytes;
 
 
 
public  class  Hbasedome  implements  HBaseDemoInterface{
 
     
     static  Configuration conf = null ;
     private  static  final  String ZKconnect= "192.168.123.212:2181,192.168.123.213:2181,192.168.123.214:2181" ;
     static {
         conf=HBaseConfiguration.create();
         conf.set( "hbase.zookeeper.quorum" , ZKconnect);
     }
//  static String tableName="student";
//  static String[] family={"lie01","lie02"};
     
     
     public  static  void  main(String[] args) {
         Hbasedome a = new  Hbasedome();
          String tableName= "student11" ;
          String[] family={ "lie01" , "lie02" };
         try  {
             HTableDescriptor htds = new  HTableDescriptor(tableName);
             for ( int  z= 0 ;z<family.length;z++){
                 HColumnDescriptor h= new  HColumnDescriptor(family[z]);
                 htds.addFamily(h);
             }
//          a.descTable("table03");
//          a.createTable(tableName, htds);
//          a.descTable("table03");
//          a.getAllTables();
//          a.createTable(tableName,family);
//          a.getResult("table03", "usr001");
//          a.dropTable("user1");
//          a.getAllTables();
//          a.putData("table03", "usr005", "liezu01", "name", "liu");
//          a.getResult("table03", "usr001");
//          a.getResultScann("table03");
//          a.getResultScann("table03","");
             
             Result result = a.getResult( "table03" "usr001" );
             System.out.println(result.toString());
             List<Cell> cells = result.listCells();
             for  ( int  i =  0 ; i < cells.size(); i++) {
                 Cell cell = cells.get(i);
                 System.out.println(cell.toString());
     //          printCell(cell);
             }
         
//          List<KeyValue> list = result.list();
//          for (int i = 0; i < list.size(); i++) {
//              KeyValue kv = list.get(i);
//              printKeyValye(kv);
//          }
         catch  (Exception e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
 
         
     }
     public  static  void  printKeyValye(KeyValue kv) {
         System.out.println(Bytes.toString(kv.getRow()) +  "\t"  + Bytes.toString(kv.getFamily()) +  "\t"  + Bytes.toString(kv.getQualifier()) +  "\t"  + Bytes.toString(kv.getValue()) +  "\t"  + kv.getTimestamp());
     }
     public  static  void  printCell(Cell cell) {
         System.out.println(Bytes.toString(cell.getRow()) +  "\t"  + Bytes.toString(cell.getFamily()) +  "\t"  + Bytes.toString(cell.getQualifier()) +  "\t"  + Bytes.toString(cell.getValue()) +  "\t"  + cell.getTimestamp());
     }
     //创建表
     @Override
     public  void  createTable(String tableName, String[] family)  throws  Exception {
         HBaseAdmin admin= new  HBaseAdmin(conf);
         HTableDescriptor desc = new  HTableDescriptor(tableName);
         
         for ( int  i= 0 ;i<family.length;i++){
             desc.addFamily( new  HColumnDescriptor(family[i]));
             System.out.println( "11111111111" +family[i]);
         }
         if (admin.tableExists(tableName)){
             System.out.println( "表已经存在,别瞎输行吗" );
//          System.exit(0);
         } else {
             admin.createTable(desc);
             System.out.println( "表创建成功" );
         }
     }
 
     //创建表
     @Override
     public  void  createTable(String tableName, HTableDescriptor htds)  throws  Exception {
         HBaseAdmin admin= new  HBaseAdmin(conf);
         boolean  tableExists1 = admin.tableExists(Bytes.toBytes(tableName));
         System.out.println(tableExists1 ?  "表已存在"  "表不存在" );
         admin.createTable(htds);
         boolean  tableExists = admin.tableExists(Bytes.toBytes(tableName));
         System.out.println(tableExists ?  "创建表成功"  "创建失败" );
     }
 
     
     @Override
     public  void  descTable(String tableName)  throws  Exception {
         HBaseAdmin admin= new  HBaseAdmin(conf);
         HTable table= new  HTable(conf, tableName);
         HTableDescriptor desc =table.getTableDescriptor();
         HColumnDescriptor[] columnFamilies = desc.getColumnFamilies();
     
         for (HColumnDescriptor t:columnFamilies){
             System.out.println(Bytes.toString(t.getName()));
         }
         
     }
 
     这种方式是替换该表tableName的所有列簇
     @Override
     public  void  modifyTable(String tableName)  throws  Exception {
         HBaseAdmin admin= new  HBaseAdmin(conf);
         HTableDescriptor htd =  new  HTableDescriptor(TableName.valueOf(tableName));
         htd.addFamily( new  HColumnDescriptor(Bytes.toBytes( "cf3" )));
         htd.addFamily( new  HColumnDescriptor(Bytes.toBytes( "cf2" )));
         admin.modifyTable(tableName, htd);
 
         // 删除该表tableName当中的特定的列簇
         // admin.deleteColumn(tableName, "cf3");
 
         System.out.println( "修改成功" );
         
     }
 
     @Override
     public  void  getAllTables()  throws  Exception {
         HBaseAdmin admin = new  HBaseAdmin(conf);
         
         String[] tableNames = admin.getTableNames();
         for ( int  i= 0 ;i<tableNames.length;i++){
             System.out.println(tableNames[i]);
         }
     }
 
     //更新数据  插入数据
     @Override
     public  void  putData(String tableName, String rowKey, String familyName, String columnName, String value)
             throws  Exception {
         HTable htable= new  HTable(conf, Bytes.toBytes(tableName));
         Put put= new  Put(Bytes.toBytes(rowKey));
         put.add(Bytes.toBytes(familyName), Bytes.toBytes(columnName), Bytes.toBytes(value));
         htable.put(put);
         
     }
 
     //为表添加数据
     @Override
     public  void  addData(String tableName, String rowKey, String[] column1, String[] value1, String[] column2,
             String[] value2)  throws  Exception {
         
         Put put= new  Put(Bytes.toBytes(rowKey));
         HTable htable= new  HTable(conf, Bytes.toBytes(tableName));
         HColumnDescriptor[] columnFamilies = htable.getTableDescriptor().getColumnFamilies();
         for ( int  i= 0 ;i<=columnFamilies.length;i++){
             String nameAsString = columnFamilies[i].getNameAsString();
             if (nameAsString.equals( "lie01" )){
                 for ( int  j= 0 ;j<column1.length;j++){
                     put.add(Bytes.toBytes(nameAsString), Bytes.toBytes(column1[j]),Bytes.toBytes(value1[j]));
                 }
             }
             if (nameAsString.equals( "lie02" )){
                 for ( int  j= 0 ;j<column2.length;j++){
                     put.add(Bytes.toBytes(nameAsString), Bytes.toBytes(column2[j]),Bytes.toBytes(value2[j]));
                 }
             }
             
         }
         htable.put(put);
         System.out.println( "addData ok!" );
     }
 
     //根据rowkey 查询
     @Override
     public  Result getResult(String tableName, String rowKey)  throws  Exception {
         Get get= new  Get(Bytes.toBytes(rowKey));
         HTable htable= new  HTable(conf, Bytes.toBytes(tableName));
         Result result=htable.get(get);
//      for(KeyValue k:result.list()){
//          System.out.println(Bytes.toString(k.getFamily()));
//          System.out.println(Bytes.toString(k.getQualifier()));
//          System.out.println(Bytes.toString(k.getValue()));
//          System.out.println(k.getTimestamp());
//      }
         return  result;
     }
 
     //查询指定的某列
     @Override
     public  Result getResult(String tableName, String rowKey, String familyName, String columnName)  throws  Exception {
         Get get= new  Get(Bytes.toBytes(rowKey));
         HTable htable= new  HTable(conf, Bytes.toBytes(tableName));
         get.addColumn(Bytes.toBytes(familyName),Bytes.toBytes(columnName));
         Result result=htable.get(get);
         for (KeyValue k:result.list()){
             System.out.println(Bytes.toString(k.getFamily()));
             System.out.println(Bytes.toString(k.getQualifier()));
             System.out.println(Bytes.toString(k.getValue()));
             System.out.println(k.getTimestamp());
         }
         return  result;
     }
 
     
     //遍历查询表
     @Override
     public  ResultScanner getResultScann(String tableName)  throws  Exception {
     
         Scan scan= new  Scan();
         ResultScanner rs = null ;
         HTable htable= new  HTable(conf, tableName);
         try {
             rs=htable.getScanner(scan);
             for (Result r: rs){
                 for (KeyValue kv:r.list()){
     
                     System.out.println(Bytes.toString(kv.getRow()));
                     System.out.println(Bytes.toString(kv.getFamily()));
                     System.out.println(Bytes.toString(kv.getQualifier()));
                     System.out.println(Bytes.toString(kv.getValue()));
                     System.out.println(kv.getTimestamp());
                 }
             }
         } finally {
             rs.close();
         }
         return  rs;
     }
 
     @Override
     public  ResultScanner getResultScann(String tableName, Scan scan)  throws  Exception {
         
         ResultScanner rs = null ;
         HTable htable= new  HTable(conf, tableName);
         try {
             rs=htable.getScanner(scan);
             for (Result r: rs){
                 for (KeyValue kv:r.list()){
     
                     System.out.println(Bytes.toString(kv.getRow()));
                     System.out.println(Bytes.toString(kv.getFamily()));
                     System.out.println(Bytes.toString(kv.getQualifier()));
                     System.out.println(Bytes.toString(kv.getValue()));
                     System.out.println(kv.getTimestamp());
                 }
             }
         } finally {
             rs.close();
         }       
         return  rs;
     }
 
     //查询表中的某一列
     @Override
     public  Result getResultByColumn(String tableName, String rowKey, String familyName, String columnName)
             throws  Exception {
         
         
         HTable htable= new  HTable(conf, tableName);
         Get get= new  Get(Bytes.toBytes(rowKey));
         get.addColumn(Bytes.toBytes(familyName),Bytes.toBytes(columnName));
         Result result=htable.get(get);
         for (KeyValue kv: result.list()){
 
             System.out.println(Bytes.toString(kv.getFamily()));
             System.out.println(Bytes.toString(kv.getQualifier()));
             System.out.println(Bytes.toString(kv.getValue()));
             System.out.println(kv.getTimestamp());
             
         }
         return  result;
     }
 
     
     //查询某列数据的某个版本
     @Override
     public  Result getResultByVersion(String tableName, String rowKey, String familyName, String columnName,
             int  versions)  throws  Exception {
     
         HTable htable= new  HTable(conf, tableName);
         Get get = new  Get(Bytes.toBytes(rowKey));
         get.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
         get.setMaxVersions(versions);
         Result result=htable.get(get);
         
         for (KeyValue kv: result.list()){
 
             System.out.println(Bytes.toString(kv.getFamily()));
             System.out.println(Bytes.toString(kv.getQualifier()));
             System.out.println(Bytes.toString(kv.getValue()));
             System.out.println(kv.getTimestamp());
             
         }
 
         return  result;
     }
 
     //删除指定某列
     @Override
     public  void  deleteColumn(String tableName, String rowKey, String falilyName, String columnName)  throws  Exception {
 
         HTable htable= new  HTable(conf, tableName);
//      Delete delete1=new Delete(Bytes.toBytes(rowKey));
         Delete de = new  Delete(Bytes.toBytes(rowKey));
         de.deleteColumn(Bytes.toBytes(falilyName), Bytes.toBytes(columnName));
         htable.delete(de);
     }
 
     
     //删除指定的某个rowkey
     @Override
     public  void  deleteColumn(String tableName, String rowKey)  throws  Exception {
         HTable htable= new  HTable(conf, tableName);
 
         Delete de = new  Delete(Bytes.toBytes(rowKey));
          htable.delete(de);
         
     }
 
     //让该表失效
     @Override
     public  void  disableTable(String tableName)  throws  Exception {
         HBaseAdmin admin= new  HBaseAdmin(conf);
         admin.disableTable(tableName);
         
     }
 
     //删除表
     @Override
     public  void  dropTable(String tableName)  throws  Exception {
         
         HBaseAdmin admin= new  HBaseAdmin(conf);
         admin.disableTable(tableName);
         admin.deleteTable(tableName);
         
     }
 
}

  

  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
package  com.ghgj.hbase.test1610;
 
import  java.io.IOException;
import  java.util.ArrayList;
import  java.util.Iterator;
import  java.util.List;
 
import  org.apache.hadoop.conf.Configuration;
import  org.apache.hadoop.hbase.Cell;
import  org.apache.hadoop.hbase.HBaseConfiguration;
import  org.apache.hadoop.hbase.HColumnDescriptor;
import  org.apache.hadoop.hbase.HTableDescriptor;
import  org.apache.hadoop.hbase.KeyValue;
import  org.apache.hadoop.hbase.TableName;
import  org.apache.hadoop.hbase.client.Get;
import  org.apache.hadoop.hbase.client.HBaseAdmin;
import  org.apache.hadoop.hbase.client.HTable;
import  org.apache.hadoop.hbase.client.Put;
import  org.apache.hadoop.hbase.client.Result;
import  org.apache.hadoop.hbase.client.ResultScanner;
import  org.apache.hadoop.hbase.client.Scan;
import  org.apache.hadoop.hbase.util.Bytes;
 
public  class  HBaseAPIDemo1610  implements  HBaseDemoInterface {
 
     private  static  final  String ROWKEY =  "p001" ;
     private  static  final  String ROWKEY2 =  "p002" ;
     private  static  final  String FAMILY1 =  "cf1" ;
     private  static  final  String FAMILY2 =  "cf2" ;
     private  static  final  String KEY =  "name" ;
     private  static  final  String VALUE =  "huangbo" ;
 
     private  static  final  String TABLE_NAME =  "person" ;
     private  static  final  String[] COLUMN_FAMILY =  new  String[] { FAMILY1, FAMILY2 };
 
     static  Configuration conf =  null ;
     static  HBaseAdmin admin =  null ;
     static  HTable table =  null ;
 
     static  {
         try  {
             conf = HBaseConfiguration.create();
             conf.set( "hbase.zookeeper.quorum" "hadoop03:2181,hadoop04:2181,hadoop05:2181" );
             admin =  new  HBaseAdmin(conf);
             table =  new  HTable(conf, TABLE_NAME);
 
         catch  (IOException e) {
             // e.printStackTrace();
             System.out.println( "报错" );
         }
     }
 
     public  static  void  main(String[] args)  throws  Exception {
         HBaseAPIDemo1610 hbase =  new  HBaseAPIDemo1610();
 
         // 测试创建表
         hbase.createTable(TABLE_NAME, COLUMN_FAMILY);
 
         // 测试创建表
         HTableDescriptor htd =  new  HTableDescriptor(TableName.valueOf(TABLE_NAME));
         for  ( int  i =  0 ; i < COLUMN_FAMILY.length; i++) {
             HColumnDescriptor cf1 =  new  HColumnDescriptor(COLUMN_FAMILY[i]);
             htd.addFamily(cf1);
         }
         hbase.createTable(TABLE_NAME, htd);
 
         // 查看表属性
         hbase.descTable(TABLE_NAME);
 
         // 查询所有的表
         hbase.getAllTables();
 
         // 测试修改表
         hbase.modifyTable(TABLE_NAME);
 
         // 插入数据
         hbase.putData(TABLE_NAME, ROWKEY, FAMILY1, KEY, VALUE);
 
         // 测试插入一堆数据
         String[] column1 =  new  String[] {  "name1" "age" "province"  };
         String[] value1 =  new  String[] {  "huangbo" "33" "xinjiang"  };
         String[] column2 =  new  String[] {  "gender"  };
         String[] value2 =  new  String[] {  "male"  };
         hbase.addData(TABLE_NAME, ROWKEY2, column1, value1, column2, value2);
 
         // 通过rowkey查询数据
         Result result = hbase.getResult(TABLE_NAME, ROWKEY2);
         System.out.println(result.toString());
         List<KeyValue> list = result.list();
         for  ( int  i =  0 ; i < list.size(); i++) {
             KeyValue kv = list.get(i);
             printKeyValye(kv);
         }
 
         // 通过rowkey, family, province查询数据
         Result result1 = hbase.getResult(TABLE_NAME, ROWKEY2, FAMILY1,  "province" );
         List<Cell> cells = result1.listCells();
         for  ( int  i =  0 ; i < cells.size(); i++) {
             Cell cell = cells.get(i);
             printCell(cell);
         }
 
         // 扫描全表数据
         ResultScanner resultScann = hbase.getResultScann(TABLE_NAME);
         printResultScanner(resultScann);
         
         /*Iterator<Result> iterator = resultScann.iterator();
         while(iterator.hasNext()){
             Result next = iterator.next();
         }*/
 
         // 通过scan扫描全表数据,scan中可以加入一些过滤条件
         Scan scan =  new  Scan();
         scan.setStartRow(Bytes.toBytes( "user" ));
         scan.setStopRow(Bytes.toBytes( "zk002" ));
         scan.setTimeRange(1488252774189l, 1488252774191l);
         ResultScanner resultScann1 = hbase.getResultScann(TABLE_NAME, scan);
         printResultScanner(resultScann1);
 
         // 两种方式查询最大版本数的hbase数据
         Result resultByVersion = hbase.getResultByVersion(TABLE_NAME, ROWKEY, FAMILY1,  "name" 3 );
         printResult(resultByVersion);
         System.out.println( "-------------------" );
         ResultScanner rs = hbase.getResultByVersion(ROWKEY, FAMILY1,  "name" 3 );
         printResultScanner(rs);
 
         // 删除表
         hbase.dropTable(TABLE_NAME);
     }
 
     public  static  void  printResultScanner(ResultScanner resultScann) {
         for  (Result result : resultScann) {
             printResult(result);
         }
     }
 
     public  static  void  printResult(Result result) {
         List<Cell> cells = result.listCells();
         for  ( int  i =  0 ; i < cells.size(); i++) {
             Cell cell = cells.get(i);
             printCell(cell);
         }
     }
 
     public  static  void  printCell(Cell cell) {
         System.out.println(Bytes.toString(cell.getRow()) +  "\t"  + Bytes.toString(cell.getFamily()) +  "\t"  + Bytes.toString(cell.getQualifier()) +  "\t"  + Bytes.toString(cell.getValue()) +  "\t"  + cell.getTimestamp());
     }
 
     public  static  void  printKeyValye(KeyValue kv) {
         System.out.println(Bytes.toString(kv.getRow()) +  "\t"  + Bytes.toString(kv.getFamily()) +  "\t"  + Bytes.toString(kv.getQualifier()) +  "\t"  + Bytes.toString(kv.getValue()) +  "\t"  + kv.getTimestamp());
     }
 
     // create 'tablename','cf1','cf2'
     @Override
     public  void  createTable(String tableName, String[] family)  throws  Exception {
         HTableDescriptor htd =  new  HTableDescriptor(TableName.valueOf(tableName));
         for  ( int  i =  0 ; i < family.length; i++) {
             HColumnDescriptor cf1 =  new  HColumnDescriptor(family[i]);
             htd.addFamily(cf1);
         }
         admin.createTable(htd);
         boolean  tableExists = admin.tableExists(Bytes.toBytes(tableName));
         System.out.println(tableExists ?  "创建表成功"  "创建失败" );
     }
 
     @Override
     public  void  createTable(String tableName, HTableDescriptor htd)  throws  Exception {
         admin.createTable(htd);
         boolean  tableExists = admin.tableExists(Bytes.toBytes(tableName));
         System.out.println(tableExists ?  "创建表成功"  "创建失败" );
     }
 
     // desc 'person'
     @Override
     public  void  descTable(String tableName)  throws  Exception {
         HTableDescriptor tableDescriptor = table.getTableDescriptor();
         HColumnDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();
         for  (HColumnDescriptor hcd : columnFamilies) {
             // System.out.println(hcd.toString()+"\t");
             System.out.println(Bytes.toString(hcd.getName()));
         }
     }
 
     @Override
     public  void  modifyTable(String tableName)  throws  Exception {
         // 这种方式是替换该表tableName的所有列簇
         HTableDescriptor htd =  new  HTableDescriptor(TableName.valueOf(tableName));
         htd.addFamily( new  HColumnDescriptor(Bytes.toBytes( "cf3" )));
         htd.addFamily( new  HColumnDescriptor(Bytes.toBytes( "cf2" )));
         admin.modifyTable(tableName, htd);
 
         // 删除该表tableName当中的特定的列簇
         // admin.deleteColumn(tableName, "cf3");
 
         System.out.println( "修改成功" );
     }
 
     // list
     @Override
     public  void  getAllTables()  throws  Exception {
         TableName[] listTableNames = admin.listTableNames();
         for  (TableName tn : listTableNames) {
             System.out.println(tn.toString());
         }
     }
 
     // put 'tablename','rowkey','familyname:key','value'
     @Override
     public  void  putData(String tableName, String rowKey, String familyName, String columnName, String value)  throws  Exception {
         // HTable table = new HTable(conf, tableName);
         Put put =  new  Put(Bytes.toBytes(rowKey));
         put.add(Bytes.toBytes(familyName), Bytes.toBytes(columnName), Bytes.toBytes(value));
         table.put(put);
         System.out.println( "插入成功" );
     }
 
     /**
      * @param tableName
      *            表名
      * @param rowKey
      *            rowkey
      * @param column1
      *            第一个列簇的key数组
      * @param value1
      *            第一个列簇的value数组,key数组和value数组长度必须一样
      * @param column2
      *            第二列簇的key数组
      * @param value2
      *            第二个列簇的values数组, 同上同理
      * @throws Exception
      */
     @Override
     public  void  addData(String tableName, String rowKey, String[] column1, String[] value1, String[] column2, String[] value2)  throws  Exception {
         List<Put> puts =  new  ArrayList<Put>();
 
         for  ( int  i =  0 ; i < column1.length; i++) {
             Put put =  new  Put(Bytes.toBytes(rowKey));
             put.add(Bytes.toBytes(FAMILY1), Bytes.toBytes(column1[i]), Bytes.toBytes(value1[i]));
             puts.add(put);
         }
 
         for  ( int  i =  0 ; i < column2.length; i++) {
             Put put =  new  Put(Bytes.toBytes(rowKey));
             put.add(Bytes.toBytes(FAMILY2), Bytes.toBytes(column2[i]), Bytes.toBytes(value2[i]));
             puts.add(put);
         }
 
         table.put(puts);
         System.out.println( "插入一堆数据成功" );
     }
 
     // get 'tablename','rowkey'
     @Override
     public  Result getResult(String tableName, String rowKey)  throws  Exception {
         Get get =  new  Get(Bytes.toBytes(rowKey));
         Result result = table.get(get);
         return  result;
     }
 
     @Override
     public  Result getResult(String tableName, String rowKey, String familyName, String columnName)  throws  Exception {
         Get get =  new  Get(Bytes.toBytes(rowKey));
         get.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
         Result result = table.get(get);
         return  result;
     }
 
     @Override
     public  ResultScanner getResultScann(String tableName)  throws  Exception {
         Scan scan =  new  Scan();
         ResultScanner scanner = table.getScanner(scan);
         // ResultScanner scanner = table.getScanner(Bytes.toBytes(FAMILY2));
         // ResultScanner scanner = table.getScanner(Bytes.toBytes(FAMILY1),
         // Bytes.toBytes("name1"));
         return  scanner;
     }
 
     @Override
     public  ResultScanner getResultScann(String tableName, Scan scan)  throws  Exception {
         return  table.getScanner(scan);
     }
 
     @Override
     public  Result getResultByColumn(String tableName, String rowKey, String familyName, String columnName)  throws  Exception {
         return  null ;
     }
 
     // get 'person','p001',{COLUMNS => 'cf1:name', VERSIONS => 3}
     @Override
     public  Result getResultByVersion(String tableName, String rowKey, String familyName, String columnName,  int  versions)  throws  Exception {
         Get get =  new  Get(Bytes.toBytes(rowKey));
         get.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
         get.setMaxVersions(versions);
         Result result = table.get(get);
         return  result;
     }
 
     public  ResultScanner getResultByVersion(String rowKey, String familyName, String columnName,  int  versions)  throws  Exception {
         Scan scan =  new  Scan(Bytes.toBytes(rowKey), Bytes.toBytes(rowKey));
         scan.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
         scan.setMaxVersions(versions);
         ResultScanner scanner = table.getScanner(scan);
         return  scanner;
     }
 
     @Override
     public  void  deleteColumn(String tableName, String rowKey, String falilyName, String columnName)  throws  Exception {
 
     }
 
     @Override
     public  void  deleteColumn(String tableName, String rowKey)  throws  Exception {
 
     }
 
     @Override
     public  void  disableTable(String tableName)  throws  Exception {
         admin.disableTable(tableName);
     }
 
     @Override
     public  void  dropTable(String tableName)  throws  Exception {
         try  {
             admin.deleteTable(tableName);
         catch  (Exception e) {
             // e.printStackTrace();
             disableTable(tableName);
             admin.deleteTable(tableName);
             System.out.println( "ssssssss" );
         finally  {
             boolean  tableExists = admin.tableExists(Bytes.toBytes(tableName));
             System.out.println(tableExists ?  "删除失败"  "删除成功" );
         }
     }
}

  • 10
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值