hbase权威指南学习笔记

一、简介
1.列式存储数据库
以列为单位聚合数据,然后将列值顺序的存入磁盘,而传统数据库时为行式数据库,连续地存储整行
列式数据库:对于特定的查询,不需要所有的值,在分析型数据库最常见
1)关系型数据库存在的问题
高并发的解决步骤
增加用于读取的从服务器,将读写分离
增加缓存,如Memcached,但无法保证数据的一致性
将数据分区到多个数据库中,运维成本高。分区主要描述了逻辑上水平划分数据的方案,特点是将数据分文件或分服务器存储,而不是连续存储。数据的分区是在固定范围内实施的:在传入数据之前,必须提前划分好数据的存储范围

一致性模型:数据库必须保证每一步操作都是从一致的状态到下一个一致的状态
按照严格强度划分:
严格一致性:数据的变化是原子的,一经改变及时生效
顺序一致性:每个客户端看到的数据依照它们操作执行的顺序而变化
因果一致性:客户端以因果关系顺序观察到数据的改变
最终一致性:在没有更新数据的一段时间里,系统将通过广播早证副本之间的数据一致性
弱一致性:没有做出保证的情况下,所有的更新会通过广播的形式传递,展现给不同客户端的数据顺序可能是不一样

阻抗匹配:为一个给定问题找到一个理想的解决方案,除了使用通用的解决方案,还应该知道有什么可用的解决方案,从而找到最适合解决该问题的系统

2.表、行、列和单元格
最基本的单位是列,一列或多列形成一行,并由唯一的行健(row key)来确定存储,一个表有若干行,其中每列可能有多个版本,在每个单元格中存储了不同的值
一行由若干列组成,若干列又构成了一个列族,一个列族的所有列存储在同一个底层文件中,这个存储文件叫做HFile,列族需要在表创建的时候就定义好,常见的引用列的格式为family:qualifer,列族的数量有限制,但是列的数量没有限制,列值也没有长度和类型的限制
在Hbase中空值是没有任何消耗的,它们不占用任何的存储空间
每列或每个单元格的值都具有时间戳,默认由系统指定,也可以由用户显示设置
BigTable和Hbase的典型使用场景是webtable,存储从互联网中抓取的网页
行数据的存储操作都是原子的,可以读写任意数目的列,目前还不支持跨行事务和跨表事务

3.自动分区
Hbase中扩展和负载均衡的基本单元称为region,region本质上是以行健排序的连续存储的区间

4.存储API
API提供了建表、删表、增加列族和删除列族的操作,同时还提供了修改表和列族元数据的功能
scanAPI提供了高效遍历某个范围的行的功能
在服务器的地址空间中执行来自客户端的代码,支持这种功能的服务器框架叫做协处理器(coprocessor)

5.实现
每次更新数据时,都会先将数据记录在提交日志上(commit log)中,在Hbase中这叫预写日志(write-ahead log,WAL),然后才将这些数据写入内存中的memstore中,到超过给定的最大值值,就写到磁盘的HFile文件,HFile是不可被改变的
合并HFile机制
minor合并:将多个小文件(默认最小3个,最大10个)重写到数据较少的大文件中,每个HFile都是经过归类的,所以合并的速度很快,只受磁盘IO的影响
major合并:将一个region中一个列族的若干个HFile重写到一个新的HFile中,major合并能扫描所有的键值对,顺序重写全部的数据

二、客户端API:基础知识
1.概述
Hbase主要的客户端接口是有org.apache.hadoop.hbase.client包中的HTable提供的HTable类提供的,通过这个类用户可以向Hbase存储和检索数据
所有修改数据的操作都保证了行级别的原子性
创建HTable实例是有代价的,每个实例都需要扫描.META.表,以检查该表是否存在,是否可用,以及一些其他操作,因此推荐用户在每个线程(在开始时)只创建一次HTable实例,而后在客户端应用的生存期内复用这个对象,如果用户需要使用多个HTable实例,应考虑使用HTablePool类
Hable(Configuration conf,"tableName")

2.CRUD操作
2.CRUD操作
2.1 put方法:向Hbase存储数据
1)调用HTable的put方法格式:
void put(Put put)或void put(List<put> puts)
Put对象的构造方法如下
创建Put实例之后,就可以使用add方法
向该实例添加数据了,每一次调用add()都可以特定的添加一列数据,如果再加上一个时间戳选项,就能形成一个数据单元格。每个KeyValue实例包含器完成地址(行健、列族、列以及时间戳)和实际数据,KeyValue是Hbase在存储架构中最底层的类
可以使用如下方法检查是否存在特定的单元格,而不需要遍历整个集合
通过客户端访问配置文件
当你调用任何一个静态create()方法时,代码会尝试使用当前的java classpath来载入两个配置文件hbase-default.xml和hbase-site.xml

Hbase的一个特殊功能是能为一个单元格存储多个版本的数据,这个版本使用一个时间戳,必须确保所有服务器的时间都是正确的,并且相互之间是同步的,默认情况下Hbase会保留3个版本的数据
若需要频繁的修改某些行,用户有必要创建一个RowLock实例来防止其他用户访问这些行

