Hbase是什么?

Hbase/Hadoop Database

是什么

概念/定义

Hbase是一个分布式,可扩展,支持海量数据存储的noSQL数据库

优点

支持大量的数据存储

易拓展

自动切片,自动故

障转移

可以使用Java API编程

缺点

没有高级查询语句

延迟较MySql等关系型数据库大

需要分布式运行,需要一定的机器数量

名词解释

namespace 类似于mysql database

rowkey:每条数据的唯一标识,hbase中的数据按照rowkey字典序排序的(1 10 100 101 11 20 21)

region:hbase分布式存储的基础,,建表时由split语句可以各region所包含startkey和stopkey,进而划分为不同的region分到不同的服务器中。

列簇:一组列的集合,同一个表中,拥有相同数量的列簇,列簇中可以拥有不同数量的列,列簇中列的宽度是动态的,在插入数据时指定。

store:每个region的每个列簇存储成为一个store,作为基础文件单元

version :Hbase对数据的修改实际上是put(时间戳,new val),这个修改不会删除旧值,而是将新值的数据加入到表中,建立列簇时可以指定version的值,Hbase最多保存该值数量的最新历史数据。

cell:由rowkey,列簇,列名,时间戳 唯一确定的单元
Hbase是什么?

为什么

架构/原理/数据结构

Region Server

1.负责客户端的数据操作请求(DML)

2.region split,store file, compact

Master

1.监听Region Server服务器状态

2.在其故障时启动故障转移机制:在其他服务器上创建新的region,将元数据与实际存储在HDFS上的数据关联

3.负责Region Server的负载均衡

4.负责表结构的操作(DDL)

HDFS

为Hbase提供底层的数据存储服务,为Hbase提供高可用的支持

Zookeeper

1.Master的高可用

2.Region Server 的状态监听

元数据

hbase:meta这个表中存储了所有表的元数据,包括所有region所在的服务器,region的名称,以及时间戳。

flush触发条件

以下触发条件都会触发flush,但flush的最小单位是region,即每次触发flush都会flush该region的所有Store的MemStore,所以region的列簇不适合设置过多,工作中一般指定为1-2个

1.MemStore存储数据达到128M

2.region中所有的MemStore数据大小达到512M

3.RegionServer所有region的所有MemStore的数据总大小达到java_heap * 40% * 95%,此时会将当前RegionServer下的所有Region根据其所有MemStore占用大小排序,优先flush占用空间大的region

4.region距离上次flush已经达到一个小时

5.当WAL文件数量已经达到32个时

6.手动flush

标记删除

Hbase数据存储于HDFS上,并不能像关系型数据库一样随意删改,实际上的删除只是标记删除,使该值不可见,等到下次major Compact时才会真正的删除。

考虑:标记删除一个范围内的数据,然后又添加了该范围内的数据,新增数据会被删除吗?

Compact

Minor Compact

触发条件:小文件数达到3个时,会触发文件的合并

合并过程:合并时只是单纯的将多个小文件合并成一个大文件,不会删除或过滤过期版本。

合并结果:出现多个大文件

Major Compact

触发条件:7天一次

合并过程:将StoreFile的所有文件合并成一个大文件,会删除或过滤过期版本

合并结果:StoreFile下只有一个文件

Region Split

默认创建表时只有一个Region,而一个Region只能存在于一个RegionServer上,是不支持分布式的。Hbase的RegionServer会在Region数据达到一定时,自动切分,分裂Region,再由Master分配到不同的Server上。

0.9-2.0

分裂标准:min(10G(默认), memStore flush.size * RegionNum^2) RegionNum是该服务器下的该表的Region个数

写流程

Hbase是什么?

StoreFile

Hbase保存在HDFS上具体存储数据的物理文件,每个store每次flush内存区都会产生一个,以Hfile格式保存

MemStore

写入的缓存,写入数据时先存入MemStore内存区,并在区中排序,触发flush后将区中数据落盘

WAL

Write-Ahead logfile,预写日志。为了防止MemStore内存区中的数据丢失,写入时会先数据将写到预写日志,内存区flush完成后会删除预写日志中的相应内容。也便于故障转移后的恢复。

流程

1)Client先访问Zookeeper,获取hbase:meta表位于哪个RegionServer。

2)访问对应的RegionServer,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个RegionServer中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问(当触发负载平衡或故障转移后,需要重新缓存meta表)。

3)与目标RegionServer进行通讯;

4)将数据顺序写入(追加)到WAL;

5)将数据写入对应的MemStore,数据会在MemStore进行排序;

6)向客户端发送ack;

7)等达到MemStore的刷写时机后,将数据刷写到HFile。

读流程

1.向zk发起请求,找到meta表所在regionserver

2.zk返回meta所在的regionserver

3.向meta所在的regionserver请求读取meta

4.将读取到meta表缓存在内存中,方便下次读取,并从meta表中找到要读取数据所在的regionserver

5.从读缓存中查找数据

6.从memstore中查找数据

7.从StoreFile中查找数据

读缓存

由RegionServer负责缓存热数据,便于访问

怎么用

常用shell指令

DDL

create_namespace 创建一个namespace

list_namespace 显示所有namespace

