1.HBase基础
什么是HBase数据库:
- Hadoop数据库,NoSQL数据库
- 稀疏的、分布式的、持久化的、多维有序映射的
- 基于行键(rowkey),列键(column key)、时间戳(timestamp)
- 键值(key value)存储、面向列族的数据库
- 可以存储结构化和非结构化数据
- 不允许跨行事务
HBase主要使用场景
- 抓取增量数据
- 抓取监控指标:OpenTSDB
- 抓取用户交互数据
- 遥测技术:捕获和存储用户计算机上生成的软件崩溃报告
- 广告效果和点击流
- 内容服务
- 用户生成内容
- 内容管理系统(Content Management System,CMS)
- URL短连接
- 用户模型服务
- 信息交换
基本操作
1.建表
HBase的表按照行(row)和列(column)来组织。列组成列族(column family),HBase表至少有一个列族。
create 'users', 'info'
2.插入/查询数据
put 'users', 'row1', 'info:a', 'true'
get 'users', 'row1'
JAVA API
1.建立连接
//HBase客户端配置信息
Configuration con = HBaseConfiguration.create();
//配置访问HBase地址和端口
con.set("hbase.zookeeper.quorum","serverip");
con.set("hbase.zookeeper.property.clientPort","2222");
//建立连接
tyr(Connection conn = ConnectionFactory.createConnection(con)){
//获取HBase表
try(Table table = conn.getTable(TableName.valueOf("users"))){
//扫描
Scan scan = new Scan();
scan.addFamily("cf".getBytes());
ResultScanner scanner = table.getScanner(scan);
for(Result result : scanner ){
//输出行键
System.out.println(new String(result.getRow()));
}
}
} catch (IOException e){
e.printStackTrace();
}
2.数据操作
HBase表的行有唯一标识符,叫做行键(rowkey)。其他部分用来存储HBase表里的数据。
HBase中所有数据都是作为原始数据(raw data)使用字节数组的形式存储的。
HBase用坐标来定位表数据,第一个坐标是行键,下一个是列族,再下一个是列限定符(column qualifier),简称为列(column),最后是时间版本。
【rowkey,column family,column qualifier,version】4个坐标确定了单元(cell)的位置。HBase中数据作为值存储在单元里。
- Put:增加行/修改行
Put put = new Put(Bytes,toBytes(rowKey));
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("message"),Bytes.toBytes("true"));
table.put(put);
- Get
Get get = new Get(Bytes.toBytes("tablename"));
Result result = table.get(get);
//指定列
get.addColumn(Bytes.toBytes("info"),Bytes.toBytes("message"));
//指定列族
get.addFamily(Bytes.toBytes("info"));
- Delete
Delete d new Delete(Bytes.toBytes("tableName"));
d.addColumn(Bytes.toBytes("info"),Bytes.toBytes("message"));
table.delete(d);
2.工作机制
1.HBase写路径
在HBase中无论是增加新行还是修改已有的行,其内部流程是相同的。HBase接到命令后存下变化信息,或者写入失败抛出异常。
默认情况下,执行写入时会写入到两个地方:**预写式日志(write-ahead log,WAL,也称HLog)**和 MemStore。
只有当这两个地方的变化信息都写入并确认后,才认为写动作完成。
MemStore是内存里的写入缓冲区,HBase中数据在永久写入硬盘之前在这里积累。当MemStore填满后,其中数据会写到硬盘,生成一个HFile(HBase底层存储格式)。
HFile对应于列族,一个列族可以有多个HFile。但一个HFile不能存储多个列族的数据。在集群的每个节点上,每个列族有一个MemStore。
问题/故障:MemStore还没有刷写,服务器就崩溃了,内存中没有写入硬盘的数据就会丢失
HBase处理办法:
- 写入动作之前先写入WAL。
- 直到WAL新记录成功写入后,写入动作才被认为成功完成。
- 没有从MemStore里刷写到HFile的数据将可以通过回放WAL来恢复
- HBase集群中每台服务器维护一个WAL来记录发生的变化。这台服务器上的所有表共享这个WAL。
- WAL是底层文件系统上的一个文件。
路径:客户端–>WAL–>MemStore–>HFile
2.HBase读路径
HBase读动作必须重新衔接持久化到硬盘上HFile和内存中MemStore里的数据。在读操作上使用LRU(最近最少使用算法)缓存技术。这种缓存也叫做BlockCache,和MemStore在一个JVM堆里。BlockCache设计用来保存从HFile里读入内存的频繁访问数据,避免硬盘读。每个列族都有自己的BlockCache。
BlockCache中的Block是HBase从硬盘完成一次读取的数据单位。HFile物理存放形式是一个Block序列外加这些Block索引。从HBase里读取一个Block需要先在索引上查找一次该Block,然后从硬盘读出。
Block是建立索引的最小数据单位,也是从硬盘读取的最小数据单位。
Block大小安装列族设定,默认值是64KB。
如果主要用于随机查询,需要细粒度的Block索引,小一点的Block更好。Block变小会导致索引变大,进而消耗更多内存。
如果经常执行顺序扫描,一次读取多个Block,大点的Block更好。Block变大意味着索引项变少,索引变小,因此节省内存。
路径:首先会检查MemStore等待修改的队列,然后检查BlockCache看包含改行的Block是否最近被访问过,最后访问硬盘上对应的HFile。
注意:HFile存在某个时刻MemStore刷写的快照,一个完整行的数据可能存放在多个HFile里。为了读出完整行,HBase可能需要读取包含该行信息的所有HFile。
3.HBase删除
**Delete命令并不会立即删除内容。实际上,它只是给记录打上删除的标记(“墓碑”记录)。**墓碑记录用来标记删除的内容不能在GET和SCAN命令中返回。因为HFile文件是不能改变的,直到执行一次大合并,这些墓碑记录才会被处理,被删除记录占用的空间才被释放。
合并分为两种:
- 大合并(major compaction)
同时处理一个列族的全部HFile,**大合并是HBase清理被删除记录的唯一机会。**因为小合并不能保证被删除的记录和墓碑标记记录在一个HFile里面。而大合并可以确保同时访问到两种记录。 - 小合并(minorco compaction)
从已有的Hfile里读出记录,合并到一个HFile。然后新HFile标记为权威数据,删除老HFile
拓展
ACID
- Atomicity(原子性):原子性是指原子不可分的操作属性,换句话说,要么全部完成要么全部不完成。如果操作成功,整个操作成功。如果操作失败,整个操作失败。
- Consistency(一致性):一致性是指把系统从一个有效状态带入另一个有状态的操作属性。如果操作使系统出现不一致,操作不会被执行或者回退。
- Isolation(隔离性):隔离性意味着两个操作的执行是互不干扰的。
- Durability(持久性):意味着数据一旦写入,确保可以读回并且不会在系统正常操作一段时间后丢失。
在线系统和离线系统
在线系统:需要低延迟。某些情况下,系统哪怕给出没有答案的响应,都比花很长时间给出正确答案的响应好。
离线系统:不需要低延迟。用户可以等待答案,不期待马上给出响应。
JRuby:是在java运行时上面的Ruby编程语言的实现。除了正常Rudy语法,JRuby支持访问Java对象和函数库。
MemStore的大小由hbase-site.xml文件里的系统级属性hbase.hregion.memstore.flush.size来定义。