hbase_hbase 大数据 - CSDN
hbase 订阅
HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。 展开全文
HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。
信息
来    源
Fay Chang 所撰写的“Bigtable
中文名
HBase
隶    属
Apache的Hadoop项目
系    统
Google
属    性
开源数据库
结    构
分布式存储系统
HBase结构介绍
HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。与FUJITSU Cliq等商用大数据产品不同,HBase是Google Bigtable的开源实现,类似Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用 Chubby作为协同服务,HBase利用Zookeeper作为对应。 [1]  上图描述Hadoop EcoSystem中的各层系统。其中,HBase位于结构化存储层,Hadoop HDFS为HBase提供了高可靠性的底层存储支持,Hadoop MapReduce为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定服务和failover机制。 此外,Pig和Hive还为HBase提供了高层语言支持,使得在HBase上进行数据统计处理变的非常简单。 Sqoop则为HBase提供了方便的RDBMS数据导入功能,使得传统数据库数据向HBase中迁移变的非常方便。
收起全文
  • 大数据之hbase详解

    2019-09-02 10:22:27
    HBase的原型是Google的BigTable论文,受到了该论文思想的启发,目前作为Hadoop的子项目来开发维护,用于支持结构化的数据存储.HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBASE技术可在廉价...
  • HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。本次课程适合HBase入门的学员,课程首先介绍了什么是HBase ,...
  • HBase是一个构建在HDFS上的分布式列存储系统; HBase是基于Google BigTable模型开发的,典型的key/value系统; HBase是Apache Hadoop生态系统中的重要一员,主要用于海量结构化数据存储; 从逻辑上讲,HBase将数据...

     

    • 概述
     



    HBase是一个构建在HDFS上的分布式列存储系统;
    HBase是基于Google BigTable模型开发的,典型的key/value系统;
    HBase是Apache Hadoop生态系统中的重要一员,主要用于海量结构化数据存储;
    从逻辑上讲,HBase将数据按照表、行和列进行存储。
    与hadoop一样,Hbase目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。
    Hbase表的特点
    大:一个表可以有数十亿行,上百万列
    无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列
    面向列:面向列(族)的存储和权限控制,列(族)独立检索
    稀疏:空(null)列并不占用存储空间,表可以设计的非常稀疏;
    数据多版本:每个单元中的数据可以有多个版本,默认情况下版本号自动分配,是单元格插入时的时间戳;
    数据类型单一:Hbase中的数据都是字符串,没有类型。

    • Hbase数据模型

    Hbase逻辑视图

     

    注意上图中的英文说明

    Hbase基本概念

    RowKey:是Byte array,是表中每条记录的“主键”,方便快速查找,Rowkey的设计非常重要。
    Column Family:列族,拥有一个名称(string),包含一个或者多个相关列
    Column:属于某一个columnfamily,familyName:columnName,每条记录可动态添加
    Version Number:类型为Long,默认值是系统时间戳,可由用户自定义
    Value(Cell):Byte array
    • Hbase物理模型

    每个column family存储在HDFS上的一个单独文件中,空值不会被保存。
    Key 和 Version number在每个 column family中均有一份;
    HBase 为每个值维护了多级索引,即:<key, column family, column name, timestamp>

    物理存储:
    1、Table中所有行都按照row key的字典序排列;
    2、Table在行的方向上分割为多个Region;
    3、Region按大小分割的,每个表开始只有一个region,随着数据增多,region不断增大,当增大到一个阈值的时候,region就会等分会两个新的region,之后会有越来越多的region;
    4、Region是Hbase中分布式存储和负载均衡的最小单元,不同Region分布到不同RegionServer上。

    5、Region虽然是分布式存储的最小单元,但并不是存储的最小单元。Region由一个或者多个Store组成,每个store保存一个columns family;每个Strore又由一个memStore和0至多个StoreFile组成,StoreFile包含HFile;memStore存储在内存中,StoreFile存储在HDFS上。

     

    • HBase架构及基本组件

     

    Hbase基本组件说明:

     

    Client

    包含访问HBase的接口,并维护cache来加快对HBase的访问,比如region的位置信息

    Master

    为Region server分配region

    负责Region server的负载均衡

    发现失效的Region server并重新分配其上的region

    管理用户对table的增删改查操作

    Region Server

    Regionserver维护region,处理对这些region的IO请求

    Regionserver负责切分在运行过程中变得过大的region

    Zookeeper作用

    通过选举,保证任何时候,集群中只有一个master,Master与RegionServers 启动时会向ZooKeeper注册

    存贮所有Region的寻址入口

    实时监控Region server的上线和下线信息。并实时通知给Master

    存储HBase的schema和table元数据

    默认情况下,HBase 管理ZooKeeper 实例,比如, 启动或者停止ZooKeeper

    Zookeeper的引入使得Master不再是单点故障

     

    Write-Ahead-Log(WAL)

    该机制用于数据的容错和恢复:

    每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中(HLog文件格式见后续),HLog文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的 HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应region的目录下,然后再将失效的region重新分配,领取 到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复

    HBase容错性
    Master容错:Zookeeper重新选择一个新的Master
    无Master过程中,数据读取仍照常进行;
    无master过程中,region切分、负载均衡等无法进行;
    RegionServer容错:定时向Zookeeper汇报心跳,如果一旦时间内未出现心跳,Master将该RegionServer上的Region重新分配到其他RegionServer上,失效服务器上“预写”日志由主服务器进行分割并派送给新的RegionServer
    Zookeeper容错:Zookeeper是一个可靠地服务,一般配置3或5个Zookeeper实例
    Region定位流程:

    寻找RegionServer

    ZooKeeper--> -ROOT-(单Region)--> .META.--> 用户表

    -ROOT-
    表包含.META.表所在的region列表,该表只会有一个Region;

    Zookeeper中记录了-ROOT-表的location。

    .META.

    表包含所有的用户空间region列表,以及RegionServer的服务器地址。

    • Hbase使用场景

    storing large amounts  of data(100s of TBs)
    need high write throughput
    need efficient random access(key lookups) within large data sets
    need to scale gracefully with data
    for structured and semi-structured data
    don't need fullRDMS capabilities(cross row/cross table transaction, joins,etc.)

    大数据量存储,大数据量高并发操作

    需要对数据随机读写操作

    读写访问均是非常简单的操作

    • Hbase与HDFS对比

    两者都具有良好的容错性和扩展性,都可以扩展到成百上千个节点;
    HDFS适合批处理场景
    不支持数据随机查找
    不适合增量数据处理

    不支持数据更新

     

    • 参考文档:

    1、http://www.alidata.org/archives/1509(存储模型比较详细)

    2、http://www.searchtb.com/2011/01/understanding-hbase.html(技术框架以及存储模型)

    3、http://wenku.baidu.com/view/b46eadd228ea81c758f578f4.html(读和写的流程比较详细)

    展开全文
  • Hbase从入门到入坑

    2020-07-03 09:39:02
    一 什么是HBASE 二 安装HBASEhbase初体验 四 HBASE客户端API操作 五 HBASE运行原理 5.1 master职责 5.2 Region Server 职责 5.3 zookeeper集群所起作用 5.4 HBASE读写数据流程 5.5 hbase:meta表 5.6 ...

    以后博客的内容都是通过微信公众号链接的形式发布,之后迁移到公众号的文章都会重新修正,也更加详细,对于以前博客内容里面的错误或者理解不当的地方都会在公众号里面修正。

    欢迎关注我的微信公众号,以后我会发布更多工作中总结的技术内容。

    目录

    一 什么是HBASE

    二 安装HBASE

    三 hbase初体验

    四 HBASE客户端API操作

    五 HBASE运行原理

    5.1 master职责

    5.2 Region Server 职责

    5.3 zookeeper集群所起作用

    5.4 HBASE读写数据流程

    5.4.1 写数据流程

    5.4.2 读数据流程

    5.4.3 数据flush过程

    5.4.4 数据合并过程

    5.5 hbase:meta表

    5.6 Region Server内部机制

    六.HBASE优化

    6.1 高可用

    6.2 预分区

    6.3 RowKey设计

    6.4 内存优化

    6.5 基础优化


    一 什么是HBASE

    HBASE是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群。

    HBASE的目标是存储并处理大型的数据,更具体来说是仅需使用普通的硬件配置,就能够处理由成千上万的行和列所组成的大型数据。

    HBASE是Google Bigtable的开源实现,但是也有很多不同之处。比如:Google Bigtable利用GFS作为其文件存储系统,HBASE利用Hadoop HDFS作为其文件存储系统;Google运行MAPREDUCE来处理Bigtable中的海量数据,HBASE同样利用Hadoop MapReduce来处理HBASE中的海量数据;Google Bigtable利用Chubby作为协同服务,HBASE利用Zookeeper作为对应。

    HBASE与mysql、oralce、db2、sqlserver等关系型数据库不同,它是一个NoSQL数据库(非关系型数据库)

    1. Hbase的表模型与关系型数据库的表模型不同:
    2. Hbase的表没有固定的字段定义;
    3. Hbase的表中每行存储的都是一些key-value对
    4. Hbase的表中有列族的划分,用户可以指定将哪些kv插入哪个列族
    5. Hbase的表在物理存储上,是按照列族来分割的,不同列族的数据一定存储在不同的文件中
    6. Hbase的表中的每一行都固定有一个行键,而且每一行的行键在表中不能重复
    7. Hbase中的数据,包含行键,包含key,包含value,都是byte[ ]类型,hbase不负责为用户维护数据类型
    8. HBASE对事务的支持很差

    HBASE相比于其他nosql数据库(mongodb、redis、cassendra、hazelcast)的特点:

    Hbase的表数据存储在HDFS文件系统中

    从而,hbase具备如下特性:存储容量可以线性扩展; 数据存储的安全性可靠性极高!

    二 安装HBASE

    HBASE是一个分布式系统

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

    其他的数据节点角色:  HRegionServer(很多台,看数据容量)

    2.1 安装准备

    需要先有一个java环境

    首先,要有一个HDFS集群,并正常运行; regionserver应该跟hdfs中的datanode在一起

    其次,还需要一个zookeeper集群,并正常运行

    然后,安装HBASE

    角色分配如下:

    Hdp01:  namenode  datanode  regionserver  hmaster  zookeeper

    Hdp02:  datanode   regionserver  zookeeper

    Hdp03:  datanode   regionserver  zookeeper

    2.2 安装步骤

    解压hbase安装包

    修改hbase-env.sh

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

    export HBASE_MANAGES_ZK=false

    修改hbase-site.xml

    <configuration>

    <!-- 指定hbase在HDFS上存储的路径 -->

            <property>

                    <name>hbase.rootdir</name>

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

            </property>

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

            <property>

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

                    <value>true</value>

            </property>

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

            <property>

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

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

            </property>

    </configuration>

    修改 regionservers

    hdp01

    hdp02

    hdp03

    2.3 启动hbase集群

    bin/start-hbase.sh

    启动完后,还可以在集群中找任意一台机器启动一个备用的master

    bin/hbase-daemon.sh start master

    新启的这个master会处于backup状态

    三 hbase初体验

    3.1 启动hbase命令行客户端

    bin/hbase shell

    Hbase> list     // 查看表

    Hbase> status   // 查看集群状态

    Hbase> version  // 查看集群版本

    3.2 hbase表模型的特点

    1. 一个表,有表名
    2. 一个表可以分为多个列族(不同列族的数据会存储在不同文件中)
    3. 表中的每一行有一个“行键rowkey”,而且行键在表中不能重复
    4. 表中的每一对kv数据称作一个cell
    5. hbase可以对数据存储多个历史版本(历史版本数量可配置)
    6. 整张表由于数据量过大,会被横向切分成若干个region(用rowkey范围标识),不同region的数据也存储在不同文件中
    7. hbase会对插入的数据按顺序存储:

         要点一:首先会按行键排序

         要点二:同一行里面的kv会按列族排序,再按k排序

    3.3 hbase的表中能存储什么数据类型

    hbase中只支持byte[]

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

    3.4 hbase命令行客户端操作

    名称

    命令表达式

    创建表

    create '表名', '列族名1','列族名2','列族名N'

    查看所有表

    list

    描述表

    describe  ‘表名’

    判断表存在

    exists  '表名'

    判断是否禁用启用表

    is_enabled '表名'

    is_disabled ‘表名’

    添加记录      

    put  ‘表名’, ‘rowKey’, ‘列族 : 列‘  ,  '值'

    查看记录rowkey下的所有数据

    get  '表名' , 'rowKey'

    查看表中的记录总数

    count  '表名'

    获取某个列族

    get '表名','rowkey','列族'

    获取某个列族的某个列

    get '表名','rowkey','列族:列’

    删除记录

    delete  ‘表名’ ,‘行名’ , ‘列族:列'

    删除整行

    deleteall '表名','rowkey'

    删除一张表

    先要屏蔽该表,才能对该表进行删除

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

    清空表

    truncate '表名'

    查看所有记录

    scan "表名"  

    查看某个表某个列中所有数据

    scan "表名" , {COLUMNS=>'列族名:列名'}

    更新记录

    就是重写一遍,进行覆盖,hbase没有修改,都是追加

    3.4.1 建表

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

                          表名      列族名   列族名

    3.4.2 插入数据

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

    0 row(s) in 0.2420 seconds

     

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

    0 row(s) in 0.0140 seconds

     

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

    0 row(s) in 0.0070 seconds

     

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

    0 row(s) in 0.0090 seconds

     

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

    0 row(s) in 0.0090 seconds

     

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

    0 row(s) in 0.0060 seconds

    3.4.3 查询方式一 scan扫描

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

    ROW                               COLUMN+CELL                                                                                     

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

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

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

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

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

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

    3.4.4 查询方式二 get单行数据

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

    COLUMN                            CELL                                                                                            

     base_info:age                    timestamp=1496568160192, value=19                                                               

     base_info:sex                    timestamp=1496567934669, value=female                                                           

     base_info:username               timestamp=1496567889554, value=zhangsan                                                         

     extra_info:career                timestamp=1496567963992, value=it                                                               

    4 row(s) in 0.0770 seconds

    3.4.5 删除一个kv数据

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

    0 row(s) in 0.0390 seconds

    删除整行数据

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

    0 row(s) in 0.0090 seconds

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

    COLUMN                            CELL                                                                                            

    0 row(s) in 0.0110 seconds

    3.4.6 删除整个表

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

    0 row(s) in 2.3640 seconds

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

    0 row(s) in 1.2950 seconds

    hbase(main):030:0> list

    TABLE                                                                                                                             

    0 row(s) in 0.0130 seconds

    => []

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

    与nosql数据库们一样,row key是用来检索记录的主键。访问HBASE table中的行,只有三种方式:

    1.通过单个row key访问

    2.通过row key的range(正则)

    3.全表扫描

    Row key行键 (Row key)可以是任意字符串(最大长度 是 64KB,实际应用中长度一般为 10-100bytes),在HBASE内部,row key保存为字节数组。存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)

    插入到hbase中去的数据,hbase会自动排序存储:

    排序规则:  首先看行键,然后看列族名,然后看列(key)名; 按字典顺序

    Hbase的这个特性跟查询效率有极大的关系

    比如:一张用来存储用户信息的表,有名字,户籍,年龄,职业....等信息

    然后,在业务系统中经常需要:

    查询某个省的所有用户

    经常需要查询某个省的指定姓的所有用户

    思路:如果能将相同省的用户在hbase的存储文件中连续存储,并且能将相同省中相同姓的用户连续存储,那么,上述两个查询需求的效率就会提高!!!

    做法:将查询条件拼到rowkey内

    四 HBASE客户端API操作

    4.1 简洁版

    HbaseClientDDL 

    package cn.hbase.demo;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.HColumnDescriptor;
    import org.apache.hadoop.hbase.HTableDescriptor;
    import org.apache.hadoop.hbase.TableName;
    import org.apache.hadoop.hbase.client.Admin;
    import org.apache.hadoop.hbase.client.Connection;
    import org.apache.hadoop.hbase.client.ConnectionFactory;
    import org.apache.hadoop.hbase.regionserver.BloomType;
    import org.junit.Before;
    import org.junit.Test;
    
    
    /**
     *  
     *  1、构建连接
     *  2、从连接中取到一个表DDL操作工具admin
     *  3、admin.createTable(表描述对象);
     *  4、admin.disableTable(表名);
    	5、admin.deleteTable(表名);
    	6、admin.modifyTable(表名,表描述对象);	
     *  
     *
     */
    public class HbaseClientDDL {
    	Connection conn = null;
    	
    	@Before
    	public void getConn() throws Exception{
    		// 构建一个连接对象
    		Configuration conf = HBaseConfiguration.create(); // 会自动加载hbase-site.xml
    		conf.set("hbase.zookeeper.quorum", "hdp-01:2181,hdp-02:2181,hdp-03:2181");
    		
    		conn = ConnectionFactory.createConnection(conf);
    	}
    	
    	
    	
    	/**
    	 * DDL
    	 * @throws Exception 
    	 */
    	@Test
    	public void testCreateTable() throws Exception{
    
    		// 从连接中构造一个DDL操作器
    		Admin admin = conn.getAdmin();
    		
    		// 创建一个表定义描述对象
    		HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("user_info"));
    		
    		// 创建列族定义描述对象
    		HColumnDescriptor hColumnDescriptor_1 = new HColumnDescriptor("base_info");
    		hColumnDescriptor_1.setMaxVersions(3); // 设置该列族中存储数据的最大版本数,默认是1
    		
    		HColumnDescriptor hColumnDescriptor_2 = new HColumnDescriptor("extra_info");
    		
    		// 将列族定义信息对象放入表定义对象中
    		hTableDescriptor.addFamily(hColumnDescriptor_1);
    		hTableDescriptor.addFamily(hColumnDescriptor_2);
    		
    		
    		// 用ddl操作器对象:admin 来建表
    		admin.createTable(hTableDescriptor);
    		
    		// 关闭连接
    		admin.close();
    		conn.close();
    		
    	}
    	
    	
    	/**
    	 * 删除表
    	 * @throws Exception 
    	 */
    	@Test
    	public void testDropTable() throws Exception{
    		
    		Admin admin = conn.getAdmin();
    		
    		// 停用表
    		admin.disableTable(TableName.valueOf("user_info"));
    		// 删除表
    		admin.deleteTable(TableName.valueOf("user_info"));
    		
    		
    		admin.close();
    		conn.close();
    	}
    	
    	// 修改表定义--添加一个列族
    	@Test
    	public void testAlterTable() throws Exception{
    		
    		Admin admin = conn.getAdmin();
    		
    		// 取出旧的表定义信息
    		HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf("user_info"));
    		
    		
    		// 新构造一个列族定义
    		HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("other_info");
    		hColumnDescriptor.setBloomFilterType(BloomType.ROWCOL); // 设置该列族的布隆过滤器类型
    		
    		// 将列族定义添加到表定义对象中
    		tableDescriptor.addFamily(hColumnDescriptor);
    		
    		
    		// 将修改过的表定义交给admin去提交
    		admin.modifyTable(TableName.valueOf("user_info"), tableDescriptor);
    		
    		
    		admin.close();
    		conn.close();
    		
    	}
    	
    	
    	/**
    	 * DML -- 数据的增删改查
    	 */
    	
    	
    
    }
    

    HbaseClientDML

    package cn.hbase.demo;
    
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.Cell;
    import org.apache.hadoop.hbase.CellScanner;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.TableName;
    import org.apache.hadoop.hbase.client.Connection;
    import org.apache.hadoop.hbase.client.ConnectionFactory;
    import org.apache.hadoop.hbase.client.Delete;
    import org.apache.hadoop.hbase.client.Get;
    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.client.Table;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.junit.Before;
    import org.junit.Test;
    
    public class HbaseClientDML {
    	Connection conn = null;
    	
    	@Before
    	public void getConn() throws Exception{
    		// 构建一个连接对象
    		Configuration conf = HBaseConfiguration.create(); // 会自动加载hbase-site.xml
    		conf.set("hbase.zookeeper.quorum", "hdp-01:2181,hdp-02:2181,hdp-03:2181");
    		
    		conn = ConnectionFactory.createConnection(conf);
    	}
    	
    	
    	/**
    	 * 增
    	 * 改:put来覆盖
    	 * @throws Exception 
    	 */
    	@Test
    	public void testPut() throws Exception{
    		
    		// 获取一个操作指定表的table对象,进行DML操作
    		Table table = conn.getTable(TableName.valueOf("user_info"));
    		
    		// 构造要插入的数据为一个Put类型(一个put对象只能对应一个rowkey)的对象
    		Put put = new Put(Bytes.toBytes("001"));
    		put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("张三"));
    		put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("18"));
    		put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));
    		
    		
    		Put put2 = new Put(Bytes.toBytes("002"));
    		put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("李四"));
    		put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("28"));
    		put2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("上海"));
    	
    		
    		ArrayList<Put> puts = new ArrayList<>();
    		puts.add(put);
    		puts.add(put2);
    		
    		
    		// 插进去
    		table.put(puts);
    		
    		table.close();
    		conn.close();
    		
    	}
    	
    	
    	/**
    	 * 循环插入大量数据
    	 * @throws Exception 
    	 */
    	@Test
    	public void testManyPuts() throws Exception{
    		
    		Table table = conn.getTable(TableName.valueOf("user_info"));
    		ArrayList<Put> puts = new ArrayList<>();
    		
    		for(int i=0;i<100000;i++){
    			Put put = new Put(Bytes.toBytes(""+i));
    			put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("username"), Bytes.toBytes("张三"+i));
    			put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes((18+i)+""));
    			put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"), Bytes.toBytes("北京"));
    			
    			puts.add(put);
    		}
    		
    		table.put(puts);
    		
    	}
    	
    	/**
    	 * 删
    	 * @throws Exception 
    	 */
    	@Test
    	public void testDelete() throws Exception{
    		Table table = conn.getTable(TableName.valueOf("user_info"));
    		
    		// 构造一个对象封装要删除的数据信息
    		Delete delete1 = new Delete(Bytes.toBytes("001"));
    		
    		Delete delete2 = new Delete(Bytes.toBytes("002"));
    		delete2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("addr"));
    		
    		ArrayList<Delete> dels = new ArrayList<>();
    		dels.add(delete1);
    		dels.add(delete2);
    		
    		table.delete(dels);
    		
    		
    		table.close();
    		conn.close();
    	}
    	
    	/**
    	 * 查
    	 * @throws Exception 
    	 */
    	@Test
    	public void testGet() throws Exception{
    		
    		Table table = conn.getTable(TableName.valueOf("user_info"));
    		
    		Get get = new Get("002".getBytes());
    		
    		Result result = table.get(get);
    		
    		// 从结果中取用户指定的某个key的value
    		byte[] value = result.getValue("base_info".getBytes(), "age".getBytes());
    		System.out.println(new String(value));
    		
    		System.out.println("-------------------------");
    		
    		// 遍历整行结果中的所有kv单元格
    		CellScanner cellScanner = result.cellScanner();
    		while(cellScanner.advance()){
    			Cell cell = cellScanner.current();
    			
    			byte[] rowArray = cell.getRowArray();  //本kv所属的行键的字节数组
    			byte[] familyArray = cell.getFamilyArray();  //列族名的字节数组
    			byte[] qualifierArray = cell.getQualifierArray();  //列名的字节数据
    			byte[] valueArray = cell.getValueArray(); // value的字节数组
    			
    			System.out.println("行键: "+new String(rowArray,cell.getRowOffset(),cell.getRowLength()));
    			System.out.println("列族名: "+new String(familyArray,cell.getFamilyOffset(),cell.getFamilyLength()));
    			System.out.println("列名: "+new String(qualifierArray,cell.getQualifierOffset(),cell.getQualifierLength()));
    			System.out.println("value: "+new String(valueArray,cell.getValueOffset(),cell.getValueLength()));
    			
    		}
    		
    		table.close();
    		conn.close();
    		
    	}
    	
    	
    	/**
    	 * 按行键范围查询数据
    	 * @throws Exception 
    	 */
    	@Test
    	public void testScan() throws Exception{
    		
    		Table table = conn.getTable(TableName.valueOf("user_info"));
    		
    		// 包含起始行键,不包含结束行键,但是如果真的想查询出末尾的那个行键,那么,可以在末尾行键上拼接一个不可见的字节(\000)
    		Scan scan = new Scan("10".getBytes(), "10000\001".getBytes());
    		
    		ResultScanner scanner = table.getScanner(scan);
    		
    		Iterator<Result> iterator = scanner.iterator();
    		
    		while(iterator.hasNext()){
    			
    			Result result = iterator.next();
    			// 遍历整行结果中的所有kv单元格
    			CellScanner cellScanner = result.cellScanner();
    			while(cellScanner.advance()){
    				Cell cell = cellScanner.current();
    				
    				byte[] rowArray = cell.getRowArray();  //本kv所属的行键的字节数组
    				byte[] familyArray = cell.getFamilyArray();  //列族名的字节数组
    				byte[] qualifierArray = cell.getQualifierArray();  //列名的字节数据
    				byte[] valueArray = cell.getValueArray(); // value的字节数组
    				
    				System.out.println("行键: "+new String(rowArray,cell.getRowOffset(),cell.getRowLength()));
    				System.out.println("列族名: "+new String(familyArray,cell.getFamilyOffset(),cell.getFamilyLength()));
    				System.out.println("列名: "+new String(qualifierArray,cell.getQualifierOffset(),cell.getQualifierLength()));
    				System.out.println("value: "+new String(valueArray,cell.getValueOffset(),cell.getValueLength()));
    			}
    			System.out.println("----------------------");
    		}
    	}
    	
    	@Test
    	public void test(){
    		String a = "000";
    		String b = "000\0";
    		
    		System.out.println(a);
    		System.out.println(b);
    		
    		
    		byte[] bytes = a.getBytes();
    		byte[] bytes2 = b.getBytes();
    		
    		System.out.println("");
    		
    	}
    	
    	
    
    }
    

    4.2 完整版

    package com.zgcbank.hbase;
    
    import java.util.ArrayList;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.Cell;
    import org.apache.hadoop.hbase.CellUtil;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.HColumnDescriptor;
    import org.apache.hadoop.hbase.HTableDescriptor;
    import org.apache.hadoop.hbase.MasterNotRunningException;
    import org.apache.hadoop.hbase.TableName;
    import org.apache.hadoop.hbase.ZooKeeperConnectionException;
    import org.apache.hadoop.hbase.client.Connection;
    import org.apache.hadoop.hbase.client.ConnectionFactory;
    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.HConnection;
    import org.apache.hadoop.hbase.client.HConnectionManager;
    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.client.Table;
    import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;
    import org.apache.hadoop.hbase.filter.CompareFilter;
    import org.apache.hadoop.hbase.filter.FilterList;
    import org.apache.hadoop.hbase.filter.FilterList.Operator;
    import org.apache.hadoop.hbase.filter.RegexStringComparator;
    import org.apache.hadoop.hbase.filter.RowFilter;
    import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class HbaseTest {
    
    	/**
    	 * 配置ss
    	 */
    	static Configuration config = null;
    	private Connection connection = null;
    	private Table table = null;
    
    	@Before
    	public void init() throws Exception {
    		config = HBaseConfiguration.create();// 配置
    		config.set("hbase.zookeeper.quorum", "master,work1,work2");// zookeeper地址
    		config.set("hbase.zookeeper.property.clientPort", "2181");// zookeeper端口
    		connection = ConnectionFactory.createConnection(config);
    		table = connection.getTable(TableName.valueOf("user"));
    	}
    
    	/**
    	 * 创建一个表
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void createTable() throws Exception {
    		// 创建表管理类
    		HBaseAdmin admin = new HBaseAdmin(config); // hbase表管理
    		// 创建表描述类
    		TableName tableName = TableName.valueOf("test3"); // 表名称
    		HTableDescriptor desc = new HTableDescriptor(tableName);
    		// 创建列族的描述类
    		HColumnDescriptor family = new HColumnDescriptor("info"); // 列族
    		// 将列族添加到表中
    		desc.addFamily(family);
    		HColumnDescriptor family2 = new HColumnDescriptor("info2"); // 列族
    		// 将列族添加到表中
    		desc.addFamily(family2);
    		// 创建表
    		admin.createTable(desc); // 创建表
    	}
    
    	@Test
    	@SuppressWarnings("deprecation")
    	public void deleteTable() throws MasterNotRunningException,
    			ZooKeeperConnectionException, Exception {
    		HBaseAdmin admin = new HBaseAdmin(config);
    		admin.disableTable("test3");
    		admin.deleteTable("test3");
    		admin.close();
    	}
    
    	/**
    	 * 向hbase中增加数据
    	 * 
    	 * @throws Exception
    	 */
    	@SuppressWarnings({ "deprecation", "resource" })
    	@Test
    	public void insertData() throws Exception {
    		table.setAutoFlushTo(false);
    		table.setWriteBufferSize(534534534);
    		ArrayList<Put> arrayList = new ArrayList<Put>();
    		for (int i = 21; i < 50; i++) {
    			Put put = new Put(Bytes.toBytes("1234"+i));
    			put.add(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("wangwu"+i));
    			put.add(Bytes.toBytes("info"), Bytes.toBytes("password"), Bytes.toBytes(1234+i));
    			arrayList.add(put);
    		}
    		
    		//插入数据
    		table.put(arrayList);
    		//提交
    		table.flushCommits();
    	}
    
    	/**
    	 * 修改数据
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void uodateData() throws Exception {
    		Put put = new Put(Bytes.toBytes("1234"));
    		put.add(Bytes.toBytes("info"), Bytes.toBytes("namessss"), Bytes.toBytes("lisi1234"));
    		put.add(Bytes.toBytes("info"), Bytes.toBytes("password"), Bytes.toBytes(1234));
    		//插入数据
    		table.put(put);
    		//提交
    		table.flushCommits();
    	}
    
    	/**
    	 * 删除数据
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void deleteDate() throws Exception {
    		Delete delete = new Delete(Bytes.toBytes("1234"));
    		table.delete(delete);
    		table.flushCommits();
    	}
    
    	/**
    	 * 单条查询
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void queryData() throws Exception {
    		Get get = new Get(Bytes.toBytes("1234"));
    		Result result = table.get(get);
    		System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));
    		System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("namessss"))));
    		System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("sex"))));
    	}
    
    	/**
    	 * 全表扫描
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void scanData() throws Exception {
    		Scan scan = new Scan();
    		//scan.addFamily(Bytes.toBytes("info"));
    		//scan.addColumn(Bytes.toBytes("info"), Bytes.toBytes("password"));
    		scan.setStartRow(Bytes.toBytes("wangsf_0"));
    		scan.setStopRow(Bytes.toBytes("wangwu"));
    		ResultScanner scanner = table.getScanner(scan);
    		for (Result result : scanner) {
    			System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));
    			System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))));
    			//System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("password"))));
    			//System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"))));
    		}
    	}
    
    	/**
    	 * 全表扫描的过滤器
    	 * 列值过滤器
    	 * 
    	 * @throws Exception
    	 */
    	@Test
    	public void scanDataByFilter1() throws Exception {
    
    		// 创建全表扫描的scan
    		Scan scan = new Scan();
    		//过滤器:列值过滤器
    		SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("info"),
    				Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL,
    				Bytes.toBytes("zhangsan2"));
    		// 设置过滤器
    		scan.setFilter(filter);
    
    		// 打印结果集
    		ResultScanner scanner = table.getScanner(scan);
    		for (Result result : scanner) {
    			System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));
    			System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))));
    			//System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("password"))));
    			//System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"))));
    		}
    
    	}
    	/**
    	 * rowkey过滤器
    	 * @throws Exception
    	 */
    	@Test
    	public void scanDataByFilter2() throws Exception {
    		
    		// 创建全表扫描的scan
    		Scan scan = new Scan();
    		//匹配rowkey以wangsenfeng开头的
    		RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^12341"));
    		// 设置过滤器
    		scan.setFilter(filter);
    		// 打印结果集
    		ResultScanner scanner = table.getScanner(scan);
    		for (Result result : scanner) {
    			System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("password"))));
    			System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))));
    			//System.out.println(Bytes.toInt(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("password"))));
    			//System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"))));
    		}
    
    		
    	}
    	
    	/**
    	 * 匹配列名前缀
    	 * @throws Exception
    	 */
    	@Test
    	public void scanDataByFilter3() throws Exception {
    		
    		// 创建全表扫描的scan
    		Scan scan = new Scan();
    		//匹配rowkey以wangsenfeng开头的
    		ColumnPrefixFilter filter = new ColumnPrefixFilter(Bytes.toBytes("na"));
    		// 设置过滤器
    		scan.setFilter(filter);
    		// 打印结果集
    		ResultScanner scanner = table.getScanner(scan);
    		for (Result result : scanner) {
    			System.out.println("rowkey:" + Bytes.toString(result.getRow()));
    			System.out.println("info:name:"
    					+ Bytes.toString(result.getValue(Bytes.toBytes("info"),
    							Bytes.toBytes("name"))));
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")) != null) {
    				System.out.println("info:age:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info"),
    								Bytes.toBytes("age"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("sex")) != null) {
    				System.out.println("infi:sex:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info"),
    								Bytes.toBytes("sex"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name")) != null) {
    				System.out
    				.println("info2:name:"
    						+ Bytes.toString(result.getValue(
    								Bytes.toBytes("info2"),
    								Bytes.toBytes("name"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("age")) != null) {
    				System.out.println("info2:age:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info2"),
    								Bytes.toBytes("age"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("sex")) != null) {
    				System.out.println("info2:sex:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info2"),
    								Bytes.toBytes("sex"))));
    			}
    		}
    		
    	}
    	/**
    	 * 过滤器集合
    	 * @throws Exception
    	 */
    	@Test
    	public void scanDataByFilter4() throws Exception {
    		
    		// 创建全表扫描的scan
    		Scan scan = new Scan();
    		//过滤器集合:MUST_PASS_ALL(and),MUST_PASS_ONE(or)
    		FilterList filterList = new FilterList(Operator.MUST_PASS_ONE);
    		//匹配rowkey以wangsenfeng开头的
    		RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^wangsenfeng"));
    		//匹配name的值等于wangsenfeng
    		SingleColumnValueFilter filter2 = new SingleColumnValueFilter(Bytes.toBytes("info"),
    				Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL,
    				Bytes.toBytes("zhangsan"));
    		filterList.addFilter(filter);
    		filterList.addFilter(filter2);
    		// 设置过滤器
    		scan.setFilter(filterList);
    		// 打印结果集
    		ResultScanner scanner = table.getScanner(scan);
    		for (Result result : scanner) {
    			System.out.println("rowkey:" + Bytes.toString(result.getRow()));
    			System.out.println("info:name:"
    					+ Bytes.toString(result.getValue(Bytes.toBytes("info"),
    							Bytes.toBytes("name"))));
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")) != null) {
    				System.out.println("info:age:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info"),
    								Bytes.toBytes("age"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info"), Bytes.toBytes("sex")) != null) {
    				System.out.println("infi:sex:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info"),
    								Bytes.toBytes("sex"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name")) != null) {
    				System.out
    				.println("info2:name:"
    						+ Bytes.toString(result.getValue(
    								Bytes.toBytes("info2"),
    								Bytes.toBytes("name"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("age")) != null) {
    				System.out.println("info2:age:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info2"),
    								Bytes.toBytes("age"))));
    			}
    			// 判断取出来的值是否为空
    			if (result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("sex")) != null) {
    				System.out.println("info2:sex:"
    						+ Bytes.toInt(result.getValue(Bytes.toBytes("info2"),
    								Bytes.toBytes("sex"))));
    			}
    		}
    		
    	}
    
    	@After
    	public void close() throws Exception {
    		table.close();
    		connection.close();
    	}
    
    }

    4.3 MapReduce操作Hbase

    4.3.1 实现方法

    Hbase对MapReduce提供支持,它实现了TableMapper类和TableReducer类,我们只需要继承这两个类即可。

    1、写个mapper继承TableMapper<Text, IntWritable>

    参数:Text:mapper的输出key类型; IntWritable:mapper的输出value类型。

          其中的map方法如下:

    map(ImmutableBytesWritable key, Result value,Context context)

     参数:key:rowKey;value: Result ,一行数据; context上下文

    2、写个reduce继承TableReducer<Text, IntWritable, ImmutableBytesWritable>

    参数:Text:reducer的输入key; IntWritable:reduce的输入value;

     ImmutableBytesWritable:reduce输出到hbase中的rowKey类型。

          其中的reduce方法如下:

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

    参数: key:reduce的输入key;values:reduce的输入value;

    4.3.2 准备表

    1、建立数据来源表‘word’,包含一个列族‘content’

    向表中添加数据,在列族中放入列‘info’,并将短文数据放入该列中,如此插入多行,行键为不同的数据即可

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

    3、通过Mr操作Hbase的‘word’表,对‘content:info’中的短文做词频统计,并将统计结果写入‘stat’表的‘content:info中’,行键为单词

    4.3.3 实现

    package com.zgcbank.hbase;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.HColumnDescriptor;
    import org.apache.hadoop.hbase.HTableDescriptor;
    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.Scan;
    import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
    import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
    import org.apache.hadoop.hbase.mapreduce.TableMapper;
    import org.apache.hadoop.hbase.mapreduce.TableReducer;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Job;
    /**
     * mapreduce操作hbase
     *
     */
    public class HBaseMr {
    	/**
    	 * 创建hbase配置
    	 */
    	static Configuration config = null;
    	static {
    		config = HBaseConfiguration.create();
    		config.set("hbase.zookeeper.quorum", "slave1,slave2,slave3");
    		config.set("hbase.zookeeper.property.clientPort", "2181");
    	}
    	/**
    	 * 表信息
    	 */
    	public static final String tableName = "word";//表名1
    	public static final String colf = "content";//列族
    	public static final String col = "info";//列
    	public static final String tableName2 = "stat";//表名2
    	/**
    	 * 初始化表结构,及其数据
    	 */
    	public static void initTB() {
    		HTable table=null;
    		HBaseAdmin admin=null;
    		try {
    			admin = new HBaseAdmin(config);//创建表管理
    			/*删除表*/
    			if (admin.tableExists(tableName)||admin.tableExists(tableName2)) {
    				System.out.println("table is already exists!");
    				admin.disableTable(tableName);
    				admin.deleteTable(tableName);
    				admin.disableTable(tableName2);
    				admin.deleteTable(tableName2);
    			}
    			/*创建表*/
    				HTableDescriptor desc = new HTableDescriptor(tableName);
    				HColumnDescriptor family = new HColumnDescriptor(colf);
    				desc.addFamily(family);
    				admin.createTable(desc);
    				HTableDescriptor desc2 = new HTableDescriptor(tableName2);
    				HColumnDescriptor family2 = new HColumnDescriptor(colf);
    				desc2.addFamily(family2);
    				admin.createTable(desc2);
    			/*插入数据*/
    				table = new HTable(config,tableName);
    				table.setAutoFlush(false);
    				table.setWriteBufferSize(500);
    				List<Put> lp = new ArrayList<Put>();
    				Put p1 = new Put(Bytes.toBytes("1"));
    				p1.add(colf.getBytes(), col.getBytes(),	("The Apache Hadoop software library is a framework").getBytes());
    				lp.add(p1);
    				Put p2 = new Put(Bytes.toBytes("2"));p2.add(colf.getBytes(),col.getBytes(),("The common utilities that support the other Hadoop modules").getBytes());
    				lp.add(p2);
    				Put p3 = new Put(Bytes.toBytes("3"));
    				p3.add(colf.getBytes(), col.getBytes(),("Hadoop by reading the documentation").getBytes());
    				lp.add(p3);
    				Put p4 = new Put(Bytes.toBytes("4"));
    				p4.add(colf.getBytes(), col.getBytes(),("Hadoop from the release page").getBytes());
    				lp.add(p4);
    				Put p5 = new Put(Bytes.toBytes("5"));
    				p5.add(colf.getBytes(), col.getBytes(),("Hadoop on the mailing list").getBytes());
    				lp.add(p5);
    				table.put(lp);
    				table.flushCommits();
    				lp.clear();
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				if(table!=null){
    					table.close();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	/**
    	 * MyMapper 继承 TableMapper
    	 * TableMapper<Text,IntWritable> 
    	 * Text:输出的key类型,
    	 * IntWritable:输出的value类型
    	 */
    	public static class MyMapper extends TableMapper<Text, IntWritable> {
    		private static IntWritable one = new IntWritable(1);
    		private static Text word = new Text();
    		@Override
    		//输入的类型为:key:rowKey; value:一行数据的结果集Result
    		protected void map(ImmutableBytesWritable key, Result value,
    				Context context) throws IOException, InterruptedException {
    			//获取一行数据中的colf:col
    			String words = Bytes.toString(value.getValue(Bytes.toBytes(colf), Bytes.toBytes(col)));// 表里面只有一个列族,所以我就直接获取每一行的值
    			//按空格分割
    			String itr[] = words.toString().split(" ");
    			//循环输出word和1
    			for (int i = 0; i < itr.length; i++) {
    				word.set(itr[i]);
    				context.write(word, one);
    			}
    		}
    	}
    	/**
    	 * MyReducer 继承 TableReducer
    	 * TableReducer<Text,IntWritable> 
    	 * Text:输入的key类型,
    	 * IntWritable:输入的value类型,
    	 * ImmutableBytesWritable:输出类型,表示rowkey的类型
    	 */
    	public static class MyReducer extends
    			TableReducer<Text, IntWritable, ImmutableBytesWritable> {
    		@Override
    		protected void reduce(Text key, Iterable<IntWritable> values,
    				Context context) throws IOException, InterruptedException {
    			//对mapper的数据求和
    			int sum = 0;
    			for (IntWritable val : values) {//叠加
    				sum += val.get();
    			}
    			// 创建put,设置rowkey为单词
    			Put put = new Put(Bytes.toBytes(key.toString()));
    			// 封装数据
    			put.add(Bytes.toBytes(colf), Bytes.toBytes(col),Bytes.toBytes(String.valueOf(sum)));
    			//写到hbase,需要指定rowkey、put
    			context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())),put);
    		}
    	}
    	
    	public static void main(String[] args) throws IOException,
    			ClassNotFoundException, InterruptedException {
    		config.set("df.default.name", "hdfs://master:9000/");//设置hdfs的默认路径
    		config.set("hadoop.job.ugi", "hadoop,hadoop");//用户名,组
    		config.set("mapred.job.tracker", "master:9001");//设置jobtracker在哪
    		//初始化表
    		initTB();//初始化表
    		//创建job
    		Job job = new Job(config, "HBaseMr");//job
    		job.setJarByClass(HBaseMr.class);//主类
    		//创建scan
    		Scan scan = new Scan();
    		//可以指定查询某一列
    		scan.addColumn(Bytes.toBytes(colf), Bytes.toBytes(col));
    		//创建查询hbase的mapper,设置表名、scan、mapper类、mapper的输出key、mapper的输出value
    		TableMapReduceUtil.initTableMapperJob(tableName, scan, MyMapper.class,Text.class, IntWritable.class, job);
    		//创建写入hbase的reducer,指定表名、reducer类、job
    		TableMapReduceUtil.initTableReducerJob(tableName2, MyReducer.class, job);
    		System.exit(job.waitForCompletion(true) ? 0 : 1);
    	}
    }

    五 HBASE运行原理

    5.1 master职责

    1.管理监控HRegionServer,实现其负载均衡。

    2.处理region的分配或转移,比如在HRegion split时分配新的HRegion;在HRegionServer退出时迁移其负责的HRegion到其他        HRegionServer上。

    3.处理元数据的变更

    4.管理namespace和table的元数据(实际存储在HDFS上)。

    5.权限控制(ACL)。

    6.监控集群中所有HRegionServer的状态(通过Heartbeat和监听ZooKeeper中的状态)。

    5.2 Region Server 职责

    1. 管理自己所负责的region数据的读写。
    2. 读写HDFS,管理Table中的数据。
    3. Client直接通过HRegionServer读写数据(从HMaster中获取元数据,找到RowKey所在的HRegion/HRegionServer后)。
    4. 刷新缓存到HDFS
    5. 维护Hlog
    6. 执行压缩
    7. 负责处理Region分片

    5.3 zookeeper集群所起作用

    1. 存放整个HBase集群的元数据以及集群的状态信息。
    2. 实现HMaster主从节点的failover。

    注: HMaster通过监听ZooKeeper中的Ephemeral节点(默认:/hbase/rs/*)来监控HRegionServer的加入和宕机。

    在第一个HMaster连接到ZooKeeper时会创建Ephemeral节点(默认:/hbasae/master)来表示Active的HMaster,其后加进来的HMaster则监听该Ephemeral节点

    如果当前Active的HMaster宕机,则该节点消失,因而其他HMaster得到通知,而将自身转换成Active的HMaster,在变为Active的HMaster之前,它会在/hbase/masters/下创建自己的Ephemeral节点。

    5.4 HBASE读写数据流程

    5.4.1 写数据流程

    客户端现在要插入一条数据,rowkey=r000001, 这条数据应该写入到table表中的那个region中呢?

    1/ 客户端要连接zookeeper, 从zk的/hbase节点找到hbase:meta表所在的regionserver(host:port);

    2/ regionserver扫描hbase:meta中的每个region的起始行健,对比r000001这条数据在那个region的范围内;

    3/ 从对应的 info:server key中存储了region是有哪个regionserver(host:port)在负责的;

    4/ 客户端直接请求对应的regionserver;

    5/ regionserver接收到客户端发来的请求之后,就会将数据写入到region中

    5.4.2 读数据流程

    客户端现在要查询rowkey=r000001这条数据,那么这个流程是什么样子的呢?

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

    2/ 请求对应的regionserver,扫描hbase:meta表,根据namespace、表名和rowkey在meta表中找到r00001所在的region是由那个regionserver负责的;

    3/找到这个region对应的regionserver

    4/ regionserver收到了请求之后,扫描对应的region返回数据到Client

    (先从MemStore找数据,如果没有,再到BlockCache里面读;BlockCache还没有,再到StoreFile上读(为了读取的效率);

    如果是从StoreFile里面读取的数据,不是直接返回给客户端,而是先写入BlockCache,再返回给客户端。)

    注:客户会缓存这些位置信息,然而第二步它只是缓存当前RowKey对应的HRegion的位置,因而如果下一个要查的RowKey不在同一个HRegion中,则需要继续查询hbase:meta所在的HRegion,然而随着时间的推移,客户端缓存的位置信息越来越多,以至于不需要再次查找hbase:meta Table的信息,除非某个HRegion因为宕机或Split被移动,此时需要重新查询并且更新缓存。

    5.4.3 数据flush过程

    1)当MemStore数据达到阈值(默认是128M,老版本是64M),将数据刷到硬盘,将内存中的数据删除,同时删除HLog中的历史数据;

    2)并将数据存储到HDFS中;

    3)在HLog中做标记点。

    5.4.4 数据合并过程

    1)当数据块达到3块,Hmaster触发合并操作,Region将数据块加载到本地,进行合并;

    2)当合并的数据超过256M,进行拆分,将拆分后的Region分配给不同的HregionServer管理;

    3)当HregionServer宕机后,将HregionServer上的hlog拆分,然后分配给不同的HregionServer加载,修改.META.;

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

    5.5 hbase:meta表

    hbase:meta表存储了所有用户HRegion的位置信息:

    Rowkey:tableName,regionStartKey,regionId,replicaId等;

    info列族:这个列族包含三个列,他们分别是:

    info:regioninfo列:

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

    info:server列:HRegionServer对应的server:port;

    info:serverstartcode列:HRegionServer的启动时间戳。

    5.6 Region Server内部机制

    • WAL即Write Ahead Log,在早期版本中称为HLog,它是HDFS上的一个文件,如其名字所表示的,所有写操作都会先保证将数据写入这个Log文件后,才会真正更新MemStore,最后写入HFile中。WAL文件存储在/hbase/WALs/${HRegionServer_Name}的目录中
    • BlockCache是一个读缓存,即“引用局部性”原理(也应用于CPU,分空间局部性和时间局部性,空间局部性是指CPU在某一时刻需要某个数据,那么有很大的概率在一下时刻它需要的数据在其附近;时间局部性是指某个数据在被访问过一次后,它有很大的概率在不久的将来会被再次的访问),将数据预读取到内存中,以提升读的性能。
    • HRegion是一个Table中的一个Region在一个HRegionServer中的表达。一个Table可以有一个或多个Region,他们可以在一个相同的HRegionServer上,也可以分布在不同的HRegionServer上,一个HRegionServer可以有多个HRegion,他们分别属于不同的Table。HRegion由多个Store(HStore)构成,每个HStore对应了一个Table在这个HRegion中的一个Column Family,即每个Column Family就是一个集中的存储单元,因而最好将具有相近IO特性的Column存储在一个Column Family,以实现高效读取(数据局部性原理,可以提高缓存的命中率)。HStore是HBase中存储的核心,它实现了读写HDFS功能,一个HStore由一个MemStore 和0个或多个StoreFile组成。
    • MemStore是一个写缓存(In Memory Sorted Buffer),所有数据的写在完成WAL日志写后,会 写入MemStore中,由MemStore根据一定的算法将数据Flush到地层HDFS文件中(HFile),通常每个HRegion中的每个 Column Family有一个自己的MemStore。
    • HFile(StoreFile) 用于存储HBase的数据(Cell/KeyValue)。在HFile中的数据是按RowKey、Column Family、Column排序,对相同的Cell(即这三个值都一样),则按timestamp倒序排列。
    • FLUSH详述
    1. 每一次Put/Delete请求都是先写入到MemStore中,当MemStore满后会Flush成一个新的StoreFile(底层实现是HFile),即一个HStore(Column Family)可以有0个或多个StoreFile(HFile)。
    2. 当一个HRegion中的所有MemStore的大小总和超过了hbase.hregion.memstore.flush.size的大小,默认128MB。此时当前的HRegion中所有的MemStore会Flush到HDFS中。
    3. 当全局MemStore的大小超过了hbase.regionserver.global.memstore.upperLimit的大小,默认40%的内存使用量。此时当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush顺序是MemStore大小的倒序(一个HRegion中所有MemStore总和作为该HRegion的MemStore的大小还是选取最大的MemStore作为参考?有待考证),直到总体的MemStore使用量低于hbase.regionserver.global.memstore.lowerLimit,默认38%的内存使用量。
    4. 当前HRegionServer中WAL的大小超过了hbase.regionserver.hlog.blocksize * hbase.regionserver.max.logs的数量,当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush使用时间顺序,最早的MemStore先Flush直到WAL的数量少于hbase.regionserver.hlog.blocksize * hbase.regionserver.max.logs这里说这两个相乘的默认大小是2GB,查代码,hbase.regionserver.max.logs默认值是32,而hbase.regionserver.hlog.blocksize默认是32MB。但不管怎么样,因为这个大小超过限制引起的Flush不是一件好事,可能引起长时间的延迟

    六.HBASE优化

    6.1 高可用

    在HBase中Hmaster负责监控RegionServer的生命周期,均衡RegionServer的负载,如果Hmaster挂掉了,那么整个HBase集群将陷入不健康的状态,并且此时的工作状态并不会维持太久。所以HBase支持对Hmaster的高可用配置。

    1.关闭HBase集群(如果没有开启则跳过此步)

    [atguigu@hadoop102 hbase]$ bin/stop-hbase.sh

    2.在conf目录下创建backup-masters文件

    [atguigu@hadoop102 hbase]$ touch conf/backup-masters

    3.在backup-masters文件中配置高可用HMaster节点

    [atguigu@hadoop102 hbase]$ echo hadoop103 > conf/backup-masters

    4.将整个conf目录scp到其他节点

    [atguigu@hadoop102 hbase]$ scp -r conf/ hadoop103:/opt/module/hbase/

    [atguigu@hadoop102 hbase]$ scp -r conf/ hadoop104:/opt/module/hbase/

    6.2 预分区

    每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。

    1.手动设定预分区

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

    2.生成16进制序列预分区

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

    3.按照文件中设置的规则预分区

    创建splits.txt文件内容如下:

    aaaa

    bbbb

    cccc

    dddd

    然后执行:

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

    4.使用JavaAPI创建预分区

    //自定义算法,产生一系列Hash散列值存储在二维数组中

    byte[][] splitKeys = 某个散列值函数

    //创建HBaseAdmin实例

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

    //创建HTableDescriptor实例

    HTableDescriptor tableDesc = new HTableDescriptor(tableName);

    //通过HTableDescriptor实例和散列值二维数组创建带有预分区的HBase表

    hAdmin.createTable(tableDesc, splitKeys);

    6.3 RowKey设计

    一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。接下来我们就谈一谈rowkey常用的设计方案。

    1.生成随机数、hash、散列值

    比如:

    原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7

    原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd

    原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913

    在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

    2.字符串反转

    20170524000001转成10000042507102

    20170524000002转成20000042507102

    3.字符串拼接

    20170524000001_a12e

    20170524000001_93i7

    6.4 内存优化

    HBase操作过程中需要大量的内存开销,毕竟Table是可以缓存在内存中的,一般会分配整个可用内存的70%给HBase的Java堆。但是不建议分配非常大的堆内存,因为GC过程持续太久会导致RegionServer处于长期不可用状态,一般16~48G内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。

    6.5 基础优化

    1.允许在HDFS的文件中追加内容

    hdfs-site.xml、hbase-site.xml

    属性:dfs.support.append

    解释:开启HDFS追加同步,可以优秀的配合HBase的数据同步和持久化。默认值为true。

    2.优化DataNode允许的最大文件打开数

     

     

    hdfs-site.xml

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

    解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096

    3.优化延迟高的数据操作的等待时间

    hdfs-site.xml

    属性:dfs.image.transfer.timeout

    解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。

    4.优化数据的写入效率

    mapred-site.xml

    属性:

    mapreduce.map.output.compress

    mapreduce.map.output.compress.codec

    解释:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec或者其他压缩方式。

    5.设置RPC监听数量

    hbase-site.xml

    属性:hbase.regionserver.handler.count

    解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

    6.优化HStore文件大小

    hbase-site.xml

    属性:hbase.hregion.max.filesize

    解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。

    7.优化hbase客户端缓存

    hbase-site.xml

    属性:hbase.client.write.buffer

    解释:用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

    8.指定scan.next扫描HBase所获取的行数

    hbase-site.xml

    属性:hbase.client.scanner.caching

    解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

    9.flush、compact、split机制

    当MemStore达到阈值,将Memstore中的数据Flush进Storefile;compact机制则是把flush出来的小文件合并成大的Storefile文件。split则是当Region达到阈值,会把过大的Region一分为二。

    涉及属性:

    128M就是Memstore的默认阈值

    hbase.hregion.memstore.flush.size:134217728

    即:这个参数的作用是当单个HRegion内所有的Memstore大小总和超过指定值时,flush该HRegion的所有memstore。RegionServer的flush是通过将请求添加一个队列,模拟生产消费模型来异步处理的。那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发OOM。

    hbase.regionserver.global.memstore.upperLimit:0.4

    hbase.regionserver.global.memstore.lowerLimit:0.38

    即:当MemStore使用内存总量达到hbase.regionserver.global.memstore.upperLimit指定值时,将会有多个MemStores flush到文件中,MemStore flush 顺序是按照大小降序执行的,直到刷新到MemStore使用内存略小于lowerLimit

    ================================================================================

    以后博客的内容都是通过微信公众号链接的形式发布,之后迁移到公众号的文章都会重新修正,也更加详细,对于以前博客内容里面的错误或者理解不当的地方都会在公众号里面修正。

    欢迎关注我的微信公众号,以后我会发布更多工作中总结的技术内容。

    展开全文
  • hbase入门精讲

    2019-06-21 09:53:18
    通过学习hbase,掌握hbase的体系结构,集群安装,使用hbase shell访问hbase中的数据,使用hbase Java访问hbase,使用mapreduce把数据从HDFS中导入到hbase中,掌握过滤器等工具。
  • 1、什么是hbase HBASE是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群。 HBASE的目标是存储并处理大型的数据,更具体来说是仅需使用普通的...

    1、什么是hbase

    HBASE是一个高可靠性、高性能、面向列、可伸缩分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群。

    HBASE的目标是存储并处理大型的数据,更具体来说是仅需使用普通的硬件配置,就能够处理由成千上万的行和列所组成的大型数据。

    HBASE是Google Bigtable的开源实现,但是也有很多不同之处。比如:Google Bigtable利用GFS作为其文件存储系统,HBASE利用Hadoop HDFS作为其文件存储系统;Google运行MAPREDUCE来处理Bigtable中的海量数据,HBASE同样利用Hadoop MapReduce来处理HBASE中的海量数据;Google Bigtable利用Chubby作为协同服务,HBASE利用Zookeeper作为对应。

    2、与传统数据库的对比

    1、传统数据库遇到的问题:

    1)数据量很大的时候无法存储

    2)没有很好的备份机制

    3)数据达到一定数量开始缓慢,很大的话基本无法支撑

     2、HBASE优势:

    1)线性扩展,随着数据量增多可以通过节点扩展进行支撑

    2)数据存储在hdfs上,备份机制健全

    3)通过zookeeper协调查找数据,访问速度块。

    3、hbase集群中的角色

    1、一个或者多个主节点,Hmaster

    2、多个从节点,HregionServer

    4、hbase数据模型

    Row Key

    与nosql数据库们一样,row key是用来检索记录的主键。访问HBASE table中的行,只有三种方式:

    1.通过单个row key访问

    2.通过row key的range(正则)

    3.全表扫描

    Row key行键 (Row key)可以是任意字符串(最大长度 是 64KB,实际应用中长度一般为 10-100bytes),在HBASE内部,row key保存为字节数组。存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)

    Columns Family

    列簇 :HBASE表中的每个列,都归属于某个列族。列族是表的schema的一部 分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如 courses:history,courses:math都属于courses 这个列族。

    Cell

    由{row key, columnFamily, version} 唯一确定的单元。cell中 的数据是没有类型的,全部是字节码形式存贮。

    关键字:无类型、字节码

    Time Stamp

    HBASE 中通过rowkey和columns确定的为一个存贮单元称为cell。每个 cell都保存 着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由HBASE(在数据写入时自动 )赋值,此时时间戳是精确到毫秒 的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版 本冲突,就必须自己生成具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

    为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,HBASE提供 了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段 时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。

     5、hbase依赖zookeeper

    保存Hmaster的地址和backup-master地址

    hmaster:管理HregionServer , 做增删改查表的节点 , 管理HregionServer中的表分配

    保存表-ROOT-的地址

    hbase默认的根表,检索表。

    HRegionServer列表

    表的增删改查数据 , 和hdfs交互,存取数据。

    6、hbase原理

    体系图

    写流程

    client向hregionserver发送写请求。

    hregionserver将数据写到hlog(write ahead log)。为了数据的持久化和恢复。

    hregionserver将数据写到内存(memstore)

    反馈client写成功。

    数据flush过程

    当memstore数据达到阈值(默认是128M),将数据刷到硬盘,将内存中的数据删除,同时删除Hlog中的历史数据。

    并将数据存储到hdfs中。

    在hlog中做标记点。

    数据合并过程

    当数据块达到4块,hmaster将数据块加载到本地,进行合并

    当合并的数据超过256M,进行拆分,将拆分后的region分配给不同的hregionserver管理当hregionser宕机后,将hregionserver上的hlog拆分,然后分配给不同的hregionserver加载,修改.META.     

    注意:hlog会同步到hdfs

    hbase的读流程

    通过zookeeper和(-ROOT-,0.96之前有).META.表定位hregionserver。

    数据从内存和硬盘合并后返回给client

    数据块会缓存

    hmaster的职责

    管理用户对Table的增、删、改、查操作;

    记录region在哪台Hregion server上

    在Region Split后,负责新Region的分配;

    新机器加入时,管理HRegion Server的负载均衡,调整Region分布

    在HRegion Server宕机后,负责失效HRegion Server 上的Regions迁移。

    hregionserver的职责

    HRegion Server主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBASE中最核心的模块。

    HRegion Server管理了很多table的分区,也就是region。

    client职责

    Client

    HBASE Client使用HBASE的RPC机制与HMaster和RegionServer进行通信

    管理类操作:Client与HMaster进行RPC;

    数据读写类操作:Client与HRegionServer进行RPC。

    7、Hbase几个特点介绍

    海量存储

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

    列式存储

    这里的列式存储其实说的是列族存储,Hbase是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定。(通常建表会只建一个列簇,)

    极易扩展

    Hbase的扩展性主要体现在两个方面,一个是基于上层处理能力(RegionServer)的扩展,一个是基于存储的扩展(HDFS)。

    通过横向添加RegionSever的机器,进行水平扩展,提升Hbase上层的处理能力,提升Hbsae服务更多Region的能力。

    备注:RegionServer的作用是管理region、承接业务的访问,这个后面会详细的介绍

    通过横向添加Datanode的机器,进行存储层扩容,提升Hbase的数据存储能力和提升后端存储的读写能力。

    高并发

    由于目前大部分使用Hbase的架构,都是采用的廉价PC,因此单个IO的延迟其实并不小,一般在几十到上百ms之间。这里说的高并发,主要是在并发的情况下,Hbase的单个IO延迟下降并不多。能获得高并发、低延迟的服务。

    ​​​​​​​稀疏

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

    不足之处:

    对多表关联查询支持不够好,

    事物支持不好

    不支持sql(加大开发难度)

    8、Rowkey 设计

    热点问题

    数据后存储的,容易被访问

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

    为了避免写热点,设计 rowkey 使得 不同行在同一个 region,但是在更多数据情况下,数据应该被写入集群的多个region,而不是一个。下面是一些常见的避免 热点的方法以及它们的优缺点:

    加盐

    这里的加盐不是密码学中的加盐,而是在rowkey 的前面增加随机数。具体就是给 rowkey 分配一个随机前缀 以使得它和之前排序不同。分配的前缀种类数量应该和你想使数据分散到不同的 region 的数量一致。 如果你有一些 热点 rowkey 反复出现在其他分布均匀的 rwokey 中,加盐是很有用的。考虑下面的例子:它将写请求分散到多个 RegionServers,但是对读造成了一些负面影响。

    哈希

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

    翻转key

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

    单调递增 rwokey(时间连续序列)

    当所有客户端一段时间内一致写入某一个region,然后再接着写入下一个 region。例如:像单调递增的 rowkey(时间戳) ,就会发生这种现象。应该尽量避免这种设计。

    打散数据的数据+时间序列

    尽量减少行和列的大小

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

    大多时候较小的低效率是无关紧要的,但是在这种情况下,任何访问模式都需要列族名,列名,rowkey,所以它们会被访问数十亿次在你的数据中。

    列族越短越好

    尽可能使列族名越短越好,最好是一个字符。(例如:'d' 代表data/default)。属性名也是一样的。

    9、应用场景

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

    是巨量大(百TPB级别)

    查询简单(基于rowkey或者rowkey范围查询)

    不涉及到复杂的关联

    有几个典型的场景特别适合使用Hbase来存储:

    银行:历史账单,记录

    海量订单流水数据(长久保存)

    交易记录

    数据库历史数据

    展开全文
  • hbase

    2018-11-21 02:02:41
    HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统。  适合于存储大表数据(表的规模可以达到数十亿行以及数百万列),并且对大表数据的读、写访问可以达到实时级别;  利用Hadoop HDFS...

    一、hbase

    HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统。

     适合于存储大表数据(表的规模可以达到数十亿行以及数百万列),并且对大表数据的读、写访问可以达到实时级别;
     利用Hadoop HDFS(Hadoop Distributed File System)作为其文件存储系统,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统;
     利用ZooKeeper作为协同服务。

    与RMDB比较:

    HBase
    分布式存储,面向列。
    动态扩展列。
    普通商用硬件支持,扩容成本低。
    RMDB
    数据结构固定。
    需要预先定义好数据结构。
    需要大量IO,扩展成本大。

    HBase适合具有如下需求的应用:

    海量数据(TB、PB)
    高吞吐量
    需要在海量数据中实现高效的随机读取
    需要很好的性能伸缩能力
    能够同时处理结构化和非结构化的数据
    不需要完全拥有传统关系型数据库所具备的ACID特性

    数据结构介绍:

    结构化数据
     具有固定的结构,属性划分,以及类型等信息。我们通常所理解的关系型数据库中所存储的数据信息,大多是结构化数据, 如职工信息表,拥有ID、Name、Phone、Address等属性信息。
     通常直接存放在数据库表中。数据记录的每一个属性对应数据表的一个字段。
    非结构化数据
     无法用统一的结构来表示,如文本文件、图像、视频、声音、网页等信息。
     数据记录较小时(如KB级别),可考虑直接存放到数据库表中(整条记录映射到某一个列中),这样也有利于整条记录的快速检索。
     数据较大时,通常考虑直接存放在文件系统中。数据库可用来存放相关数据的索引信息。
    半结构化数据
     具有一定的结构,但又有一定的灵活可变性。典型如XML、HTML等数据。其实也是非结构化数据的一种。
     可以考虑直接转换成结构化数据进行存储。
     根据数据记录的大小和特点,选择合适的存储方式。这一点与非结构化数据的存储类似。

    行列存储:
    按行存储:
    : 数据按行存储在底层文件系统中。通常,每一行会被分配固定的空间。
     优点:有利于增加/修改整行记录等操作;有利于整行数据的读取操作;
     缺点:单列查询时,会读取一些不必要的数据。

    按列存储:
    数据以列为单位,存储在底层文件系统中。
     优点:有利于面向单列数据的读取/统计等操作。
     缺点:整行读取时,可能需要多次I/O操作。

    主键设置规则:

    这里写图片描述

    Secondary Index

     HBase是一个Key-Value类型的分布式存储数据库。每张表的数据,是按照RowKey的字典顺序排序的,因此,如果按照某个指定的RowKey去查询数据,或者指定某一个RowKey范围去扫描数据时,HBase可以快速定位到需要读取的数据位置,从而可以高效地获取到所需要的数据。
     在实际应用中,很多场景是查询某一个列值为XXX的数据。HBase提供了Filter特性去支持这样的查询,它的原理是:按照RowKey的顺序,去遍历所有可能的数据,再依次去匹配那一列的值,直到获取到所需要的数据。可以看出,可能仅仅为了获取一行数据,它却扫描了很多不必要的数据。因此,如果对于这样的查询请求非常频繁并且对查询性能要求较高,使用Filter无法满足这个需求。
    这就是HBase二级索引产生的背景。二级索引为HBase提供了按照某些列的值进行索引的能力。
    这里写图片描述
    一般HBase的查询都是通过RowKey(要把多条件组合查询的字段都拼接在RowKey中显然不太可能),或者全表扫描再结合过滤器筛选出目标数据(太低效),所以通过设计HBase的二级索引来解决这个问题。
    对于HBase而言,如果想精确地定位到某行记录,唯一的办法是通过rowkey来查询。如果不通过rowkey来查找数据,就必须逐行地比较每一列的值,即全表扫瞄。对于较大的表,全表扫瞄的代价是不可接受的。
    但是,很多情况下,需要从多个角度查询数据。例如,在定位某个人的时候,可以通过姓名、身份证号、学籍号等不同的角度来查询,要想把这么多角度的数据都放到rowkey中几乎不可能(业务的灵活性不允许,对rowkey长度的要求也不允许)。
    所以,需要secondary index来完成这件事。secondary index的原理很简单,但是如果自己维护的话则会麻烦一些。现在,Phoenix已经提供了对HBase secondary index的支持,下面将说明这样用Phoenix来在HBase中创建二级索引。
    create index my_index on example (m.c0);

    ###HBase FileStream
    HBase文件存储模块(HBase FileStream,简称HFS)是HBase的独立模块,它作为对HBase与HDFS接口的封装,应用在FusionInsight HD的上层应用,为上层应用提供文件的存储、读取、删除等功能。
    在Hadoop生态系统中,无论是HDFS,还是HBase,均在面对海量文件的存储的时候,在某些场景下,都会存在一些很难解决的问题:
     如果把海量小文件直接保存在HDFS中,会给NameNode带来极大的压力。
     由于HBase接口以及内部机制的原因,一些较大的文件也不适合直接保存到HBase中。
    HFS的出现,就是为了解决需要在Hadoop中存储海量小文件,同时也要存储一些大文件的混合的
    场景。简单来说,就是在HBase表中,需要存放大量的小文件(10MB以下),同时又需要存放一
    些比较大的文件(10MB以上)。
    HFS为以上场景提供了统一的操作接口,这些操作接口与HBase的函数接口类似。
    注意事项
     如果只有小文件,确定不会有大文件的场景下,建议使用HBase的原始接口进行操作。
     HFS接口需要同时对HBase和HDFS进行操作,所以客户端用户需要同时拥有这两个组件的操作权限。
     直接存放在HDFS中的大文件,HFS在存储时会加入一些元数据信息,所以存储的文件不是直接等于原文件的。不能直接从HDFS中移动出来使用,而需要用HFS的接口进行读取。
     使用HFS接口存储在HDFS中的数据,暂不支持备份与容灾。
    这里写图片描述

    HBASE+Solr全文检索

    背景
    某电信项目中采用HBase来存储用户终端明细数据,供前台页面即时查询。HBase无可置疑拥有其优势,但其本身只对rowkey支持毫秒级的快速检索,对于多字段的组合查询却无能为力。针对HBase的多条件查询也有多种方案,但是这些方案要么太复杂,要么效率太低,本文只对基于Solr的HBase多条件查询方案进行测试和验证。
    原理
    基于Solr的HBase多条件查询原理很简单,将HBase表中涉及条件过滤的字段和rowkey在Solr中建立索引,通过Solr的多条件查询快速获得符合过滤条件的rowkey值,拿到这些rowkey之后在HBASE中通过指定rowkey进行查询。
    这里写图片描述
    HBase与Solr系统架构设计
    使用HBase搭建结构数据存储云,用来存储海量数据;使用SolrCloud集群用来搭建搜索引擎,将要查找的结构化数据的ID查找出来,只配置它存储ID。
    这里写图片描述
    wd代表用户write data写数据,从用户提交写数据请求wd1开始,经历wd2,写入MySQL数据库,或写入结构数据存储云中,wd3,提交到Solr集群中,从而依据业务需求创建索引。
    rd代表用户read data读数据,从用户提交读数据请求rd1开始,经历rd2,直接读取MySQL中数据,或向Solr集群请求搜索服务,rd3,向Solr集群请求得到的搜索结果为ID,再向结构数据存储云中通过ID取出数据,最后返回给用户结果。

    实现方法有两种
    手工编码,直接用HBASE的API,可以参考下文
    http://www.cnblogs.com/chenz/articles/3229997.html
    可以使用HBASE/Solr的LUNA接口,就不用自己管理两者。
    这里写图片描述

    二、部署

    当我们按照hadoop完全分布式集群搭建博客搭建了hadoop以后,发现这是一个空的hadoop,只有YARN,MapReduce,HDFS,而这些实际上我们一般不会直接使用,而是需要另外部署Hadoop的其他组件,来辅助使用。比如我们需要数据库,那么hadoop提供了分布式非关系型数据库hbase,用来存储半结构化,非结构化的一些数据,供我们查询使用等,下面我们来介绍一下,如何实现在完全分布式hadoop集群之上安装hbase。

    操作步骤

    1. 下载hbase1.2.6压缩包

    hbase1.2.6下载地址
    下载后上传到管理节点的opt目录下

    2. 解压缩hbase和修改目录名

     # cd /opt
     # tar -xzvf hbase-1.2.6-bin.tar.gz
     # mv hbase-1.2.6 hbase1.2.6
     # chmod 777 -R /opt/hbase1.2.6
    

    3. 配置环境变量

     # vim /etc/profile
    
    export JAVA_HOME=/opt/jdk1.8
    export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    export PATH=$PATH:$JAVA_HOME/bin
    
    export HADOOP_HOME=/opt/hadoop2.6.0
    export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
    
    export HIVE_HOME=/opt/hive2.1.1
    export HIVE_CONF_DIR=$HIVE_HOME/conf
    export CLASSPATH=.:$HIVE_HOME/lib:$CLASSPATH
    export PATH=$PATH:$HIVE_HOME/bin
    
    export SQOOP_HOME=/opt/sqoop1.4.6
    export PATH=$PATH:$SQOOP_HOME/bin
    
    export ZOOKEEPER_HOME=/opt/zookeeper3.4.10
    export PATH=$PATH:$ZOOKEEPER_HOME/bin
    
    export HBASE_HOME=/opt/hbase1.2.6
    export PATH=$PATH:$HBASE_HOME/bin           #添加最后两行,hbase的相关环境变量属性
    
     # source /etc/profile              #使环境变量配置生效
    

    4. 修改hbase-env.sh配置文件

     # vim /opt/hbase1.2.6/conf/hbase-env.sh
    
    export JAVA_HOME=/opt/jdk1.8  
    export HADOOP_HOME=/opt/hadoop2.6.0 
    export HBASE_HOME=/opt/hbase1.2.6 
    export HBASE_CLASSPATH=/opt/hadoop2.6.0/etc/hadoop  
    export HBASE_PID_DIR=/opt/hbase1.2.6/pids  
    export HBASE_MANAGES_ZK=false
    

    这里写图片描述

    5. 修改hbase-site.xml配置文件

    # 创建目录
     # mkdir  /opt/hbase1.2.6/tmp  
     # mkdir  /opt/hbase1.2.6/pids 
    
     # cd /opt/hbase1.2.6/conf/
     # vim hbase-site.xml
    
    <configuration>
      <property>
        <name>hbase.rootdir</name>
        <value>hdfs://hadoop0:9000/hbase</value>
        <description>The directory shared byregion servers.</description>
      </property>
      <property>
        <name>hbase.zookeeper.property.clientPort</name>
        <value>2181</value>
        <description>Property from ZooKeeper'sconfig zoo.cfg. The port at which the clients will connect.
        </description>
      </property>
      <property>
        <name>zookeeper.session.timeout</name>
        <value>120000</value>
      </property>
      <property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop0,hadoop1,hadoop2</value>   
      </property>
      <property>
        <name>hbase.tmp.dir</name>
        <value>/opt/hbase1.2.6/tmp</value>
      </property>
      <property>
        <name>hbase.cluster.distributed</name>
       <value>true</value>
      </property>
    </configuration>
    

    6. 修改regionservers配置文件

     # cd /opt/hbase1.2.6/conf
     # vim regionservers        # 添加集群的三个主机名
     
    hadoop0
    hadoop1
    hadoop2
    

    7. 拷贝管理节点的hbase到其他两个节点

     # cd /opt/ 
     # scp -r hbase1.2.6 root@hadoop1:/opt/ 
     # scp -r hbase1.2.6 root@hadoop2:/opt/  
    
    # 修改环境变量添加【在其他两个节点】
    
    export HBASE_HOME=/opt/hbase1.2.6
    export PATH=$PATH:$HBASE_HOME/bin
    

    8. 启动和测试

    启动

    首先先确保,hadoop和zookeeper正常运行,然后只需要在管理节点启动Hbase即可。

     # cd /opt//hbase1.2.6/bin     
     # ./start-hbase.sh
    

    这里写图片描述

    浏览器访问:http://192.168.210.70:16010/master-status

    这里写图片描述

    测试

    在主节点命令行,输入hbase shell,启动hbase后台

    这里写图片描述

    三、注意

    在Hbase搭建完之后,本想开开心心的启动Hbase,进行测试使用hbase,但是发现启动hbase的时候,报各种各样的错误,java_home,hbase,hadoop等找不到文件或目录,no such file or directory!

    [root@hadoop0 bin]# start-hbase.sh 
    /opt/hbase1.2.6/conf/hbase-env.sh: line 50: export JAVA_HOME=/opt/jdk1.8: No such file or directory
    /opt/hbase1.2.6/conf/hbase-env.sh: line 52: export HBASE_HOME=/opt/hbase1.2.6: No such file or directory
    /opt/hbase1.2.6/conf/hbase-env.sh: line 53: export HBASE_CLASSPATH=/opt/hadoop2.6.0/etc/hadoop: No such file or directory
    /opt/hbase1.2.6/conf/hbase-env.sh: line 54: export HBASE_PID_DIR=/opt/hbase1.2.6/pids: No such file or directory
    starting master, logging to /opt/hbase1.2.6/logs/hbase-root-master-hadoop0.out
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
    hadoop0: /opt/hbase1.2.6/conf/hbase-env.sh: line 50: export JAVA_HOME=/opt/jdk1.8: No such file or directory
    hadoop0: /opt/hbase1.2.6/conf/hbase-env.sh: line 52: export HBASE_HOME=/opt/hbase1.2.6: No such file or directory
    hadoop0: /opt/hbase1.2.6/conf/hbase-env.sh: line 53: export HBASE_CLASSPATH=/opt/hadoop2.6.0/etc/hadoop: No such file or directory
    hadoop0: /opt/hbase1.2.6/conf/hbase-env.sh: line 54: export HBASE_PID_DIR=/opt/hbase1.2.6/pids: No such file or directory
    hadoop0: +======================================================================+
    hadoop0: |                    Error: JAVA_HOME is not set                       |
    hadoop0: +----------------------------------------------------------------------+
    hadoop0: | Please download the latest Sun JDK from the Sun Java web site        |
    hadoop0: |     > http://www.oracle.com/technetwork/java/javase/downloads        |
    hadoop0: |                                                                      |
    hadoop0: | HBase requires Java 1.7 or later.                                    |
    hadoop0: +======================================================================+
    hadoop2: /opt/hbase1.2.6/conf/hbase-env.sh: line 50: export JAVA_HOME=/opt/jdk1.8: No such file or directory
    hadoop2: /opt/hbase1.2.6/conf/hbase-env.sh: line 51: export HADOOP_HOME=/opt/hadoop2.6.0: No such file or directory
    hadoop2: /opt/hbase1.2.6/conf/hbase-env.sh: line 52: export HBASE_HOME=/opt/hbase1.2.6: No such file or directory
    hadoop2: /opt/hbase1.2.6/conf/hbase-env.sh: line 53: export HBASE_CLASSPATH=/opt/hadoop2.6.0/etc/hadoop: No such file or directory
    hadoop1: /opt/hbase1.2.6/conf/hbase-env.sh: line 50: export JAVA_HOME=/opt/jdk1.8: No such file or directory
    hadoop1: /opt/hbase1.2.6/conf/hbase-env.sh: line 51: export HADOOP_HOME=/opt/hadoop2.6.0: No such file or directory
    hadoop2: /opt/hbase1.2.6/conf/hbase-env.sh: line 54: export HBASE_PID_DIR=/opt/hbase1.2.6/pids: No such file or directory
    hadoop1: /opt/hbase1.2.6/conf/hbase-env.sh: line 52: export HBASE_HOME=/opt/hbase1.2.6: No such file or directory
    hadoop1: /opt/hbase1.2.6/conf/hbase-env.sh: line 53: export HBASE_CLASSPATH=/opt/hadoop2.6.0/etc/hadoop: No such file or directory
    hadoop2: /opt/hbase1.2.6/conf/hbase-env.sh: line 55: $'export\302\240HBASE_MANAGES_ZK=false': command not found
    hadoop1: /opt/hbase1.2.6/conf/hbase-env.sh: line 54: export HBASE_PID_DIR=/opt/hbase1.2.6/pids: No such file or directory
    hadoop1: /opt/hbase1.2.6/conf/hbase-env.sh: line 55: $'export\302\240HBASE_MANAGES_ZK=false': command not found
    hadoop2: +======================================================================+
    hadoop2: |                    Error: JAVA_HOME is not set                       |
    hadoop2: +----------------------------------------------------------------------+
    hadoop2: | Please download the latest Sun JDK from the Sun Java web site        |
    hadoop2: |     > http://www.oracle.com/technetwork/java/javase/downloads        |
    hadoop2: |                                                                      |
    hadoop2: | HBase requires Java 1.7 or later.                                    |
    hadoop2: +======================================================================+
    hadoop1: +======================================================================+
    hadoop1: |                    Error: JAVA_HOME is not set                       |
    hadoop1: +----------------------------------------------------------------------+
    hadoop1: | Please download the latest Sun JDK from the Sun Java web site        |
    hadoop1: |     > http://www.oracle.com/technetwork/java/javase/downloads        |
    hadoop1: |                                                                      |
    hadoop1: | HBase requires Java 1.7 or later.                                    |
    hadoop1: +======================================================================+
    

    解决方案

    # 查看hbase-env.sh文件
    
     # cd /opt/hbase1.2.6/conf
     # vim hbase-env.sh
    
    export HBASE_MANAGES_ZK=false
    export JAVA_HOME="/opt/jdk1.8"
    export HADOOP_HOME="/opt/hadoop2.6.0"
    export HBASE_HOME="/opt/hbase1.2.6"
    export HBASE_CLASSPATH="/opt/hadoop2.6.0/etc/hadoop"
    export HBASE_PID_DIR="/opt/hbase1.2.6/pids"
    
    # 上面这一块配置,全部重新手写,不要从网上复制过来直接黏贴,其中可能有中文字符,导致找不到环境变量
    

    修改后直接在主节点启动Hbase

     # start-hbase.sh    
    

    注:只需要在主节点上启动,从节点会自动全部开启hbase服务

    这里写图片描述

    这里写图片描述

    这里写图片描述

    四、自动关闭

    HBase启动后HMaster进程启动几秒后自动关闭
    产生错误的原因:zookeeper 链接信息过期了

    解决办法:进入zookeeper 删除hbase (rmr /hbase )重启zookeeper即可

    具体步骤:

    • 1、停止hbase(./stop-hbase.sh)
    • 2、hbase zkcli
    • 3、 ls / #扫描zookeeper中的数据
    • 4、 rmr / hbase #删除zookeeper中的hbase数据
    • 5、重新启动hbase即可

    五、python连hbase

    开启thrift:

    hbase thrift -p 9090 start
    ./hbase-daemons.sh start thrift

    代码测试

    from thrift.transport import TSocket,TTransport
    from thrift.protocol import TBinaryProtocol
    from hbase import Hbase
    
    # thrift默认端口是9090
    socket = TSocket.TSocket('192.168.186.48',9090)
    socket.setTimeout(5000)
    print("连接成功!")
    
    transport = TTransport.TBufferedTransport(socket)
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    
    client = Hbase.Client(protocol)
    socket.open()
    print(client.getTableNames())
    print(client.get('xmstest','xms','f1:name'))
    
    socket.close()
    
    展开全文
  • HBase基础知识

    2018-12-30 09:10:32
    1、HBase数据库介绍 1.1、产生背景 1.2、简介 1.3、表结构逻辑视图 1.3.1、行键(RowKey) 1.3.2、列簇(Column Family) 1.3.3、时间戳(TimeStamp) 1.3.4、单元格(Cell) 1.4、HBase应用场景 2、HBase...

    目录

    1、HBase数据库介绍

    1.1、产生背景

    1.2、简介

    1.3、表结构逻辑视图

    1.3.1、行键(RowKey)

    1.3.2、列簇(Column Family)

    1.3.3、时间戳(TimeStamp)

    1.3.4、单元格(Cell)

    1.4、HBase应用场景

    2、HBase集群结构

    3、HBase和Hive的比较

    3.1、相同点

    3.2、不同点

    4、HBase集群搭建

    4.1、安装步骤

    5、HBase命令行演示

    5.1、HBase命令使用初准备

    5.2、HBase命令使用实战

    6、HBase Java API 代码开发

    6.1、基本增删改查实现

    6.2、过滤器查询


    1、HBase数据库介绍

    1.1、产生背景

    自 1970 年以来,关系数据库用于数据存储和维护有关问题的解决方案。大数据的出现后,好多公司实现处理大数据并从中受益,并开始选择像 Hadoop 的解决方案。Hadoop 使用分布式文件系统,用于存储大数据,并使用 MapReduce 来处理。Hadoop 擅长于存储各种格式的庞大的数据,任意的格式甚至非结构化的处理。

    Hadoop 的限制
    Hadoop 只能执行批量处理,并且只以顺序方式访问数据。这意味着必须搜索整个数据集,即使是最简单的搜索工作。当处理结果在另一个庞大的数据集,也是按顺序处理一个巨大的数据集。在这一点上,一个新的解决方案,需要访问数据中的任何点(随机访问)单元。

    Hadoop 随机存取数据库
    应用程序,如 HBase,Cassandra,CouchDB,Dynamo 和 MongoDB 都是一些存储大量数据和以随机方式访问数据的数据库。

    Hadoop 的特点:
    对于任意格式的庞大数据集,Hadoop 可以做到安全存储但是对于需要在庞大数据集做针对于单条记录的增删改查是做不到的。

    Hive 的特点:
    对于存储在 HDFS 上的结构化的数据,如果增加一些描述这些数据的元数据信息,那么我们可以把存储在 HDFS 上的数据抽象成一张二维表格,使用 Hive 进行各种 Insert/Select 操作。但是 Hive 还是天生不支持对于单条记录的增删改查,也不是设计用来做单条记录的增删改查的。

    总结:
    1)海量数据量存储成为瓶颈,单台机器无法负载大量数据
    2)单台机器 IO 读写请求成为海量数据存储时候高并发大规模请求的瓶颈
    3)随着数据规模越来越大,大量业务场景开始考虑数据存储横向水平扩展,使得存储服务可以增加/删除,而目前的关系型数据库更专注于一台机器。

    重要问题探讨:如何设计一个能存储庞大数据集,同时也能做到实时增删改查的数据库系统?相当于设计一个 MySQL 的分布式版本。
    先解决这个问题,再来学习别人的成果,这是一种较好的学习方式。而不是一上来便学习别人的成功。须知:已掌握的知识会限制我们的思维方式。

    类似问题:
    1、如何设计一个分布式文件系统?
    2、如何设计一个分布式计算框架?
    3、如何设计一个分布式数据库?
    他们的难点是什么?

    思路引爆点:
    1、怎样快速判断一个元素在不在一个数据集中?布隆过滤器
    2、是否能找到一种合适的数据结构和搜索算法能快速从一个数据集中找出一个元素?二分查找
    3、如何设计分布式系统?网络编程模型(NIO RPC Netty)
    4、是否可以提前过滤不参与查询的数据,提高查询效率?列裁剪

    1.2、简介

    官网:http://hbase.apache.org/

    HBase 是 BigTable 的开源(源码使用 Java 编写)版本。是 Apache Hadoop 的数据库,是建立在 HDFS 之上,被设计用来提供高可靠性、高性能、列存储、可伸缩、多版本的 NoSQL的分布式数据存储系统,实现对大型数据的实时、随机的读写访问。

    HBase 依赖于 HDFS 做底层的数据存储,BigTable 依赖 Google GFS 做数据存储
    HBase 依赖于 MapReduce 做数据计算,BigTable 依赖 Google MapReduce 做数据计算
    HBase 依赖于 ZooKeeper 做服务协调,BigTable 依赖 Google Chubby 做服务协调

    与 Hadoop 一样,HBase 目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。所以,HBase 是一个通过大量廉价机器解决海量数据的高速存储和读取的分布式数据库解决方案

    NoSQL = NO SQL
    NoSQL = Not Only SQL:会有一些把 NoSQL 数据的原生查询语句封装成 SQL,比如 HBase 就有 Phoenix 工具

    关系型数据库 和 非关系型数据库的典型代表:
    NoSQL:HBase, Redis, MongoDB
    RDBMS:MySQL, Oracle, SQL Server, DB2

    以下5点是HBase这个NoSQL数据库的要点

    ① 高并发,可扩展,解决海量数据集的随机实时增删改查
    ② HBase 本质依然是 Key-Value 数据库,查询数据功能很简单,不支持 join 等复杂操作(可通过 Hive 支持来实现多表 join 等复杂操作)
    ③ 不支持复杂的事务,只支持行级事务
    ④ HBase 中支持的数据类型:byte[](底层所有数据的存储都是字节数组)
    ⑤ 主要用来存储结构化和半结构化的松散数据。

    结构化:数据结构字段含义确定,清晰,典型的如数据库中的表结构
    半结构化:具有一定结构,但语义不够确定,典型的如 HTML 网页,有些字段是确定的(title),有些不确定(table)
    非结构化:杂乱无章的数据,很难按照一个概念去进行抽取,无规律性

    HBase 中的表特点

    1、:一个表可以有上十亿行,上百万列
    2、面向列:列可以灵活指定,面向列(族)的存储和权限控制,列(簇)独立检索。
    3、稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏。
    4、无严格模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态的增加,同一张表中不同的行可以有截然不同的列

    关于存储系统的模式介绍:

    读模式:在读取数据的时候做模式校验,比如数据仓库 Hive
    写模式:在写入数据进入存储系统的时候做模式校验,比如 RDBMS

    1.3、表结构逻辑视图

    1、RDBMS 完全可以抽象成是一张二维表格,表由行和列组成。由行和列确定一个唯一的值
    2、HBase 本质是 key-value 数据库,key 是行健 rowkey,value 是所有真实 key-value 的集合
    3、HBase 可以抽象成为一张四维表格,四维分别由行健RowKey,列簇Column Family,列Column和时间戳Timestamp 组成。
    4、其中,一张 HBase 的所有列划分为若干个列簇 (Column Family)

    1.3.1、行键(RowKey)

    与 NoSQL 数据库们一样,RowKey 是用来检索记录的主键。访问 HBase Table 中的行,只有三种方式:
    1、通过单个 row key 访问
    2、通过 row key 的 range
    3、全表扫描

    RowKey 行键可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),最好是 16。在 HBase 内部,RowKey 保存为字节数组。HBase 会对表中的数据按照 rowkey 排序(字典顺序)

    存储时,数据按照 RowKey 的字典序(byte order)排序存储。设计 Key 时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)

    注意:
    字典序对 int 排序的结果是
    1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。
    要保持整形的自然序,行键必须用 0 作左填充。
    行的一次读写是原子操作(不论一次读写多少列)。这个设计决策能够使用户很容易的理解程序在对同一个行进行并发更新操作时的行为。
     

    1.3.2、列簇(Column Family)

    HBase 表中的每个列,都归属与某个列簇。列簇是表的 Schema 的一部分(而列不是),必须在创建表的时候指定。指定好了列簇就不能更改。列簇可以增加或者删除,删除的时候会删除这个列簇中的所有数据。

    列名都以列簇作为前缀。例如 courses:history,courses:math 都属于 courses 这个列簇。访问控制、磁盘和内存的使用统计等都是在列簇层面进行的。

    列簇越多,在取一行数据时所要参与 IO、搜寻的文件就越多,所以,如果没有必要,不要设置太多的列簇,官网推荐是小于等于 3(最好就一个列簇)。

    1.3.3、时间戳(TimeStamp)

    HBase 中通过 RowKey 和 Column 确定的为一个存储单元称为 Cell。每个 Cell 都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64 位整型。时间戳可以由 HBase (在数据写入时自动)赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个Cell 中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。HBase 在查询的时候,默认返回最新版本/最近的数据。如果需要读取旧版本的数据,可以指定时间戳。

    为了避免数据存在过多版本造成的的管理(包括存储和索引)负担,HBase 提供了两种数据版本回收方式:
    保存数据的最后 n 个版本
    保存最近一段时间内的版本(设置数据的生命周期 TTL)。

    用户可以针对每个列簇进行设置。

    1.3.4、单元格(Cell)

    由{RowKey, Column( =<Column Family> + <Qualifier>), Version} 唯一确定的单元。Cell 中的数据是没有类型的,全部是字节码形式存储。

    1.4、HBase应用场景

    1、半结构化或非结构化数据
    对于数据结构字段不够确定或杂乱无章很难按一个概念去进行抽取的数据适合用 HBase。而且 HBase 是面向列的,HBase 支持动态增加字段

    2、记录非常稀疏
    RDBMS 的行有多少列是固定的,为 null 的列浪费了存储空间。而 HBase 为 null 的 Column是不会被存储的,这样既节省了空间又提高了读性能。

    3、多版本数据
    对于需要存储变动历史记录的数据,使用 HBase 就再合适不过了。HBase 根据 Row key 和Column key 定位到的 Value 可以有任意数量的版本值。

    4、超大数据量的随机、实时读写
    当数据量越来越大,RDBMS 数据库撑不住了,就出现了读写分离策略,通过一个 Master 专门负责写操作,多个 Slave 负责读操作,服务器成本倍增。随着压力增加,Master 撑不住了,这时就要分库了,把关联不大的数据分开部署,一些 join 查询不能用了,需要借助中间层。随着数据量的进一步增加,一个表的记录越来越大,查询就变得很慢,于是又得搞分表,比如按 ID 取模分成多个表以减少单个表的记录数。经历过这些事的人都知道过程是多么的折腾。采用 HBase 就简单了,只需要加机器即可,HBase 会自动水平切分扩展,跟 Hadoop 的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性(MapReduce)。

    5、查询简单
    不涉及到复杂的 Join 查询,基于 RowKey 或者 RowKey 的范围查询

    2、HBase集群结构

    Region:是 HBase 将一个表中的所有数据按照 RowKey 的不同范围进行切割的逻辑单元,每个 Region 负责一定范围数据的读写访问。Region 由 RegionServer 负责管理。HBase 中的 Region的概念就和 HDFS 中的数据块的概念差不多,Region 是 HBase 表切分出来的一个分片。数据块是 HDFS 中的一个大文件切分出来的一个分片。

    HMaster:HBase 的主节点,负责整个集群的状态感知、负载分配、负责用户表的元数据(schema)管理(可以配置多个用来实现 HA),HMaster 负载压力相对于 HDFS 的 NameNode会小很多。HBase 的 HMaster 其实就算是宕机一段时间也可以正常对外提供服务的(要搞清楚为什么)。

    RegionServer:HBase 中真正负责管理 Region 的服务器,也就是负责为客户端进行表数据读写的服务器。每一台 RegionServer 会管理很多的 Region,一个 RegionServer 上面管理的所有的region不属于同一张表。负责Region的拆分,负责和底层的HDFS的存储交互,负责StoreFile的合并。

    ZooKeeper:整个 HBase 中的主从节点协调,元数据的入口,主节点之间的选举,集群节点之间的上下线感知……都是通过 ZooKeeper 来实现

    HDFS:用来存储 HBase 的系统文件,或者表的 Region 文件

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

    3、HBase和Hive的比较

    3.1、相同点

    1、HBase 和 Hive 都是架构在 Hadoop 之上,用 HDFS 做底层的数据存储,用 MapReduce 做数据计算

    3.2、不同点

    1、Hive 是建立在 Hadoop 之上为了降低 MapReduce 编程复杂度的 ETL 工具。
     HBase 是为了弥补 Hadoop 对实时操作的缺陷

    2、Hive 表是纯逻辑表,因为 Hive 的本身并不能做数据存储和计算,而是完全依赖 Hadoop
     HBase 是物理表,提供了一张超大的内存 Hash 表来存储索引,方便查询

    3、Hive 是数据仓库工具,需要全表扫描,就用 Hive,因为 Hive 是文件存储
     HBase 是数据库,需要索引访问,则用 HBase,因为 HBase 是面向列的 NoSQL 数据库

    4、Hive 表中存入数据(文件)时不做校验,属于读模式存储系统
     HBase 表插入数据时,会和 RDBMS 一样做 Schema 校验,所以属于写模式存储系统

    5、Hive 不支持单行记录操作,数据处理依靠 MapReduce,操作延时高
     HBase 支持单行记录的 CRUD,并且是实时处理,效率比 Hive 高得多

    4、HBase集群搭建

    4.1、安装步骤

    1、 安装 zookeeper 集群,此处略

    2、 找到官网下载 hbase 安装包 hbase-1.2.6-bin.tar.gz,这里给大家提供一个下载地址:
    http://mirrors.hust.edu.cn/apache/hbase/
    对应版本的官方文档:http://hbase.apache.org/1.2/book.html

    3、 上传安装包到服务器,并解压到对应的安装目录
    [hadoop@hadoop02 apps]# tar -zxvf hbase-1.2.6-bin.tar.gz -C /home/hadoop/apps/

    4、 修改配置文件

    1、修改运行环境配置环境
    [hadoop@hadoop02 conf]# vi hbase-env.sh
    修改两个两地方:
    export JAVA_HOME=/usr/local/java/jdk1.8.0_73,表示修改为自己的 jdk 目录
    export HBASE_MANAGES_ZK=false,表示不引用 hbase 自带的 zookeeper,用我们自己
    安装的
    保存退出

     

    2、修改集群配置文件:hbase-site.xml
    增加以下配置:
    <configuration>
     <property>
    <!-- 指定 hbase 在 HDFS 上存储的路径 -->
     <name>hbase.rootdir</name>
     <value>hdfs://myha01/hbase</value>
     </property>
     <property>
    <!-- 指定 hbase 是分布式的 -->
     <name>hbase.cluster.distributed</name>
     <value>true</value>
     </property>
     <property>
    <!-- 指定 zk 的地址,多个用“,”分割 -->
     <name>hbase.zookeeper.quorum</name>
     <value>hadoop03:2181,hadoop04:2181,hadoop05:2181</value>
     </property>
    </configuration>
    保存退出

     

    3、修改 regionservers
    vi regionservers

    hadoop02
    hadoop03
    hadoop04
    hadoop05

    4、修改 backup-masters(自行创建),指定备用的主节点
    该文件是不存在的,先自行创建:vi backup-masters

    hadoop05

    5、拷贝 hadoop 的核心配置文件过来
    最重要一步,要把 hadoop 的 hdfs-site.xml 和 core-site.xml 放到 hbase-1.2.6/conf 下
    cp ~/apps/hadoop-2.7.5/etc/hadoop/core-site.xml ~/apps/hbase-1.2.6/conf/
    cp ~/apps/hadoop-2.7.5/etc/hadoop/hdfs-site.xml ~/apps/hbase-1.2.6/conf/

    5、 分发安装到各节点
    scp -r hbase-1.2.6 hadoop03:/home/hadoop/apps/
    scp -r hbase-1.2.6 hadoop04:/home/hadoop/apps/
    scp -r hbase-1.2.6 hadoop05:/home/hadoop/apps/

    6、 别忘了同步时间!!!!!!!!
    HBase 集群对于时间的同步要求的比 HDFS 严格,所以,集群启动之前千万记住要进行时间同步,要求相差不要超过 30s 

    7、 配置环境变量
    vi ~/.bashrc
    添加两行:
    export HBASE_HOME=/home/hadoop/apps/hbase-1.2.6
    export PATH=$PATH:$HBASE_HOME/bin

    保存退出!!!别忘了执行 source ~/.bashrc,使配置生效

    8、 启动(顺序别搞错了)

    1、 先启动 zookeeper 集群
    zkServer.sh start

     

    2、 启动 hdfs 集群
    start-dfs.sh

     

    3、 启动 hbase
    保证 ZooKeeper 集群和 HDFS 集群启动正常的情况下启动 HBase 集群
    启动命令:start-hbase.sh

     

     

    观看启动日志可以看到:
    1、首先在命令执行节点启动 master
    2、然后分别在 hadoop02,hadoop03,hadoop04,hadoop05 启动 regionserver
    3、然后在 backup-masters 文件中配置的备节点上再启动了一个 master 主进程

    9、 查看启动是否正常,是否成功

    1、 检查各进程是否启动正常
    主节点和备用节点都启动 hmaster 进程
    各从节点都启动 hregionserver 进程

    按照对应的配置信息各个节点应该要启动的进程如上图所示

     

    2、 通过访问浏览器页面,格式为”主节点:16010”
    http://hadoop02:16010/

    10、如果有节点相应的进程没有启动,那么可以手动启动
    hbase-daemon.sh start master
    hbase-daemon.sh start regionserver 

    5、HBase命令行演示

    5.1、HBase命令使用初准备

    概述:大数据生态里的各种软件,基本都会给出 shell 命令行操作。所以在拿到新上手的软件的时候先找到怎么进入命令行,然后相应要想到 help 命令,查看命令帮助。别着急一股脑儿扎进去敲各种命令,这就是思路,思路很重要。

    下面按照我的思路来进行练习:

    1、先进入 hbase shell 命令行
    在你安装的随意台服务器节点上,执行命令:hbase shell,会进入到你的 hbase shell 客户端
    [root@hadoop01 ~]# hbase shell

    2、进入之后先别着急,先看一下提示。其实是不是有一句很重要的话:
    HBase Shell; enter 'help<RETURN>' for list of supported commands.
    Type "exit<RETURN>" to leave the HBase Shell
    意在告诉怎么获得帮助,怎么退出客户端
    help 获取帮助
    help 获取所有命令提示
    help "dml" 获取一组命令的提示
    help "put" 获取一个单独命令的提示帮助
    exit 退出 hbase shell 客户端

    重点关注类操作:DDL, DML

    3、语法规则

    名称 命令表达式
    创建表 create '表名称','列名称1','列名称2','列名称N'
    添加记录 put '表名称','行名称','列名称:','值'
    查看记录 get '表名称','行名称'
    查看表中的记录总数 count '表名称'
    删除记录 delete '表名','行名称','列名称'
    删除一张表 先要屏蔽该表,才能对表进行删除操作,第一步disable '表名称' 第二步 drop '表名称'
    查看所有记录 scan '表名称'
    查看某个表某个列中所有数据 scan '表名称',['列名称:']
    更新记录 就是重写一遍进行覆盖

    5.2、HBase命令使用实战

    1、显示 hbase 中的表列表:list

    2、创建表

    创建一张 hbase 表,表名叫做 user,该表有 info 和 data 两个列簇,注意,创建表的时候不 用指定列的信息,插入数据的时候才需要指定 key-value 的信息,这个 key 就是列

    create 'user', 'info', 'data'

    也可以这样写:

    create 'user',{NAME=>'info'},{NAME=>'data'}

    创建一张表叫做 user_info,包含两个列簇 base_info 和 extra_info,并且分别指定这两个列簇 的数据的版本数为 3 和 1

    create 'user_info',{NAME=>'base_info',VERSIONS=>3 },{NAME=>'extra_info',VERSIONS=>1}

    create 'user',{NAME=>'info',VERSIONS=>3 },{NAME=>'data',VERSIONS=>2}

    3、查看表的详细信息:desc 和 describe

    desc "user_info" 或者 describe "user_info"

    4、往表中插入数据:put

    向 user 表中插入信息,row key 为 rk0001,列簇 info 中添加 name 列标示符,值为 zhangsan

    put 'user', 'rk0001', 'info:name', 'zhangsan'

     

    向 user 表中插入信息,row key 为 rk0001,列簇 info 中添加 gender 列标示符,值为 female

    put 'user', 'rk0001', 'info:gender', 'female'

     

    向 user 表中插入信息,row key 为 rk0001,列簇 info 中添加 age 列标示符,值为 20

    put 'user', 'rk0001', 'info:age', 20

     

    向 user 表中插入信息,row key 为 rk0001,列簇 data 中添加 pic 列标示符,值为 picture

    put 'user', 'rk0001', 'data:pic', 'picture'

     

    再插入几条其他数据:

    put 'user', 'rk0002', 'info:name', 'fanbingbing'

    put 'user', 'rk0002', 'info:gender', 'female'

    put 'user', 'rk0002', 'info:nationality', '中国'

     

    插入一堆示例数据,以便后面测试:

    put 'user_info', 'user0000', 'base_info:name', 'luoyufeng'

    put 'user_info', 'user0000', 'base_info:age', '18'
    put 'user_info', 'user0000', 'base_info:gender', 'female'

    put 'user_info', 'user0000', 'extra_info:size', '34'

    put 'user_info', 'user0001', 'base_info:name', 'zhangsan'

    put 'user_info', 'user0001', 'base_info:name', 'luoyufeng'

    put 'user_info', 'user0001', 'base_info:name', 'zhangsan'

     

    put 'user_info', 'zhangsan_20150701_0001', 'base_info:name', 'zhangsan1'

    put 'user_info', 'zhangsan_20150701_0002', 'base_info:name', 'zhangsan2'

    put 'user_info', 'zhangsan_20150701_0003', 'base_info:name', 'zhangsan3'

    put 'user_info', 'zhangsan_20150701_0004', 'base_info:name', 'zhangsan4'

    put 'user_info', 'zhangsan_20150701_0005', 'base_info:name', 'zhangsan5'

    put 'user_info', 'zhangsan_20150701_0006', 'base_info:name', 'zhangsan6'

    put 'user_info', 'zhangsan_20150701_0007', 'base_info:name', 'zhangsan7'

    put 'user_info', 'zhangsan_20150701_0008', 'base_info:name', 'zhangsan8'

     

    put 'user_info', 'zhangsan_20150701_0001', 'base_info:age', '21'

    put 'user_info', 'zhangsan_20150701_0002', 'base_info:age', '22'

    put 'user_info', 'zhangsan_20150701_0003', 'base_info:age', '23'

    put 'user_info', 'zhangsan_20150701_0004', 'base_info:age', '24'

    put 'user_info', 'zhangsan_20150701_0005', 'base_info:age', '25'

    put 'user_info', 'zhangsan_20150701_0006', 'base_info:age', '26'

    put 'user_info', 'zhangsan_20150701_0007', 'base_info:age', '27'

    put 'user_info', 'zhangsan_20150701_0008', 'base_info:age', '28'

     

    put 'user_info', 'zhangsan_20150701_0001', 'extra_info:Hobbies', 'music'

    put 'user_info', 'zhangsan_20150701_0002', 'extra_info:Hobbies', 'sport'

    put 'user_info', 'zhangsan_20150701_0003', 'extra_info:Hobbies', 'music'

    put 'user_info', 'zhangsan_20150701_0004', 'extra_info:Hobbies', 'sport'

    put 'user_info', 'zhangsan_20150701_0005', 'extra_info:Hobbies', 'music'

    put 'user_info', 'zhangsan_20150701_0006', 'extra_info:Hobbies', 'sport'

    put 'user_info', 'zhangsan_20150701_0007', 'extra_info:Hobbies', 'music'

     

    put 'user_info', 'baiyc_20150716_0001', 'base_info:name', 'baiyc1'

    put 'user_info', 'baiyc_20150716_0002', 'base_info:name', 'baiyc2'

    put 'user_info', 'baiyc_20150716_0003', 'base_info:name', 'baiyc3'

    put 'user_info', 'baiyc_20150716_0004', 'base_info:name', 'baiyc4'

    put 'user_info', 'baiyc_20150716_0005', 'base_info:name', 'baiyc5'

    put 'user_info', 'baiyc_20150716_0006', 'base_info:name', 'baiyc6'

    put 'user_info', 'baiyc_20150716_0007', 'base_info:name', 'baiyc7'

    put 'user_info', 'baiyc_20150716_0008', 'base_info:name', 'baiyc8'

     

    put 'user_info', 'baiyc_20150716_0001', 'base_info:age', '21'

    put 'user_info', 'baiyc_20150716_0002', 'base_info:age', '22'

    put 'user_info', 'baiyc_20150716_0003', 'base_info:age', '23'

    put 'user_info', 'baiyc_20150716_0004', 'base_info:age', '24'

    put 'user_info', 'baiyc_20150716_0005', 'base_info:age', '25'

    put 'user_info', 'baiyc_20150716_0006', 'base_info:age', '26'

    put 'user_info', 'baiyc_20150716_0007', 'base_info:age', '27'

    put 'user_info', 'baiyc_20150716_0008', 'base_info:age', '28'

     

    put 'user_info', 'baiyc_20150716_0001', 'extra_info:Hobbies', 'music'

    put 'user_info', 'baiyc_20150716_0002', 'extra_info:Hobbies', 'sport'

    put 'user_info', 'baiyc_20150716_0003', 'extra_info:Hobbies', 'music'

    put 'user_info', 'baiyc_20150716_0004', 'extra_info:Hobbies', 'sport'

    put 'user_info', 'baiyc_20150716_0005', 'extra_info:Hobbies', 'music'

    put 'user_info', 'baiyc_20150716_0006', 'extra_info:Hobbies', 'sport'

    put 'user_info', 'baiyc_20150716_0007', 'extra_info:Hobbies', 'music'

    put 'user_info', 'baiyc_20150716_0008', 'extra_info:Hobbies', 'sport'

    4、查询数据:get

    获取 user 表中 row key 为 rk0001 的所有信息

    get 'user', 'rk0001'

     

    获取 user 表中 row key 为 rk0001,info 列簇的所有信息

    get 'user', 'rk0001', 'info'

     

    获取 user 表中 row key 为 rk0001,info 列簇的 name、age 列标示符的信息

    get 'user', 'rk0001', 'info:name', 'info:age'

     

    获取 user 表中 row key 为 rk0001,info 和 data 列簇的信息

    get 'user', 'rk0001', 'info', 'data'
    get 'user', 'rk0001', {COLUMN => ['info', 'data']}
    get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic']}

     

    获取 user 表中 row key 为 rk0001,列簇为 info,版本号最新 5 个的信息
    get 'user', 'rk0001', {COLUMN => 'info', VERSIONS => 2}
    get 'user', 'rk0001', {COLUMN => 'info:name', VERSIONS => 5}
    get 'user', 'rk0001', {COLUMN => 'info:name', VERSIONS => 5, TIMERANGE => [1392368783980, 1392380169184]}

    get 'user_info', 'user0001', {COLUMN => 'base_info:name', VERSIONS => 3}

     

    获取 user 表中 row key 为 rk0001,cell 的值为 zhangsan 的信息

    get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:图片')"}

     

    获取 user 表中 row key 为 rk0001,列标示符中含有 a 的信息

    get 'user', 'rk0001', {FILTER => "(QualifierFilter(=,'substring:a'))"}

    5、查询数据:scan

    查询 user_info 表中的所有信息

    scan 'user_info'

     

    查询 user_info 表中的指定列簇的所有信息
    scan 'user_info', {COLUMNS => 'base_info'}
    scan 'user_info', {COLUMNS => 'base_info:name'}
    scan 'user_info', {COLUMNS => ['base_info', 'extra_info']}

     

    查询 user_info 表中的指定列簇为 base_info 的所有版本信息
    scan 'user_info', {COLUMNS => 'base_info'} #只查询最新值

    scan 'user_info', {COLUMNS => 'base_info', VERSIONS => 5}

     

    查询 user 表中列簇为 info 和 data 的信息
    scan 'user', {COLUMNS => ['info', 'data']}
    scan 'user', {COLUMNS => 'info:name'}
    scan 'user', {COLUMNS => ['info:name', 'data:pic']}

     

    查询 user_info 表中列簇为 base_info、列标示符为 name 的信息,并且版本最新的 5 个

    scan 'user_info', {COLUMNS => 'base_info:name', VERSIONS => 5}

     

    查询 user 表中列簇为 info 和 data 且列标示符中含有 a 字符的信息
    scan 'user', {COLUMNS => ['info', 'data']}
    scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}

     

    查询表名为 user_info 表中列簇为 base_info,rowkey 的起始偏移范围是[baiyc_20150716_0003, baiyc_20150716_0006)的数据
    scan 'user_info', {COLUMNS => 'base_info', STARTROW => 'baiyc_20150716_0003', ENDROW => 'baiyc_20150716_0006'}

     

    查询 user 表中 rowkey 以 rk 字符开头的

    scan 'user', {FILTER=>"PrefixFilter('rk')"}

     

    查询 user_info 表中指定时间戳范围的数据
    scan 'user_info', {TIMERANGE => [1540882871681,1540882888540]}

    6、删除数据:delete

    删除记录
    delete 'user', 'rk0001' #不能一口气删除一个 rowkey 所对应的所有 key-value

     

    删除字段

    delete 'user', 'rk0001', 'info:name'

     

    删除 user_info 表 rowkey 为 user0000,列标示符为 info:name 的数据
    get 'user_info', 'user0000', 'base_info:name'
    delete 'user_info', 'user0000', 'base_info:name' #实现删除,其他两句为辅助测试语句

    put 'user_info', 'user0000', 'base_info:name', 'luoyufeng'

     

    删除 user 表 rowkey 为 rk0001,列标示符为 info:name,timestamp 为 1392383705316 的数据

    delete 'user', 'rk0001', 'info:name', 1392383705316

    7、修改表结构:alter

    添加两个列簇 f2 和 f3
    alter 'user_info', NAME => 'f2'

    alter 'user_info', NAME => 'f3'

     

    删除一个列簇 f2:
    alter 'user_info', NAME => 'f2', METHOD => 'delete'


    alter 'user_info', 'delete' => 'f2'

     

    添加列簇 f1 同时删除列簇 f3
    alter 'user_info', {NAME => 'f1'}, {NAME => 'f3', METHOD => 'delete'}

     

    将 user_info 表的 base_info 列簇版本号改为 5
    alter 'user_info', NAME => 'base_info', VERSIONS => 5

    8、修改数据

    严格来说,HBase 没有修改数据的显示操作,重复插入就相当于是修改操作

    9、清空表:truncate

    truncate 'user' #清空 user 表中的数据

    10、停用表/启用表:disable 和 enable

    disable 'user' #首先停用 user 表

    enable 'user' #启用表

    11、删除表

    disable 'user'  #删除前,先停用表

    drop 'user' #停用表之后才能删除

    12、过滤器操作

    过滤器
    get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:中国')"}

    get 'user', 'rk0001', {FILTER => "(QualifierFilter(=,'substring:a'))"}

     

    scan 'user', {COLUMNS => 'info:name'}

    scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}
    scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}
    scan 'user', {COLUMNS => 'info', STARTROW => '20140201', ENDROW => '20140301'}
    scan 'user', {COLUMNS => 'info:name', TIMERANGE => [1395978233636, 1395987769587]}

    6、HBase Java API 代码开发

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

    java类 HBase数据模型
    HBaseAdmin 数据库(DataBase)
    HBaseConfiguration
    HTable 表(Table)
    HTableDescriptor 列簇(Column Family)
    HColumnDescriptor
    Put 列修饰符(Column Qualifier)
    Get
    Delete
    Result
    Scan
    ResultScanner

    1、HBaseAdmin

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

    void addColumn(String tableName, HColumnDescriptor column) #向一个已经存在的表添加列

     

    void checkHBaseAvailable(HBaseConfiguratio n conf) #静态函数,查看 HBase是否处于运行状态

     

    void createTable(HTableDescriptor desc) #创建一个表,同步操作

     

    void deleteTable(byte[] tableName) #删除一个已经存在的表

     

    void enableTable(byte[] tableName) #使表处于有效状态

     

    void disableTable(byte[] tableName) #使表处于无效状态

     

    HTableDescriptor[] listTables() #列出所有用户空间表项

     

    void modifyTable(byte[] tableName, HTableDescriptor htd) #修改表的模式,是异步的 操作,可能需要花费一定 的时间

     

    boolean tableExists(String tableName) #检查表是否存在

     

    用法示例:

    HBaseAdmin admin = new HBaseAdmin(config);

    admin.disableTable("tablename")

    2、HBaseConfiguration

    关系:org.apache.hadoop.hbase.HBaseConfiguration

    作用:对 HBase 进行配置

    void addResource(Path file) #通过给定的路径所指的文件来添加资源

     

    void clear() #清空所有已设置的属性

     

    String get(String name) #获取属性名对应的值 

     

    String getBoolean(String name, boolean defaultValue) #获取为 boolean 类型的属性值,如果其属 性值类型部位 boolean,则返回默认属性值

     

    void set(String name, String value) #通过属性名来设置值

     

    void setBoolean(String name, boolean value) #设置 boolean 类型的属性值

     

    用法示例:

    HBaseConfiguration hconfig = new HBaseConfiguration();

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

    该 方 法 设 置 了 "hbase.zookeeper.property.clientPort" 的 端 口 号 为 2181 。 一 般 情 况 下 ,HBaseConfiguration 会使用构造函数进行初始化,然后在使用其他方法。

    3、HTableDescriptor

    关系:org.apache.hadoop.hbase.HTableDescriptor

    作用:包含了表的名字极其对应表的列簇

    void addFamily(HColumnDescriptor) #添加一个列簇

     

    HColumnDescriptor removeFamily(byte[] column) #移除一个列簇

     

    byte[] getName() #获取表的名字

     

    byte[] getValue(byte[] key) #获取属性的值

     

    void setValue(String key, String value) #设置属性的值

     

    用法示例:

    HTableDescriptor htd = new HTableDescriptor(table);

    htd.addFamily(new HcolumnDescriptor("family"));

    在上述例子中,通过一个 HColumnDescriptor 实例,为 HTableDescriptor 添加了一个列簇:family

    4、HColumnDescriptor

    关系:org.apache.hadoop.hbase.HColumnDescriptor

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

    byte[] getName() #获取列簇的名字

     

    byte[] getValue(byte[] key) #获取对应的属性的值

     

    void setValue(String key, String value) #设置对应属性的值

     

    用法示例:

    HTableDescriptor htd = new HTableDescriptor(tablename);

    HColumnDescriptor col = new HColumnDescriptor("content:");

    htd.addFamily(col);

    此例添加了一个 content 的列簇

    5、HTable

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

    void checkAdnPut(byte[] row, byte[] family, byte[] qualifier, byte[] value, Put put) #自动的检查row/family/qualifier 是否与给定的值匹配

     

    void close() #释放所有的资源或挂起内部缓冲区中的更新

     

    Boolean exists(Get get) #检查 Get 实例所指定的值是否存在于 HTable 的列中

     

    Result get(Get get) #获取指定行的某些单元格所对 应的值

     

    byte[][] getEndKeys() #获取当前一打开的表每个区域的结束键值

     

    ResultScanner getScanner(byte[] family) #获取当前给定列簇的 scanner实例

     

    HTableDescriptor getTableDescriptor() #获取当前表的HTableDescriptor 实例

     

    byte[] getTableName() #获取表名

     

    static boolean isTableEnabled(HBaseConfiguration conf, String tableName) #检查表是否有效

     

    void put(Put put) #向表中添加值

     

    用法示例:

    HTable table = new HTable(conf, Bytes.toBytes(tablename));

    ResultScanner scanner = table.getScanner(family);

    6、Put

    关系:org.apache.hadoop.hbase.client.Put

    作用:用来对单个行执行添加操作

    Put add(byte[] family, byte[] qualifier, byte[] value) #将指定的列和对应的值添加到Put 实例中

     

    Put add(byte[] family, byte[] qualifier, long ts, byte[] value) #将指定的列和对应的值及时间 戳添加到 Put 实例中

     

    byte[] getRow() #获取 Put 实例的行

     

    RowLock getRowLock() #获取 Put 实例的行锁

     

    long getTimeStamp() #获取 Put 实例的时间戳

     

    boolean isEmpty() #检查 familyMap 是否为空

     

    Put setTimeStamp(long timeStamp) #设置 Put 实例的时间戳

     

    用法示例:

    HTable table = new HTable(conf,Bytes.toBytes(tablename));

    Put p = new Put(brow);//为指定行创建一个 Put 操作

    p.add(family,qualifier,value);
    table.put(p);

    7、Get

    关系:org.apache.hadoop.hbase.client.Get

    作用:用来获取单个行的相关信息

    Get addColumn(byte[] family, byte[] qualifier) #获取指定列簇和列修饰符对应的列

     

    Get addFamily(byte[] family) #通过指定的列簇获取其对应的所有列

     

    Get setTimeRange(long minStamp,long maxStamp) #获取指定取件的列的版本号

     

    Get setFilter(Filter filter) #当执行 Get 操作时设置服务器端的过滤器

     

    用法示例:

    HTable table = new HTable(conf, Bytes.toBytes(tablename));

    Get g = new Get(Bytes.toBytes(row));

    8、Delete

    关系:org.apache.hadoop.hbase.client.Delete

    作用:用来封装一个要删除的信息

    9、Scan

    关系:org.apache.hadoop.hbase.client.Scan

    作用:用来封装一个作为查询条件的信息

    10、Result

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

    boolean containsColumn(byte[] family, byte[] qualifier) #检查指定的列是否存在

     

    NavigableMap<byte[],byte[] > getFamilyMap(byte[] family) #获取对应列簇所包含的修 饰符与值的键值对

     

    byte[] getValue(byte[] family, byte[] qualifier) #获取对应列的最新值

    11、ResultScanner

    关系:org.apache.hadoop.hbase.client.ResultScanner

    作用:存储 Scan 操作后获取表的单行值

    6.1、基本增删改查实现

    查看hbase-01中的资料!操作要认真写一遍。

    6.2、过滤器查询

    过滤器的类型很多,但是可以分为两大类——比较过滤器,专用过滤器。过滤器的作用是在服务端判断数据是否满足条件,然后只将满足条件的数据返回给客户端;

    hbase 过滤器的比较运算符:

    LESS <

    LESS_OR_EQUAL <=

    EQUAL =
    NOT_EQUAL <>

    GREATER_OR_EQUAL >=

    GREATER >
    NO_OP 排除所有

    HBase 过滤器的比较器(指定比较机制):

    BinaryComparator 按字节索引顺序比较指定字节数组,采用 Bytes.compareTo(byte[])

    BinaryPrefixComparator 跟前面相同,只是比较左端的数据是否相同
    NullComparator 判断给定的是否为空
    BitComparator 按位比较

    RegexStringComparator 提供一个正则的比较器,仅支持 EQUAL 和非 EQUAL

    SubstringComparator 判断提供的子串是否出现在 value 中。

    比较过滤器:

    行键过滤器 RowFilter

    Filter filter1 = new RowFilter(CompareOp.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("user0000")));
    scan.setFilter(filter1);

     

    列簇过滤器 FamilyFilter

    Filter filter1 = new FamilyFilter(CompareOp.LESS, new BinaryComparator(Bytes.toBytes("base_info")));
    scan.setFilter(filter1);

     

    列过滤器 QualifierFilter

    Filter filter = new QualifierFilter(CompareOp.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("name")));
    scan.setFilter(filter1);

     

    值过滤器 ValueFilter

    Filter filter = new ValueFilter(CompareOp.EQUAL, new SubstringComparator("zhangsan") );

    scan.setFilter(filter1);

     

    时间戳过滤器 TimestampsFilter

    List<Long> tss = new ArrayList<Long>();

    tss.add(1495398833002l);
    Filter filter1 = new TimestampsFilter(tss);

    scan.setFilter(filter1);

    专用过滤器:

    单列值过滤器 SingleColumnValueFilter----会返回满足条件的整行

    SingleColumnValueFilter filter = new SingleColumnValueFilter( Bytes.toBytes("colfam1"),Bytes.toBytes("col-5"), CompareFilter.CompareOp.NOT_EQUAL, new SubstringComparator("val-5"));

    filter.setFilterIfMissing(true); //如果不设置为 true,则那些不包含指定 column 的行也会返回

    scan.setFilter(filter1);

     

    单列值排除器 SingleColumnValueExcludeFilter -----返回排除了该列的结果与上面的结果相反

     

    前缀过滤器 PrefixFilter----针对行键

    Filter filter = new PrefixFilter(Bytes.toBytes("row1"));

    scan.setFilter(filter1);

     

    列前缀过滤器 ColumnPrefixFilter

    Filter filter = new ColumnPrefixFilter(Bytes.toBytes("qual2"));

    scan.setFilter(filter1);

     

    分页过滤器 PageFilter

    查看hbase-01中的资料!操作要认真写一遍。

    展开全文
  • HBase中的表一般有这样的特点: 1 大:一个表可以有上亿行,上百万列 2 面向列:面向列(族)的存储和权限控制,列(族)独立检索。 3 稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏。 ...
  • HBase详解(很全面)

    2020-03-19 17:53:56
    【转自:http://jiajun.iteye.com/blog/899632】一、简介historystarted by chad walters and jim2006.11 G release paper on BigTable2007.2 inital HBase prototype created as Hadoop contrib2007.10 First ...
  • hbase 详解

    2019-07-10 16:06:42
    1.hbase简介 1.1.什么是hbaseHBASE是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群。   HBASE的目标是存储并处理大型的数据,更具体来...
  • 目录   一、简介 二、HBase使用场景 2.1 历史数据存储类应用(约占七成) ... HBase - Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上...
  • 在本课程中,主要讲述了HBase详细的架构原理及特点、HBase内部各个角色的详细介绍、安装配置、HBase的Shell操作、新旧版本的读写数据详细流程、HBase的API操作、使用MapReduce以及Hive对HBase数据分析、Rowkey设计、...
  • 相信做大数据开发的朋友对hive和HBase一定不会陌生。 HBASE 想了解更多大数据相关知识可以点击“了解更多” Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql...
  • 这是HBase入门系列的第1篇文章,介绍HBase的数据模型、适用场景、集群关键角色、建表流程以及所涉及的HBase基础概念,本文内容基于HBase 2.0 beta2版本。本文既适用于HBase新手,也适用于已有一定经验的HBase开发...
  • 进入HBase数据库 # hbase shell 注意HBase Shell 中的回格键没用,要用【Ctrl+Backspace】,每个命令之后不需要分号(;)结束。 HBase帮助命令: hbase&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; help '...
  • HBase的高表和宽表

    2018-05-04 21:35:06
    HBase的高表和宽表hbase中的宽表是指很多列较少行,即列多行少的表,一行中的数据量较大,行数少;高表是指很多行较少列,即行多列少,一行中的数据量较少,行数大。hbase的row key是分布式的索引,也是分片的依据。...
  • HBase Shell 基本使用

    2019-04-10 16:17:11
    在上章, 我们尝试在本地安装了HBase. 本章, 我们主要了解下HBase Shell的基本使用. 基础知识 HBase是什么 在使用HBase之前, 我们先了解下HBase的几项基本知识. 与MySQL不同, HBase是面向列的数据库. 通常会将某些...
  • HBase并行写机制(mvcc)

    2018-12-10 00:06:26
    HBase在保证高性能的同时,为用户提供了便于理解的一致性数据模型MVCC (Multi Version Concurrency Control),即多版本并发控制技术,把数据库的行锁与行的多个版本结合起来,从而去提高数据库系统的并发性能。...
  • 访问hbase,以及操作hbase,命令不用使用分号 hbase shell 进入hbase list 查看表 hbase shell -d hbase(main):024:0> scan '.META.' =============小例子=============================================...
1 2 3 4 5 ... 20
收藏数 139,883
精华内容 55,953
关键字:

hbase