list_namespace_tables 查看一个namespace下的所有表

describe 查看一个表的属性

disable 禁用一个表

enable 启用一个禁用的表

create 创建一个表

drop 删除一个空namespace 或一个禁用的表

DML

scan 扫描一个表

get 获取一个cell的值

put 添加行或修改行

delete 删除一个cell

deleteall 删除一行多个cell

count 统计表行数

truncate清空表

Java API

1.建立连接

conf = HBaseConfiguration.create();//创建conf配置对象
conf.set("hbase.zookeeper.quorum", "hadoop106,hadoop107,hadoop108");//设置zk地址
connection = ConnectionFactory.createConnection(conf);//建立连接
admin = connection.getAdmin();//注册用户

2.进行操作

DDL语言是admin对象来操作的

DML语言是table对象来操作的,获取table对象方法:

connection.getTable(TableName.valueOf("ns1_name:t1_name"));

3.关闭连接

table.close();
admin.close();
connection.close();

优化

预分区

默认创建表时,只会产生一个Region,此时读写都从这个Region负载,性能表现较差,我们可以通过预分区的方式,结合rowkey 的设计和数据的平衡,预分区出合适的分区,并尽量将这些负载压力平分到这些Region上(而不是由框架自动分区)

Rowkey设计优化

长度限制:太长的Rowkey会占用大量的空间

唯一原则:Rowkey必须是唯一确定的,不可重复

散列原则:单调递增的Rowkey是不够优化的,不论对于预分区来说,还是对于系统自动分区来说,大部分写负载都只在一个Region上进行。Rowkey必须是散列的,才能均匀分布于各个Region上。

Rowkey常用设计方案:

1.生成随机数前缀 (就是加盐salting)

2.取hash值做Rowkey(不能对可能重复值进行此操作)

3.时间戳反转

内存调整

适量增加RS占用的内存,能提高缓存能力,增加读写速度

Phoenix

是什么

Phoenix 的口号是:把SQl语句带给NOSQL数据库

它是apache 的一个开源框架,基于HBase,可以使用 JDBC API代替Hbase客户端API,以达到使用SQL操作Hbase的目的,Phoenix也支持二级索引。

Hbase是什么?

为什么

hbase作为nosql关系型数据库在存储数据时拥有能够海量存储的特点,但也丧失了关系型数据库通过索引来快速查找到所需数据的优点。使用Phoenix给数据建立索引可以达到通过索引快速查找数据的作用。

怎么用

配置环境

1.安装Phoenix

2.将安装目录下的phoenix-5.0.0-HBase-2.0-server.jar拷贝到Hbase的lib目录下

3.启动

bin/sqlline.py #启动客户端
bin/queryserver.py#启动服务器

SQL操作

与SQL类似,具体查看

Grammar | Apache Phoenix

API操作

1.添加依赖

<dependencies>
        <dependency>
            <groupId>org.apache.phoenix</groupId>
            <artifactId>phoenix-queryserver-client</artifactId>
            <version>5.0.0-HBase-2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>1.10.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2.加载对应JDBC

Class.forName("org.apache.phoenix.queryserver.client.Driver");

3.建立连接

connection = DriverManager.getConnection(url)

4.预定义语句

statement = connection.prepareStatement("upsert into person1 values(?,?)")//example
statement.setString(1,"100"+i);
statement.setString(2,"1100"+i);//填入参数
statement.execute();//直接执行
statement.executeBatch();//执行批处理
statement.executeUpdate();//执行更新
statement.executeQuery();//执行查询语句返回结果集
connection.commit();//事务提交

5.关闭资源

statement.close();
connection.close();

其他操作

加盐

create table person2(id varchar primary key , name varchar ) salt_buckets=4;

自动加盐,如果没有预分区,指定多少个bucket就会有多少个region

创建二级索引

全局二级索引

全局二级索引是在原表外新建了一个表,用来建立索引字段与其他字段(rowkey,可以包括其他,默认索引表rowkey为col_name_rowkey)的连接,当使用该索引字段进行查询时,会自动使用该索引表,但如果所建立的索引字段中不包括其他字段,仍会进行全表扫描。如建立了person表中name 的索引表,当查询字段包括age,而索引表中没有包括age,仍会进行全局扫描。(可以通过先从索引表找出rowkey,再从rowkey获取age?)

create index my_index on table_name(col_name)[include(col1_name)]#根据字段col_name创建全局二级索引 include 字段col1_name
本地二级索引

本地二级索引是在原表中插入一行对每一行源数据的映射,格式为__columnvalue__rowkey,索引表会被分到同一个region中,这样在读写时的效率都会很高,当根据索引查找字段时,会现根据索引找到rowkey 的值,再根据rowkey的值去找对应行的数据,所以可以查询出所有字段的值。

create local index my_index on table_name(col_name)# 根据字段col_name创建本地二级索引

事务

Hbase只提供了row级别的事务等级,Phoenix提供了跨表和跨行的事务

具体参见

Transactions (beta) | Apache Phoenix

UDF

User-defined functions(UDFs) | Apache Phoenix

上一篇:HBase MemStore


下一篇:JVM垃圾回收算法与垃圾收集器介绍二