设为首页 加入收藏

TOP

Hadoop生态圈(十):Hbase
2019-04-26 01:32:06 】 浏览:43
Tags:Hadoop 生态 Hbase

目录

1 Hbase概述

1.1 什么是Hbase

1.2 Hbase特点

1.3HBase架构

1.4HBase中的角色

1.4.1 HMaster

1.4.2 RegionServer

1.4.3 其他组件

2 Hbase安装

2.1 环境准备

2.2 下载安装

2.3 Hbase服务的启动

2.4 查看Hbase的WEBUI界面

3 Hbase Shell操作

3.1 基本操作

3.2 表的操作

4 Hbase数据结构

4.1 RowKey

4.2 Column Family

4.3 Time Stamp

4.4命名空间

5 Hbase原理

6 HbaseAPI操作

6.1 HbaseAPI

7 Hbase优化

7.1 高可用(high available)

7.2RowKey设计

7.3预分区

7.4 内存优化


1 Hbase概述

1.1 什么是Hbase

HBase的原型是Google的BigTable论文,受到了该论文思想的启发,目前作为Hadoop的子项目来开发维护。

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

-- 2006年Google发表BigTable白皮书

-- 2006年开始开发HBase

-- 2008年北京成功开奥运会,程序员默默地将HBase弄成了Hadoop的子项目

-- 2010年HBase成为Apache顶级项目

-- 现在很多公司二次开发出了很多发行版本,你也开始使用了。

->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作为对应。

Zk:ha使用过自动故障转移;kafka存储元数据(集群的元数据+消费者的元数据)

1.2 Hbase特点

1海量存储

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

2列式存储

->这里的列式存储其实说的是列族存储,Hbase是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定。

3极易扩展

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

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

备注:RegionServer的作用是管理region、承接业务的访问,这个后面会详细的介绍,通过横向添加Datanode的机器,进行存储层扩容,提升Hbase的数据存储能力和提升后端存储的读写能力。

4高并发

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

5稀疏

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

1.3HBase架构

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

1Client

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

2Zookeeper

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

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

通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知Master RegionServer上下线的信息(就是使用zk完成的服务器上下线机制

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

3Hmaster

master节点的主要职责如下:

(1)为RegionServer分配Region
(2)维护整个集群的负载均衡
(3)维护集群的元数据信息
(4)发现失效的Region,并将失效的Region分配到正常的RegionServer上
(5)当RegionSever失效的时候,协调对应Hlog的拆分

4HregionServer

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

5HDFS

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

1.4HBase中的角色

1.4.1 HMaster

功能

  1. 监控RegionServer
  2. 处理RegionServer故障转移
  3. 处理元数据的变更
  4. 处理region的分配或转移
  5. 在空闲时间进行数据的负载均衡
  6. 通过Zookeeper发布元数据的位置给客户端

1.4.2 RegionServer

功能

  1. 负责存储HBase的实际数据
  2. 处理分配给它的Region
  3. 刷新缓存到HDFS
  4. 维护Hlog(每个regionserver都有一个Hlog)
  5. 执行压缩
  6. 负责处理Region分片(自动分片)

1.4.3 其他组件

1.Write-Ahead logs(WAL,HLOG&edits日志)

HBase的修改记录,当对HBase读写数据的时候,数据不是直接写进磁盘,它会在内存中保留一段时间(时间以及数据量阈值可以设定)。但把数据保存在内存中可能有更高的概率引起数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入内存中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。

2.Region

Hbase表的分片,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。

3.Store

HFile存储在Store中,一个Store对应HBase表中的一个列族。

4.MemStore

顾名思义,就是内存存储,位于内存中,用来保存当前的数据操作,所以当数据保存在WAL中之后,RegsionServer会在内存中存储键值对。

5.HFile

这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以HFile的形式存储在HDFS的。

2 Hbase安装

2.1 环境准备

(1)zookeeper正常部署:保证zookeeper的正常部署,并启动zookeeper集群

(2)Hadoop正常部署:保证Hadoop集群的正常部署,并启动hdfs和yarn

2.2 下载安装

1)下载:

官方网站:http://hbase.apache.org/downloads.html

