Hbase/Hadoop Database
是什么
概念/定义
Hbase是一个分布式,可扩展,支持海量数据存储的nosql数据库
优点
支持大量的数据存储
易拓展
障转移
可以使用Java API编程
缺点
没有高级查询语句
需要分布式运行,需要一定的机器数量
名词解释
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,列簇,列名,时间戳 唯一确定的单元
为什么
架构/原理/数据结构
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已经达到一个小时
6.手动flush
标记删除
Hbase数据存储于HDFS上,并不能像关系型数据库一样随意删改,实际上的删除只是标记删除,使该值不可见,等到下次major Compact时才会真正的删除。
考虑:标记删除一个范围内的数据,然后又添加了该范围内的数据,新增数据会被删除吗?
Compact
Minor Compact
合并过程:合并时只是单纯的将多个小文件合并成一个大文件,不会删除或过滤过期版本。
合并结果:出现多个大文件
Major Compact
触发条件:7天一次
合并过程:将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个数
写流程
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下的所有表
enable 启用一个禁用的表
create 创建一个表
DML
scan 扫描一个表
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常用设计方案:
2.取hash值做Rowkey(不能对可能重复值进行此操作)
3.时间戳反转
内存调整
Phoenix
是什么
它是apache 的一个开源框架,基于HBase,可以使用 JDBC API代替Hbase客户端API,以达到使用sql操作Hbase的目的,Phoenix也支持二级索引。
为什么
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类似,具体查看
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。