2)KeyValue类
数据和坐标都是以java的byte[]形式存储的,使用这种类型的目的是允许存储任意类型的数据

3)客户端的写缓冲区
每一个put操作实际上都是一个RPC操作,它将客户端数据传送到服务器后返回,这只适合小数据量的操作,Hbase的API配备了一个客户端的写缓冲区(write buffer),缓冲区负责收集put操作,然后调用RPC操作一次性将put送往服务器,全局交换机制控制着该缓冲区是否在使用,其方法如下
void setAutoFlush(boolean autoFlush)
默认情况下,客户端缓冲区是禁用的,可以通过将autoflush设置为false来激活缓冲区,通过setBufferSize(long size)来配置客户端写缓冲区的大小,默认大小是2M,为每一个用户创建的HTable实例都设置缓冲器大小十分麻烦,可以在hbase-site.xml中添加一个较大的预设值,配置如下
<property>
<name>hbase.client.write.value</name>
<value>20971520</value>
</property>

当需要强制把数据写到服务器端时,用flushCommit()函数
隐式刷写:在用户调用put()或setBufferSize()时触发,这两个方法都会将目前占用的缓冲区大小和用户配置的缓冲区大小进行比较,此外调用HTable的close()也会无条件地隐式刷写
用户可以通过访问ArrayList<Put> getWriteBuffer()来访问客户端写缓冲区的内容
如果用户只存储大单元格,那么客户端缓冲区的作用就不大了
4)Put列表
调用void put(List<put> puts)时,客户端先把所有的Put实例插入到本地写缓冲区中,然后隐式的调用flushCache(),如果其中有失败的Put实例(有些检查是在客户端完成的,如确认Put实例的内容是否为null或是否指定了列),那么后面的Put实例不会被添加到缓冲区,也不会触发刷写命令,当使用基于列表的Put调用时,用户需要特别注意:用户无法控制服务器执行put的顺序,如果要保证写入的顺序,需要小心地使用这个操作。

5)原子性操作compare-and-set
有一种特别的put调用,其能保证自身操作的原子性:checkAndPut(row,family,qualifier,value,Put put),这种有原子性的操作经常被用于账户结余,状态转换或数据处理等场景
有一种特别的检查通过checkAndPut()调用来完成,即只有在另外一个值不存在的情况下,才执行这个修改,要执行这种操作只需要将参数value设置为null
Hbase提供的compare-and-set操作,只能检查和修改同一行数据

2.2 get方法:客户端获取已存储数据的方法
Result get(Get get);
1)单行Get
构造Get实例:
Get(rowkey)
Get(rowkey,RowLock rowLock)
可以通过多种标准筛选目标数据:
Get addFamily(family):只能取得一个指定的列族
Get addColumn(family,qualifier):获取指定的列
Get setTimeRange(long minStamp,long masStamp)、
Get setTimeStamp(long timeStamp)
Get setMaxVersions(int maxVersions)

2)result类
get()返回的结果包含所有匹配的单元格数据,被封装成一个Result类
常用方法:
byte[] getValue(family,qualifier):取得特定单元格的值
byte[] value():返回第一列对应的最新单元格的值
byte[] getRow():返回行健
int size():检查是否有对应的记录
boolean isEmpty():检查是否有对应的记录
KeyValue[] raw()
List<KeyValue> list():用户可以方便的迭代数据
List<KeyValue> getColumn(family,qualifier)
KeyValue getColumnLatest(family,qualifier)
boolean containsColumn(family,qualifier)
NavigableMap<byte[],NavigableMap[],NavigableMap<Long,byte[]>>> getMap():把请求返回的内容都装入一个Map类实例中,可以遍历所有结果

3)get列表
Result[] get(List<Get> gets);
boolean exists(Get get):查看存储的数据是否存在
getRowOrBefore(row,family):

2.3 删除方法
1)单行删除
void delete(Delete delete)
Delete实例构造方法
Delete(rowkey)
Delete(rowkey,long timestamp,RowLock rowLock)
常用方法
Delete deleteFamily(family[,long timestamp])
Delete deleteColumns(family,qualifier[,long timestamp]):没指定timestamp,则删除所有版本
Delete deleteColumn(family,qualifier[,long timestamp]):没指定timestamp,则删除最新版本

2)Delete的列表
void delete(List<Delete> deletes)

3)原子性操作compare-and-delete
boolean checkAndDelete(row,qualifier,value,Delete delete)

2.4批处理操作
事实上许多基于列表的操作都是基于batch()方法是实现的。
方法:
void batch(List<Row> actions,Object[] results)
Object[] batch(List<Row> actions)
注:不可以将针对同一行数据的Put和Delete操作放在同一个批处理请求中
Row是Put、Get、Delete类的父类
当用户使用batch()功能时,Put实例不会被客户端写入缓冲区中缓冲,batch()请求是同步的,会把操作直接发送给服务器
两种方法相同点:
get、put、delete操作都支持,如果执行时出现问题,客户端将抛出异常并报告问题,都不适用客户端的写缓冲区
不同点:
void batch(acitons,results):能访问成功操作的结果,同时也可以获取远程失败的异常
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值