网盘链接:请点这里 提取码:cgf7

2)上传并安装

(1)将现在的Hbase安装包上传到hadoop101节点/opt/modoule/目录下,配置完成后再分发到其他节点

(2)解压Hbase到指定目录:

[root@hadoop101 software]# tar -zxvf hadoop-2.7.2.tar.gz -C /opt/module/

(3)修改conf目录下的配置文件:

1)修改hbase-env.sh,添加以下内容:

export JAVA_HOME=/opt/module/jdk1.8.0_144

export HBASE_MANAGES_ZK=false

2)hbase-site.xml修改内容如下:

<configuration>

<property>

<name>hbase.rootdir</name>

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

</property>

<property>

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

<value>true</value>

</property>

<!--0.98后的新变动,之前版本没有port,默认端口为60000 -->

<property>

<name>hbase.master.port</name>

<value>16000</value>

</property>

<property>

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

<value>hadoop101:2181,hadoop102:2181,hadoop103:2181</value>

</property>

<property>

<name>hbase.zookeeper.property.dataDir</name>

<value>/opt/module/zookeeper-3.4.10/zkData</value>

</property>

</configuration>

3)修改regionservers:

hadoop101

hadoop102

hadoop103

4)软连接hadoop配置文件到hbase:

[root@hadoop101 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/core-site.xml /opt/module/hbase-1.3.1/conf/core-site.xml

[root@hadoop101 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/hdfs-site.xml /opt/module/hbase-1.3.1/conf/hdfs-site.xml

5)将配置好的Hbase分发到其他节点

2.3 Hbase服务的启动

1)启动方式1:

[root@hadoop101 hbase]$ bin/hbase-daemon.sh start master

[root@hadoop101 hbase]$ bin/hbase-daemon.sh start regionserver

可能出现的问题:如果集群之间的节点时间不同步,会导致regionserver无法启动,抛出ClockOutOfSyncException异常。

解决方案:

a、同步时间服务

b、属性:hbase.master.maxclockskew设置更大的值

<property>

<name>hbase.master.maxclockskew</name>

<value>180000</value>

<description>Time difference of regionserver from master</description>

</property>

2)启动方式2:

[root@hadoop101 hbase]$ bin/start-hbase.sh

[root@hadoop101 hbase]$ bin/stop-hbase.sh //对应的停止服务

2.4 查看Hbase的WEBUI界面

启动成功后,可以通过“host:port”的方式来访问HBase管理页面,例如:http://hadoop101:16010

3 Hbase Shell操作

3.1 基本操作

1.进入HBase客户端命令行(任意节点均可)

[root@hadoop101 hbase]$ bin/hbase shell

2.查看帮助命令

hbase(main):001:0> help

3.查看当前数据库中有哪些表

hbase(main):002:0> list

3.2 表的操作

1.创建表

hbase(main):002:0> create 'student','info' (单双引号无所谓)

2.插入数据到表

hbase(main):003:0> put 'student','1001','info:sex','male'

hbase(main):004:0> put 'student','1001','info:age','18'

hbase(main):005:0> put 'student','1002','info:name','Janna'

hbase(main):006:0> put 'student','1002','info:sex','female'

hbase(main):007:0> put 'student','1002','info:age','20'

3.扫描查看表数据

hbase(main):008:0> scan 'student'

hbase(main):009:0> scan 'student',{STARTROW => '1001', STOPROW => '1002'}

hbase(main):010:0> scan 'student',{STARTROW => '1001'}

4.查看表结构

hbase(main):011:0> describe 'student'

5.更新指定字段的数据

hbase(main):012:0> put 'student','1001','info:name','Nick'

hbase(main):013:0> put 'student','1001','info:age','100'

6.查看“指定行”或“指定列族:列”的数据

hbase(main):014:0> get 'student','1001'

hbase(main):015:0> get 'student','1001','info:name'

7.统计表数据行数

hbase(main):021:0> count 'student'

8.删除数据

删除某rowkey的全部数据:

hbase(main):016:0> deleteall 'student','1001'

删除某rowkey的某一列数据:

hbase(main):017:0> delete 'student','1002','info:sex'

