HBase基础 HBase简介 HBase的概念 HBase是⼀个分布式海量列式⾮关系型数据库系统,可以提供超⼤规模数据集的实时随机读写。
什么是列式存储?举个例子:
MySQL是行式存储,需要存储如下数据:
id
name
age
salary
1
小明
21
2
小红
12k
这样存储信息,空值字段会浪费存储空间
但如果是列式存储:
1 2 3 4 rowkey: 1 name: 小明 rowkey: 1 age: 21 rowkey: 2 name: 小红 rowkey: 2 salary: 12k
HBase的优点
海量存储: 底层基于HDFS存储海量数据
列式存储:HBase表的数据是基于列族进⾏存储的,⼀个列族包含若⼲列
极易扩展:底层依赖HDFS,当磁盘空间不⾜的时候,只需要动态增加DataNode服务节点就可以
⾼并发:⽀持⾼并发的读写请求
稀疏:稀疏主要是针对HBase列的灵活性,在列族中,你可以指定任意多的列,在列数据为空的情况下,是不会占⽤存储空间的
数据的多版本:HBase表中的数据可以有多个版本值,默认情况下是根据版本号去区分,版本号就是插⼊数据的时间戳
数据类型单⼀:所有的数据在HBase中是以字节数组进⾏存储
HBase数据模型 一些概念:
NameSpace ,命名空间,类似于关系型数据库的database概念,每个命名空间下有多个表。HBase两个⾃带的命名空间,分别是hbase和default,hbase中存放的是HBase内置的表,default表是⽤户默认使⽤的命名空间。⼀个表可以⾃由选择是否有命名空间,如果创建表的时候加上了命名空间后,这个表名字以:
作为区分
Table ,类似于关系型数据库的表概念。不同的是,HBase定义表时只需要声明列族即可,数据属性,⽐如超时时间(TTL),压缩算法(COMPRESSION)等,都在列族的定义中定义,不需要声明具体的列。
Row(一行逻辑数据) ,HBase表中的每⾏数据都由⼀个RowKey和多个Column(列)组成。⼀个⾏包含了多个列,这些列通过列族来分类,⾏中的数据所属列族只能从该表所定义的列族中选取,不能定义这个表中不存在的列族,否则报错NoSuchColumnFamilyException。
RowKey(每行数据主键) ,Rowkey由⽤户指定的⼀串不重复的字符串定义,是⼀⾏的唯⼀标识。数据是按照RowKey的字典顺序存储的,并且查询数据时只能根据RowKey进⾏检索,所以RowKey的设计⼗分重要。如果使⽤了之前已经定义的RowKey,那么会将之前的数据更新掉。
Column Family(列族) ,列族是多个列的集合。⼀个列族可以动态地灵活定义多个列。表的相关属性⼤部分都定义在列族上,同⼀个表⾥的不同列族可以有完全不同的属性配置,但是同⼀个列族内的所有列都会有相同的属性。列族存在的意义是HBase会把相同列族的列尽量放在同⼀台机器上,所以说,如果想让某⼏个列被放到⼀起,你就给他们定义相同的列族。
Column Qualifier(列) ,Hbase中的列是可以随意定义的,⼀个⾏中的列不限名字、不限数量,只限定列族。因此列必须依赖于列族存在!列的名称前必须带着其所属的列族!例如info:name,info:age
TimeStamp(时间戳=>版本) ,⽤于标识数据的不同版本(version)。时间戳默认由系统指定,也可以由⽤户显式指定。在读取单元格的数据时,版本号可以省略,如果不指定,Hbase默认会获取最后⼀个版本的数据返回!
Cell ,⼀个列中可以存储多个版本的数据。⽽每个版本就称为⼀个单元格(Cell)。
Region(表的分区) ,Region由⼀个表的若⼲⾏组成!在Region中⾏的排序按照⾏键(rowkey)字典排序。Region不能跨RegionSever,且当数据量⼤的时候, HBase会拆分Region。
HBase的逻辑架构:
HBase物理存储:
HBase整体架构
各组件的作用:
zookeeper
实现了HMaster的⾼可⽤
保存了HBase的元数据信息,是所有HBase表的寻址⼊⼝
对HMaster和HRegionServer实现了监控
HMaster(Master)
为HRegionServer分配Region
维护整个集群的负载均衡
维护集群的元数据信息
发现失效的Region,并将失效的Region分配到正常的HRegionServer上
HRegionServer(RegionServer)
负责管理Region
接受客户端的读写数据请求
切分在运⾏过程中变⼤的Region
Region
每个HRegion由多个Store构成
每个Store保存⼀个列族(Columns Family),表有⼏个列族,则有⼏个Store
每个Store由⼀个MemStore和多个StoreFile组成,MemStore是Store在内存中的内容,写到⽂件后就是StoreFile。StoreFile底层是以HFile的格式保存
HBase的安装部署 下载安装包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 tar -zxvf hbase-1.3.1-bin.tar.gz -C /opt/servers export HBASE_HOME=/opt/servers/hbase-1.3.1export PATH=$PATH :$HBASE_HOME /binln -s /opt/servers/hadoop-2.9.2/etc/hadoop/core-site.xml /opt/servers/hbase-1.3.1/conf/core-site.xmlln -s /opt/servers/hadoop-2.9.2/etc/hadoop/hdfs-site.xml /opt/servers/hbase-1.3.1/conf/hdfs-site.xmlexport JAVA_HOME=/opt/servers/jdk1.8.0_231export HBASE_MANAGES_ZK=FALSE
修改 hbase-site.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <configuration > <property > <name > hbase.rootdir</name > <value > hdfs://node1:9000/hbase</value > </property > <property > <name > hbase.cluster.distributed</name > <value > true</value > </property > <property > <name > hbase.zookeeper.quorum</name > <value > node1:2181,node2:2181,node3:2181</value > </property > </configuration >
修改regionservers⽂件
1 2 3 4 5 6 7 8 9 10 vim regionservers node1 node2 node3 vim backup-masters hadoop-node2
将hbase目录分发到其他节点
HBase集群的启动和停⽌:
前提条件:先启动hadoop和zk集群
启动HBase:start-hbase.sh
停⽌HBase:stop-hbase.sh
启动好HBase集群之后,可以访问地址:HMaster的主机名:16010,查看HBase集群的web管理界面
HBase shell的基本操作 进⼊Hbase客户端命令操作界⾯
查看帮助命令:
查看当前数据库中有哪些表
创建⼀张student表, 包含base_info、extra_info两个列族
1 2 3 4 hbase(main):004:0> create 'student' ,'base_info' ,'extra_info' 或者 create 'student' , {NAME => 'base_info' , VERSIONS => '3' },{NAME => 'extra_info' ,VERSIONS => '3' }
添加数据操作 1 2 3 4 5 6 7 8 hbase(main):006:0> put "student" , "rk1" , "base_info:name" , "wang" hbase(main):008:0> put 'student' , 'rk1' , 'base_info:age' , 30 hbase(main):010:0> put 'student' , 'rk1' , 'extra_info:address' , 'shanghai'
查询数据 通过rowkey进⾏查询
1 2 3 4 5 6 7 8 hbase(main):012:0> get 'student' , 'rk1' COLUMN CELL base_info:age timestamp=1622014015143, value=30 base_info:name timestamp=1622013932351, value=wang extra_info:address timestamp=1622014075602, value=shanghai 1 row(s) in 0.0270 seconds
查看rowkey下⾯的某个列族的信息
1 2 3 4 5 6 hbase(main):013:0> get 'student' , 'rk1' , 'base_info' COLUMN CELL base_info:age timestamp=1622014015143, value=30 base_info:name timestamp=1622013932351, value=wang 1 row(s) in 0.0080 seconds
查看rowkey指定列族指定字段的值
1 2 3 4 5 6 hbase(main):014:0> get 'student' , 'rk1' , 'base_info:name' , 'base_info:age' COLUMN CELL base_info:age timestamp=1622014015143, value=30 base_info:name timestamp=1622013932351, value=wang 1 row(s) in 0.0040 seconds
查看rowkey指定多个列族的信息
1 2 3 4 5 6 hbase(main):010:0> get 'student' , 'rk1' , 'base_info' , 'extra_info' 或者 hbase(main):011:0> get 'student' , 'rk1' , {COLUMN => ['base_info' , 'extra_info' ]} 或者 hbase(main):012:0> get 'student' , 'rk1' , {COLUMN => ['base_info:name' , 'extra_info:address' ]}
指定rowkey与列值查询
1 2 3 4 5 hbase(main):029:0> get 'student' , 'rk1' , {FILTER => "ValueFilter(=, 'binary:wang')" } COLUMN CELL base_info:name timestamp=1622013932351, value=wang 1 row(s) in 0.0030 second
指定rowkey与列值模糊查询
1 2 3 4 5 hbase(main):033:0> get 'student' , 'rk1' , {FILTER => "(QualifierFilter(=,'substring:d'))" } COLUMN CELL extra_info:address timestamp=1622014075602, value=shanghai 1 row(s) in 0.0030 second
查询所有数据
1 2 3 4 5 6 7 hbase(main):034:0> scan 'student' ROW COLUMN+CELL rk1 column=base_info:age, timestamp=1622014015143, value=30 rk1 column=base_info:name, timestamp=1622013932351, value=wang rk1 column=extra_info:address, timestamp=1622014075602, value=shangh ai 1 row(s) in 0.0190 seconds
列族查询
1 2 3 4 5 6 hbase(main):001:0> scan 'student' , {COLUMNS => 'base_info' } hbase(main):002:0> scan 'student' , {COLUMNS => 'base_info' , RAW => true , VERSIONS => 3}
指定多个列族与按照数据值模糊查询
1 2 3 4 5 6 7 hbase(main):039:0> scan 'student' , {COLUMNS => ['base_info' , 'extra_info' ], FILTER => "(QualifierFilter(=,'substring:a'))" } ROW COLUMN+CELL rk1 column=base_info:age, timestamp=1622014015143, value=30 rk1 column=base_info:name, timestamp=1622013932351, value=wang rk1 column=extra_info:address, timestamp=1622014075602, value=shanghai 1 row(s) in 0.0070 seconds
rowkey的范围值查询
1 2 3 4 5 6 hbase(main):043:0> scan 'student' , {COLUMNS => 'base_info' , STARTROW => 'rk1' , ENDROW => 'rk3' } ROW COLUMN+CELL rk1 column=base_info:age, timestamp=1622014015143, value=30 rk1 column=base_info:name, timestamp=1622013932351, value=wang 1 row(s) in 0.0040 seconds
指定rowkey模糊查询
1 2 3 4 5 6 7 8 hbase(main):045:0> scan 'student' ,{FILTER=>"PrefixFilter('rk')" } ROW COLUMN+CELL rk1 column=base_info:age, timestamp=1622014015143, value=30 rk1 column=base_info:name, timestamp=1622013932351, value=wang rk1 column=extra_info:address, timestamp=1622014075602, value=shangh ai 1 row(s) in 0.0070 seconds
更新数据 更新操作同插⼊操作⼀模⼀样,只不过有数据就更新,没数据就添加
把student表中rowkey为rk1的base_info列族下的列name修改为zhangsan
1 hbase(main):046:0> put 'student' , 'rk1' , 'base_info:name' , 'zhangsan'
删除数据和表 指定rowkey以及列名进⾏删除
1 2 hbase(main):048:0> delete 'student' , 'rk1' , 'base_info:name'
删除 base_info 列族
1 2 3 4 5 hbase(main):050:0> alter 'student' , 'delete' => 'base_info' Updating all regions with the new schema... 1/1 regions updated. Done. 0 row(s) in 2.1990 seconds
清空表数据
1 2 3 4 5 hbase(main):052:0> truncate 'student' Truncating 'student' table (it may take a while ): - Disabling table... - Truncating table... 0 row(s) in 3.3660 seconds
删除表
1 2 3 4 5 6 7 8 hbase(main):054:0> disable 'student' 0 row(s) in 2.2270 seconds hbase(main):055:0> drop 'student' 0 row(s) in 1.2350 seconds
HBase内部原理 HBase读数据流程
client⾸先访问zookeeper找到meta表的region位置,然后读取meta表中的数据,meta表中存储了⽤户表的region信息
根据要查询的namespace、表名和rowkey信息。找到写⼊数据对应的region信息
找到这个region对应的regionServer,然后发送请求
查找对应的region
先从MemStore查找数据,如果没有,再从BlockCache上读取
如果BlockCache中也没有找到,再到StoreFile上进⾏读取
从storeFile中读取到数据之后,不是直接把结果数据返回给客户端, ⽽是把数据先写⼊到BlockCache中,⽬的是为了加快后续的查询;然后在返回结果给客户端
HBase上Regionserver的内存分为两个部分:
⼀部分作为Memstore,主要⽤来写
另外⼀部分作为BlockCache,主要⽤于读数据
HBase写数据流程
client⾸先访问zookeeper找到meta表的region位置,然后读取meta表中的数据,meta表中存储了⽤户表的region信息
根据要查询的namespace、表名和rowkey信息。找到写⼊数据对应的region信息
找到这个region对应的regionServer,然后发送请求
把数据分别写到HLog(write ahead log)和memstore各⼀份
memstore达到阈值后把数据刷到磁盘,⽣成storeFile⽂件
删除HLog中的历史数据
HBase的flush机制 flush机制
当memstore的⼤⼩超过这个值的时候,会flush到磁盘,默认为128M
1 2 3 4 <property > <name > hbase.hregion.memstore.flush.size</name > <value > 134217728</value > </property >
当memstore中的数据时间超过1⼩时,会flush到磁
1 2 3 4 <property > <name > hbase.regionserver.optionalcacheflushinterval</name > <value > 3600000</value > </property >
HregionServer的全局memstore的⼤⼩,超过该⼤⼩会触发flush到磁盘的操作,默认是堆⼤⼩的 40% * 0.95
1 2 3 4 5 6 7 8 <property > <name > hbase.regionserver.global.memstore.size</name > <value > 0.4</value > </property > <property > <name > hbase.regionserver.global.memstore.size.lower.limit</name > <value > 0.95</value > </property >
阻塞机制 上面说的是Store中memstore数据刷写磁盘的标准,但是Hbase会进行周期性检查,看是否满⾜以上标准,满⾜就会进⾏刷写。
但是如果在下次检查到来之前,数据疯狂写⼊Memstore中,会触发阻塞机制,此时⽆法写⼊数据到Memstore,数据⽆法写⼊Hbase集群。
当memstore达到128M时,没有检查会继续往里写,刷写磁盘不会阻塞,但是数据量远远大于128M时,hbase为了保证集群的安全,会停止写入数据。这个停止写入数据的数据量大小默认是512M
1 2 3 memstore数据达到一定值的计算公式:hbase.hregion.memstore.flush.size * hbase.hregion.memstore..block.multiplier hbase.hregion.memstore.flush.size刷写的阀值,默认是134217728,即128MB hbase.hregion.memstore.block.multiplier是⼀个倍数,默认是4
regionserver全部的memstore达到规定值,这个规定值是可以配置的
1 2 3 4 5 hbase.regionserver.global.memstore.size.lower.limit是0.95, hbase.regionserver.global.memstore.size是0.4, 堆内存总共是 16G, 触发刷写的阈值是:16*0.95*0.4=6.08GB 触发阻塞的阈值是:16*0.4=6.4GB
hbase阻塞了是无法写入数据的,就无法使用了。缓解阻塞机制:可以尽可能的调大内存
Compact合并机制 在hbase中主要存在两种类型的compact合并
minor compact 小合并
在将Store中多个HFile(StoreFile)合并为⼀个HFile。这个过程中,删除和更新的数据仅仅只是做了标记,并没有物理移除,这种合并的触发频率很⾼。
minor compact⽂件选择标准 由以下⼏个参数共同决定:
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 <property > <name > hbase.hstore.compaction.min</name > <value > 3</value > </property > <property > <name > hbase.hstore.compaction.max</name > <value > 10</value > </property > <property > <name > hbase.hstore.compaction.min.size</name > <value > 134217728</value > </property > <property > <name > hbase.hstore.compaction.max.size</name > <value > 9223372036854775807</value > </property >
根据上面的配置来看,一次minor compact最少3个文件最多10个文件
触发minor compact的条件:
memstore flush ,在进⾏memstore flush前后都会进⾏判断是否触发compact
定期检查线程 ,周期性检查是否需要进⾏compaction操作,由参数:hbase.server.thread.wakefrequency决定,默认值是10000 millseconds
major compact 大合并 合并Store中所有的HFile为⼀个HFile
这个过程有删除标记的数据会被真正移除,同时超过单元格maxVersion的版本记录也会被删除。合并频率⽐较低,默认7天执⾏⼀次,并且性能消耗⾮常大,建议⽣产关闭(设置为0),在应⽤空闲时间⼿动触发。⼀般可以是⼿动控制进⾏合并,防⽌出现在业务⾼峰期
major compact触发时间条件:
1 2 3 4 5 <property > <name > hbase.hregion.majorcompaction</name > <value > 604800000</value > </property >
⼿动触发:
1 2 major_compact tableName
Region 拆分机制 Region中存储的是⼤量的rowkey数据,当Region中的数据条数过多的时候,直接影响查询效率。
当Region过⼤的时候,HBase会拆分Region,这也是Hbase的⼀个优点。
拆分策略 HBase的Region Split策略⼀共有以下⼏种:
ConstantSizeRegionSplitPolicy
这是0.94版本前默认切分策略。
当region大小大于某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,⼀个region等分为2个region。
但是在⽣产线上这种切分策略却有相当的弊端:切分策略对于大表和小表没有明显的区分。阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,这对业务来说并不是什么好事。如果设置较小则对小表友好,但⼀个大表就会在整个集群产生大量 的region,这对于集群的管理、资源使⽤、failover来说都不是⼀件好事。
IncreasingToUpperBoundRegionSplitPolicy
是0.94版本~2.0版本默认切分策略
1 2 3 4 5 6 7 8 9 10 11 切分策略稍微有点复杂,总体看和ConstantSizeRegionSplitPolicy思路相同,⼀个region⼤⼩⼤于设置阈值就会触发切分。但是这个阈值并不像ConstantSizeRegionSplitPolicy是⼀个固定的值,⽽是会在⼀定条件下不断调整,调整规则和region所属表在当前regionserver上的region个数有关系。 region split的计算公式是: regioncount^3 * 128M * 2,当region达到该size的时候进⾏split 例如: 第⼀次split:1^3 * 256 = 256MB 第⼆次split:2^3 * 256 = 2048MB 第三次split:3^3 * 256 = 6912MB 第四次split:4^3 * 256 = 16384MB > 10GB,因此取较⼩的值10GB 后⾯每次split的size都是10GB了
2.0版本默认切分策略
1 2 3 这种切分策略的切分阈值⼜发⽣了变化,相比 IncreasingToUpperBoundRegionSplitPolicy 简单了⼀些,依然和待分裂region所属表在当前regionserver上的region个数有关系,如果region个数等于1,切分阈值为flush size * 2,否则为MaxRegionFileSize。 这种切分策略对于⼤集群中的⼤表、⼩表会⽐ncreasingToUpperBoundRegionSplitPolicy 更加友好,⼩表不会再产⽣⼤量的⼩region,⽽是适可⽽⽌
KeyPrefixRegionSplitPolicy
根据rowKey的前缀对数据进行分组,这⾥是指定rowKey的前多少位作为前缀,⽐如rowKey都是16位的,指定前5位是前缀,那么前5位相同的rowKey在进行region split的时候会分到相同的region中。
DelimitedKeyPrefixRegionSplitPolicy
保证相同前缀的数据在同⼀个region中,例如rowKey的格式为:userideventtype_eventid,指定的delimiter为 ,则split的的时候会确保userid 相同的数据在同⼀个region中。
DisabledRegionSplitPolicy
不启用自动拆分,需要指定⼿动拆分。不建议!
RegionSplitPolicy的应用 Region拆分策略可以全局统⼀配置,也可以为单独的表指定拆分策略。
通过hbase-site.xml全局统⼀配置(对hbase所有表⽣效)
1 2 3 4 <property > <name > hbase.regionserver.region.split.policy</name > <value > org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value > </property >
通过Java API为单独的表指定Region拆分策略
1 2 3 4 HTableDescriptor tableDesc = new HTableDescriptor ("test1" );tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, IncreasingToUpperBoundRegionSplitPolicy.class.getName()); tableDesc.addFamily(new HColumnDescriptor (Bytes.toBytes("cf1" ))); admin.createTable(tableDesc);
通过HBase Shell为单个表指定Region拆分策略
1 hbase> create 'test2', {METADATA => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy'}},{NAME => 'cf1'}
HBase表的预分区(region) 当⼀个table刚被创建的时候,Hbase默认的分配⼀个region给table。也就是说这个时候,所有的读写请求都会访问到同⼀个regionServer的同⼀个region中,这个时候就达不到负载均衡的效果了,集群中的其他regionServer就可能会处于⽐较空闲的状态。解决这个问题可以⽤pre-splitting,在创建table的时候就配置好,⽣成多个region。
这样的好处:
增加数据读写效率
负载均衡,防⽌数据倾斜
⽅便集群容灾调度region
每⼀个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护
⼿动指定预分区:
1 create 'person','info1','info2',SPLITS => ['1000','2000','3000']
也可以把分区规则创建于⽂件中
1 2 3 4 5 6 vim split.txt aaa bbb ccc ddd
执行:create 'student','info',SPLITS_FILE => '/root/hbase/split.txt'
HBase表Region合并 Region的合并不是为了性能,⽽是出于维护的目的
通过Merge类冷合并Region
需要先关闭hbase集群
需求:需要把student表中的2个region数据进⾏合并:student, ,1593244870695.10c2df60e567e73523a633f20866b4b5和student,1000,1593244870695.0a4c3ff30a98f79ff6c1e4cc927b3d0d
这里通过org.apache.hadoop.hbase.util.Merge类来实现,不需要进⼊hbase shell,直接执⾏(需要先关闭hbase集群):
1 2 3 hbase org.apache.hadoop.hbase.util.Merge student \ student,,1595256696737.fc3eff4765709e66a8524d3c3ab42d59. \ student,aaa,1595256696737.1d53d6c1ce0c1bed269b16b6514131d0.
通过online_merge热合并Region 不需要关闭hbase集群,在线进行合并
1 2 3 4 5 6 7 8 与冷合并不同的是,online_merge的传参是Region的hash值,⽽Region的hash值就是Region名称的最后那段在两个.之间的字符串部分。 需求:需要把student表2个region数据进⾏合并: student,,1587392159085.9ca8689901008946793b8d5fa5898e06. \ student,aaa,1587392159085.601d5741608cedb677634f8f7257e000. 需要进⼊hbase shell: merge_region 'c8bc666507d9e45523aebaffa88ffdd6','02a9dfdf6ff42ae9f0524a3d8f4c7777'
HBase API应用和优化 Hbase 客户端API操作 添加依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <dependencies > <dependency > <groupId > org.apache.hbase</groupId > <artifactId > hbase-client</artifactId > <version > 1.3.1</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > compile</scope > </dependency > <dependency > <groupId > org.testng</groupId > <artifactId > testng</artifactId > <version > 6.14.3</version > <scope > test</scope > </dependency > </dependencies >
简单操作:
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 package org.javaboy.hbase.client;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.hbase.*;import org.apache.hadoop.hbase.client.*;import org.apache.hadoop.hbase.util.Bytes;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.IOException;public class HbaseClientDemo { Configuration conf = null ; Connection conn = null ; @Before public void init () throws IOException { conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum" , "192.168.33.111,192.168.33.112" ); conf.set("hbase.zookeeper.property.clientPort" , "2181" ); conn = ConnectionFactory.createConnection(conf); } @Test public void createTable () throws IOException { HBaseAdmin admin = (HBaseAdmin) conn.getAdmin(); HTableDescriptor student = new HTableDescriptor (TableName.valueOf("student" )); student.addFamily(new HColumnDescriptor ("info" )); admin.createTable(student); System.out.println("student表创建成功" ); } @Test public void putData () throws IOException { Table student = conn.getTable(TableName.valueOf("student" )); Put put = new Put (Bytes.toBytes("110" )); put.addColumn(Bytes.toBytes("info" ), Bytes.toBytes("addr" ), Bytes.toBytes("beijing" )); student.put(put); student.close(); System.out.println("插入数据到student表成功" ); } @Test public void deleteData () throws IOException { Table student = conn.getTable(TableName.valueOf("student" )); Delete delete = new Delete (Bytes.toBytes("110" )); student.delete(delete); System.out.println("删除数据成功" ); } @Test public void getData () throws IOException { Table student = conn.getTable(TableName.valueOf("student" )); Get get = new Get (Bytes.toBytes("110" )); get.addFamily(Bytes.toBytes("info" )); Result result = student.get(get); Cell[] cells = result.rawCells(); for (Cell cell : cells) { String rowKey = Bytes.toString(CellUtil.cloneRow(cell)); String f = Bytes.toString(CellUtil.cloneFamily(cell)); String column = Bytes.toString(CellUtil.cloneQualifier(cell)); String value = Bytes.toString(CellUtil.cloneValue(cell)); System.out.println("rowKey = " + rowKey + ", f = " + f + ", column = " + column + ", value = " + value); } student.close(); } @Test public void scanData () throws IOException { Table student = conn.getTable(TableName.valueOf("student" )); Scan scan = new Scan (); ResultScanner resultScanner = student.getScanner(scan); for (Result result : resultScanner) { Cell[] cells = result.rawCells(); for (Cell cell : cells) { String rowKey = Bytes.toString(CellUtil.cloneRow(cell)); String f = Bytes.toString(CellUtil.cloneFamily(cell)); String column = Bytes.toString(CellUtil.cloneQualifier(cell)); String value = Bytes.toString(CellUtil.cloneValue(cell)); System.out.println("rowKey = " + rowKey + ", f = " + f + ", column = " + column + ", value = " + value); } } student.close(); } @Test public void scanStartEndData () throws IOException { Table student = conn.getTable(TableName.valueOf("student" )); Scan scan = new Scan (); scan.setStartRow(Bytes.toBytes("001" )); scan.setStopRow(Bytes.toBytes("2" )); ResultScanner resultScanner = student.getScanner(scan); for (Result result : resultScanner) { Cell[] cells = result.rawCells(); for (Cell cell : cells) { String rowKey = Bytes.toString(CellUtil.cloneRow(cell)); String f = Bytes.toString(CellUtil.cloneFamily(cell)); String column = Bytes.toString(CellUtil.cloneQualifier(cell)); String value = Bytes.toString(CellUtil.cloneValue(cell)); System.out.println("rowKey = " + rowKey + ", f = " + f + ", column = " + column + ", value = " + value); } } student.close(); } @After public void release () { if (conn != null ) { try { conn.close(); } catch (IOException e) { e.printStackTrace(); } } } }
协处理器