LSM-tree模型
概念: Log-Struct-Merge 模型树,即wal,flush,compaction,split等过程;
功能: 将随机无序的数据变成有序的数据,通过有序的算法来加快数据的读取,因为写入时需要进行排序,所有牺牲了一定的写入数据的效率,都用内存来实现数据的读写的存储
-
主要步骤:
- 请求时现将数据保存到预写日志,然后写入内存
- 在内存中对数据进行排序
- 将内存中的数据写入文件,构成一个有序数据文件
- 合并: 将有序的多个数据文件进行合并生成一个新的有序的文件
- 删除和更新: 在模型设计中,本身并没有删除和更新,通过插入来模拟的,一般都是在文件合并时来进行实际的物理删除操作
WAL
- 概念: 预写日志, write-ahead-log
- 职责: 当产生写的请求后,写请求提交给regionserver,regionserver会将这个写的操作记录在WAL中,即Hlog,然后再写入memstore
- 存储: 将WAL存储在hdfs上,每台regionserver维护一份WAL,
- 场景: 用于数据恢复,hfile由hdfs恢复,memstore由WAL恢复
- 补充:
oldwals: 不再被需要的Hlog日志文件
Flush
- 概念: 刷写
- 功能: 数据在memstore中先做一次按rowkey的字典顺序排序,然后将memstore中的数据写入持久化到hdfs上,会生成一个有序的storefile文件
- 场景: 由于memstore是使用的内存,内存容量有限,为了提高新数据的命中率,需要将老的数据吸入hdfs进行安全存储
Compaction
- 概念: 合并
- 功能: 将hdfs上的多个storefile文件进行合并,构建统一的有序文件
- 场景: 为提供文件的快速读取,将多个storefile文件合并成一个整体有序的storefile文件,因为读取多个数据源没有读取一个数据源快
- 过程:
minor compaction: 将hdfs上早些生成的一些文件进行合并
major compaction: 将所有的文件进行合并,合并的过程中会将标记为删除或过期的数据真正的删除
Split
- 概念: 分裂
- 功能: 若一个region分区的数据过多,会分裂成两个region
- 场景: 一个分区的数据过多时,就会容易造成服务端引起的热点问题,无法实现分布式高性能,此时由regionserver将这一个分区均分为两个分区,由master重新将两个分区分配到不同的regionserver中,分配成功后旧的region下线
数据加载
-
概念: 将数据导入到hbase中,有两种实现方式。
-
“使用put对象”
- 例如: hbase shell,java api,mr程序封装
- 缺点: 数据流经过WAL,然后经过内存,最后再到hdfs上,当导入海量数据是,容易导致region和hdfs的io过高,增加服务端负载,影响其他应用
-
“Bulkload”
- 原理: hbase底层存储是hdfs上的hfile文件,然后通过meta表关联数据,所以可以先本地将数据转换为hfile文件,然后上传到hdfs上去,同时补充上meta表数据
- 场景: 适用于导入大量数据的批量hbase场景,要求稳定性能
- 缺点:
- 数据第一次读取时都是在hdfs上的,没有存在memstore中,所以第一次会变慢,但是如果数据量特别大的时候,两种方式最终的数据第一次读取都是在hdfs上的,所以没差别
- 数据直接从传到hdfs上的,没经过WAL,所以当出现数据丢失,没办法恢复数据,需要重新再转换一次
-
实现:
应用程序实现:
1. 负责将普通文件转换成为hfile文件
2. 负责将转换好的hfile文件加载到hbase表中
hbase自带实现:
1.ImportTSV,是hbase-server.jar包中自带的一个命令,可以实现使用put方式将数据导入hbase表中,也实现了将普通文件转换成一个hfile文件的两种方式
2.completebulkload,上面的importtsv命令将普通文件转换成一个hfile文件,但是并没有加载到hbase表中,completebulkload负责将hfile文件加载到hbase表中
<命令>:
1. yarn jar /export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-server-1.2.0-cdh5.14.0.jar
importtsv -Dimporttsv.columns=a,b,c <tablename> <inputdir> -Dimporttsv.separator=','
-Dimporttsv.bulk.output=/bulkload/output2
2. yarn jar export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-server-1.2.0-cdh5.14.0.jar
completebulkload /bulkload/output2 mrhbase
<解释>:
-Dimporttsv.columns 指定文件中列映射的列簇及列
Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:age,info:sex mrhbase /bulkload/input
-Dimporttsv.separator 指定读取文件中的列分隔符,默认以制表符分隔
-Dimporttsv.bulk.output 指定生成的HFILE文件所在的hdfs的位置
SQL on Hbase
背景:
hbase是nosql数据库,有自己的api实现,不支持sql语言,不利于开发和数据分析人员,sql on hbase 解决了这一场景,在hbase上使用sql/jdbc操作-
原理:
- 基于java api/mapreduce 实现
- 基于hbase shell 实现
- 搭桥 通过hdfs 实现
-
实现:
- hive集成hbase:
原理: 通过hive中的hql语句,底层转换为mapreduce操作,在mapreduce操作的同时,也用mapreduce操作hbase表
实现: 在hive中创建一张与hbase关联的表,操作hive中关联表,实际上是对hbase在操作 - phoenix第三方工具:
原理: 基于hbase构建了二级索引,直接调用hbase的api实现,因此在于hbase集成度和性能是最优选 - sqoop第三方工具:
原理: 底层也是使用mapreduce程序导入数据,从关系型数据库中导入到hdfs,然后使用importtsv命令和completebulkload命令来完成从hdfs上的导入,sqoop可以导入,但是不能导出,因为半结构化数据支持结构化数据存储,结构化数据不支持半结构化数据存储
- hive集成hbase:
-
补充:
- 若hbase表已经存在,hive中只能创建外部表,使用key来表示rowkey
- 若hbase表不存在,默认以hive表的第一列作为hbase的rowkey,
- hbase与hive关联,hive中的关联表加载数据时不能使用load加载,因为load命令底层没有使用mapreduce,因为load命令是使用hdfs的put命令,只能用insert命令
二级索引
- 概念:基于rowkey再构建一个索引,称为二级索引
- 意义:
rowkey是唯一索引,而且rowkey是前缀匹配,若我们不知道前缀,但知道rowkey部分字段,只能全部扫描吗? 二级索引就是解决了rowkey唯一索引这个问题 - 解决: 构建二级索引
- 方式:
- 创建索引表,将原表中的查询条件作为索引表的rowkey,将原表中的rowkey作为索引表中的value;
查询是若不指定原表的前缀,就先根据查询条件去查询索引表,找到原表的rowkey,再根据获得的rowkey去查原表
- 创建索引表,将原表中的查询条件作为索引表的rowkey,将原表中的rowkey作为索引表中的value;
协处理器
背景: 构建二级索引,因为索引表和原表是两张不同的表,如何保证两张表的数据同步?
-
同步方式:
- 手动进行两次插入,在插入原表的同时,也插入索引表
缺点: 性能较差,操作繁琐,请求数加倍,对服务器负载过高 - 构建协处理器,构建类似于mysql中的触发器
- 依靠第三方工具,让他们来实现二级索引
例如: solr,ES 构建索引类型丰富,可以实现自动同步,Phoenix用sql构建索引
- 手动进行两次插入,在插入原表的同时,也插入索引表
概念: Coprocessor,协助开发者构建自定义的二级索引
本质:自定义实现hbase提供对应接口的一段程序
-
分类:
- observer: 观察者的协处理器,类似于监听功能,类似于触发器,一般用于二级索引同步
功能: 监听原表,只看客户端往原表中插入一条数据,协处理器自动往索引表中插入一条数据 - endpoint: 终端者协处理器,类似于存储过程,或java中达到一个方法,一般用来做分布式聚合统计
功能: 监听一张表,这张表的每个region都会计算自己的rowkey个数,当客户端调用时,就会返回每个region的个数
- observer: 观察者的协处理器,类似于监听功能,类似于触发器,一般用于二级索引同步
-
补充: 如何快速统计一张表的rowkey个数
- 通过编写mapreduce方法,最慢的最蠢的方式
- 使用hbase自带的count命令
- 开发endpoint协处理,最快最有效的方式