9.清空表数据(表结构还在)

hbase(main):018:0> truncate 'student'

提示:清空表的操作顺序为先disable,然后再truncate。

10.删除表

首先需要先让该表为disable状态:

hbase(main):019:0> disable 'student'

然后才能drop这个表:

hbase(main):020:0> drop 'student'

提示:如果直接drop表,会报错:ERROR: Table student is enabled. Disable it first.

11.变更表信息

将info列族中的数据存放3个版本:

hbase(main):022:0> alter 'student',{NAME=>'info',VERSIONS=>3}

hbase(main):022:0>get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3}

4 Hbase数据结构

4.1 RowKey

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

  1. 通过单个RowKey访问
  2. 通过RowKey的range
  3. 全表扫描

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

4.2 Column Family

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

4.3 Time Stamp

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

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

4.4命名空间

命名空间的结构:

1) Table:表,所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定,则在default默认的命名空间中。

2) RegionServergroup:一个命名空间包含了默认的RegionServerGroup。

3) Permission:权限,命名空间能够让我们来定义访问控制列表ACL(Access Control List)。例如,创建表,读取表,删除,更新等等操作。

4) Quota:限额,可以强制一个命名空间可包含的region的数量。

5 Hbase原理

可以参考我的另一篇文章:https://blog.csdn.net/jiezou12138/article/details/88677006

6 HbaseAPI操作

首先添加下面的依赖:

<dependency>

<groupId>org.apache.hbase</groupId>

<artifactId>hbase-client</artifactId>

<version>1.3.1</version>

</dependency>

6.1 HbaseAPI

package com.bigdata;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class HbaseTest {

    private Configuration conf;

    @Before
    public void init() {
        conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", "192.168.1.102");
        conf.set("hbase.zookeeper.property.clientPort", "2181");
    }

    /**
     * use_case:判断Hbase表是否存在
     * @throws IOException
     */
    @Test
    public void testExists() throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);

        HBaseAdmin hBaseAdmin = (HBaseAdmin) conn.getAdmin();

        boolean exists = hBaseAdmin.tableExists(TableName.valueOf("student"));
        System.out.println("=========================>>>" + exists);

        hBaseAdmin.close();
        conn.close();
    }

    /**
     * use_case:创建Hbase表
     */
    @Test
    public void testCreateTable() throws IOException {
        //1.获取连接对象
        Connection connection = ConnectionFactory.createConnection(conf);
        //2.通过连接获取Hbase的客户端对象
        HBaseAdmin hBaseAdmin = (HBaseAdmin) connection.getAdmin();
        //3.创建表描述器
        HTableDescriptor student = new HTableDescriptor(TableName.valueOf("student1"));
        //4.设置列组描述器
        student.addFamily(new HColumnDescriptor("info"));
        //5.执行创建操作
        hBaseAdmin.createTable(student);
        System.out.println("====================>>>student表创建成功了");

        hBaseAdmin.close();
        connection.close();
    }

    /**
     * use_case:删除hbase表
     */
    @Test
    public void testDeleteTable() throws IOException {
        //1.获取连接对象
        Connection conn = ConnectionFactory.createConnection(conf);
        //2.通过连接对象获取Hbase的客户端对象
        HBaseAdmin admin = (HBaseAdmin) conn.getAdmin();
        //3.先设置表位不可用
        admin.disableTable("student1");
        //4.删除表
        admin.deleteTable("student1");

        admin.close();
        conn.close();
    }

    /**
     * use_case:向表中插入一条数据
     */
    @Test
    public void testInsert() throws IOException {
        Connection connection = ConnectionFactory.createConnection(conf);
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        //获取一个表对象
        Table student = connection.getTable(TableName.valueOf("student"));
        //设置rowkey
        Put put = new Put(Bytes.toBytes("1106"));
        //设置列组、列、列值
        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("Rose"));
        //执行插入
        student.put(put);

        student.close();
        admin.close();
        connection.close();
    }

    /**
     * use_case:向表中插入多条数据
     */
    @Test
    public void testInserts() throws IOException {
        Connection connection = ConnectionFactory.createConnection(conf);
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        //获取一个表对象
        Table student = connection.getTable(TableName.valueOf("student"));
        List<Put> list = new ArrayList<>();
        Put put1 = new Put(Bytes.toBytes("1106"));
        put1.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("Rose"));

        Put put2 = new Put(Bytes.toBytes("1106"));
        put2.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"), Bytes.toBytes("16"));

        Put put3 = new Put(Bytes.toBytes("1106"));
        put3.addColumn(Bytes.toBytes("info"), Bytes.toBytes("sex"), Bytes.toBytes("female"));

        list.add(put1);
        list.add(put2);
        list.add(put3);
        student.put(list);

        student.close();
        admin.close();
        connection.close();
    }

    /**
     * use_case:删除一行或多行数据
     */
    @Test
    public void testDelete() throws IOException {
        Connection connection = ConnectionFactory.createConnection(conf);
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();

        Table student = connection.getTable(TableName.valueOf("student"));
        Delete delete = new Delete(Bytes.toBytes("1106"));
        Delete delete1 = new Delete(Bytes.toBytes("1107"));
        List<Delete> list = new ArrayList<>();
        list.add(delete);
        list.add(delete1);
        student.delete(list);

        student.close();
        admin.close();
        connection.close();
    }

    /**
     * use_case:获取所有数据
     */
    @Test
    public void testScan() throws IOException {
        Connection connection = ConnectionFactory.createConnection(conf);
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();

        Table student = connection.getTable(TableName.valueOf("student"));

        ResultScanner scanner = student.getScanner(new Scan());
        for (Result result : scanner) {
            Cell[] cells = result.rawCells();
            for (Cell cell : cells) {
                String row = Bytes.toString(CellUtil.cloneRow(cell));
                String cf = Bytes.toString(CellUtil.cloneFamily(cell));
                String column = Bytes.toString(CellUtil.cloneQualifier(cell));
                String value = Bytes.toString(CellUtil.cloneva lue(cell));
                System.out.println("row:" + row + " column:" + row + ":" + column + "   value=" + value);
            }
        }
        student.close();
        admin.close();
        connection.close();
    }

    /**
     * use_case:获取某一行的数据,指定列族,列
     */
    @Test
    public void testGet() throws IOException {

        Connection connection = ConnectionFactory.createConnection(conf);
        Table student = connection.getTable(TableName.valueOf("student"));
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        //创建查询的get对象
        Get get = new Get(Bytes.toBytes("1105"));
        //指定要查询的列族的指定列
        //get.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));
        //Result result = student.get(get);

        //查询指定的列族
        get.addFamily(Bytes.toBytes("info"));
        Result result = student.get(get);
        Cell[] cells = result.rawCells();
        for (Cell cell : cells) {
            String row = Bytes.toString(CellUtil.cloneRow(cell));
            String cf = Bytes.toString(CellUtil.cloneFamily(cell));
            String column = Bytes.toString(CellUtil.cloneQualifier(cell));
            String value = Bytes.toString(CellUtil.cloneva lue(cell));
            System.out.println("row:" + row + " column:" + row + ":" + column + "   value=" + value);
        }
        student.close();
        admin.close();
        connection.close();
    }
}

7 Hbase优化

7.1 高可用(high available)

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

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

[root@hadoop101 hbase-1.3.1]$ bin/stop-hbase.sh

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

[root@hadoop101 hbase-1.3.1]$ touch conf/backup-masters

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

[root@hadoop101 hbase-1.3.1]$ echo hadoop103 > conf/backup-masters

4.将backup-masters分发到其他节点

5.启动集群并打开页面测试查看

7.2RowKey设计

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

注意:RowKey如何设计必须结合实际业务场景

设计原则可参考下面两篇博文:

https://www.cnblogs.com/yuguoshuo/p/6265649.html

https://blog.csdn.net/b6ecl1k7BS8O/article/details/82754169

7.3预分区

每一个region维护着startRowKey与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。
注意:手动分区(预分区)需要对业务数据量有把控

1.手动设定预分区

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

7.4 内存优化

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

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇5 hbase-shell +   hbase.. 下一篇Hbase架构   Hbase Region的..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目