主流nosql
MongoDB、Hbase、Redis
HBase是列式存储还是行式存储
HBase表数据模型比较特别,也可以简单理解为有行和列的二维表,只是它的列称为“列族”,列族下面又可以在数据写入时指定很多的子列。另外,HBase物理存储上是将整个列族数据存储在一起的。所以,如果HBase中的一张表只有一个列族的话,等于是这个列族包含了这张表的所有列,也就是将表正行的数据连续存储在了一起,就等于是行式存储了。再比如,一张表有多个列族,并且每个列族下仅有一列(虽然HBase不建议这么做),也就是将表的列数据连续存储在了一起,就等于是列式存储了。
架构
HBase数据模型
命名空间
命名空间是对表的逻辑分组,不同的命名空间类似于关系型数据库中的不同的Database数据库。利用命名空间,在多租户场景下可做到更好的资源和数据隔离。
表
对应于关系型数据库中的一张张表,HBase以“表”为单位组织数据,表由多行组成。
行
行由一个RowKey和多个列族组成,一个行有一个RowKey,用来唯一标示。
列族
每一行由若干列族组成,每个列族下可包含多个列,如上ImployeeBasicInfoCLF和DetailInfoCLF即是两个列族。列族是列共性的一些体现。注意:物理上,同一列族的数据存储在一起的。
列限定符
列由列族和列限定符唯一指定,像如上的name、age即是ImployeeBasicInfoCLF列族的列限定符。
单元格
单元格由RowKey、列族、列限定符唯一定位,单元格之中存放一个值(Value)和一个版本号。
时间戳
单元格内不同版本的值按时间倒序排列,最新的数据排在最前面
列簇与数据存储
Region虽然是分布式操作的最小单元,但并不是存储的最小单元,在region里面,又划分了很多更小的单位进行存储,如下所示
- Region由一个或者多个Store组成,每个Store保存一个ColumnFamily
- 每个Store又由一个memStore和多个storefile组成
- memstore存储在内存中,storefile存储的HDFS上
- StoreFile以HFile格式保存在HDFS上。HFile是Hadoop的二进制格式文件。实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile
HBase 优点
- 存储容量大,一个表可以容纳上亿行,上百万列;
- 可通过版本进行检索,能搜到所需的历史版本数据;
- 负载高时,可通过简单的添加机器来实现水平切分扩展,跟Hadoop的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性能(MapReduce);
- 在第3点的基础上可有效避免单点故障的发生。
HBase 缺点
- 基于Java语言实现及Hadoop架构意味着其API更适用于Java项目;
- node开发环境下所需依赖项较多、配置麻烦(或不知如何配置,如持久化配置),缺乏文档;
- 占用内存很大,API相比其它 NoSql 的相对笨拙。
HBase 适用场景
1)bigtable类型的数据存储;
2)对数据有版本查询需求;
3)应对超大数据量要求扩展简单的需求。
思考几个问题
1、region是如何划分?
- hbase的表中的行rowkey按照字典顺序进行排序
- 在行的方向上基于rowkey分割为多个region
2、region是如何分配管理的?
- 一张表上面有多个region被随机分配到集群中的regionserver中进行管理,由master进行随机分配
- 同一个regionserver上可以管理不同表中的region,每个rengionserver上管理的regin的数量是均衡。
- 每张表默认创建时候只用一个region,随着表中数据量的增大到一定阀值(10G),会自动分为两个region,分割后region会被master再次分配给regionserver去管理
- 当某台机器的regionserver发生宕机,那么其管理的region丢失管理,master把这台regionserver管理的region重新分配给其他的regionserver去管理
3、为什么HBase 中不建议单表列簇超过 3 个
1. 多列簇导致持有数据量最少的列簇扫描性能下降,主要是因为数据太分散。
2.存在多个列簇的时候,由于它们是共享的同一个 Region,如果其中的一个 列簇触发了 flush(compaction) 动作,相应关联的其他列簇也会进行 flush(compaction ) 。导致系统整体产生更多的 IO , 耗费资源 。
3.列族对于内存的影响,因为一个列族对应一个MemStore,如果列族过多,MemStore会占用RegionServer大量内存资源
读写性能对比
Hbase写入速度比读取速度要快,根本原因LSM存储引擎,
- Hbase底层的存储引擎为LSM-Tree(Log-Structured Merge-Tree)。
- LSM核心思想的核心就是放弃部分读能力,换取写入的最大化能力。将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘,不过读取的时候稍微麻烦,需要合并磁盘中历史数据和内存中最近修改操作,所以写入性能大大提升,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件。极端的说,基于LSM树实现的HBase的写性能比MySQL高了一个数量级,读性能低了一个数量级。
Hbase三个重要的机制
flush机制:
当 MemStore满了以后会Flush 成一个 StoreFile (底层实现是Hfile )。
当metastore达到128MB的时候,会把数据flush成为storeFile <property> <name>hbase.hregion.max.filesize</name> <value>10737418240</value> <source>hbase-default.xml</source> </property> 当regionserver上全部的metastore达到40%的时候,强制阻塞操作,直接把metastore中数据,flush成storeFile <property> <name>hbase.regionserver.global.memstore.upperLimit</name> <value>0.4</value> <source>hbase-default.xml</source> </property> 当regionserver上全部的metastore达到38%的时候,把占比比较大的metastore中数据,flush成storeFile <property> <name>hbase.regionserver.global.memstore.lowerLimit</name> <value>0.38</value> <source>hbase-default.xml</source> </property> |
compact机制:
当StoreFile 文件数量增长到一定阈值,会触发 Compect合并操作,将多个StoreFiles 合并
成一个StoreFile ,合并过程中会对Cell 进行版本合并和数据删除。
Hbase只增加数据,更新和删除操作都是在后续的 Compect过程中进行的,这使得用户的
写操作只要进入内存中就可以立即返回,Hbase I/O保证了 的高性能。
minor compact通常会把数个小的相邻的 StoreFile 合并成一个大的StoreFile ,minor 不会删除标示为删除的数据和过期的数据,只做文件的合并,不做其它事情
major compact:除了文件合并,还有很多其它任务,删除过期数据。读取的所有文件, 合并之后,一个Store 只有一个StoreFile 文件,会对Store 的所有数据进行重写,有较大的性能消耗。
split机制:
当合并后的storeFile越来越大,(10G)就会触发split机制。把region一分为二,父Regin 会下线,
新Split 出的 个孩子 会被HMaster 分配到相应的 HReginServer 上(默认的老版本的是248M)
一个大坑
Regin Split时,旧的Regin 下线会导致MR Job Crash (hive),一般提供在线服务Hbase的集群均会弃用Hbase的自动split ,转而自己管理Split
max.flesize < flush.size * blockingStoreFiles
ps:storeFile的大小 = memstore大小,上面的公式保证了split优先于block触发。
由于split的阀值较大所以一般只有手动执行split命令时才会触发,再执行block,保证了生产
环境block时的可控性
Hbase写入数据的流程
1.client先去zookeeper访问,从zookeeper中获取meta表
2.通过读取meta表,确定region所在的regionserver的服务器
3.client直接向这台服务器发出写入数据的请求
4.regionserver接到请求,然后响应
5.client首先把数据写入Hlog中,防止丢失
6.把数据写入metastore进行缓存。默认的大小是128M
7.当Hlog和metastore全部完成,这次写入才算成功
8.当数据达到128M的时候,发生flush机制把数据变为storeFile
9.当storeFile越来越多,会触发compact(压紧)机制,把多个storeFile合并成一个大的storeFile
10.当合并后的storeFile越来越大,(10G)会触发split机制,把region拆分为2个region,
一个列簇对应一个store,一个store下面会有多个storeFile,最终落地在HDFS,形成Hfile
高级参数
生存时间(TTL)
• 可以在列族级别设置一个 (单位是秒),早于指定 值的数据在下一次Major Compaction时会被删除;
单元版本和最少时间版本数(VERSION)
• 默认情况下每个 维护五个时间版本。
• 如果只需要一个版本,就应该在建表时明确定义。 这样系统就不会保留多个时间版本。
压缩(COMPRESSION)
压缩并存放在 上。这有助于节省硬盘 ,但是读写数据时压缩和解压缩会抬高 利用率。
布隆过滤器(BOOLMFLITER)
• 数据块索引在确定一个数据行是不是在某个数据块里的作用有限;
• 布隆过滤器要么确定回答该行不在,要么回答它不知道;
• 行级布隆过滤器,在数据块里检查特定行键是否不存在,
• 列标识符级布隆过滤器,检查行和列标识符联合体是否不存在
HBase BlockCache机制讲解
客户的读请求会先到memstore中查数据,若查不到就到blockcache中查,再查不到就会从磁盘上读,并把读入的数据同时放入blockcahce。我们知道缓存有三种不同的更新策略,分别是先入先出(FIFO)、LRU(最近最少使用)和LFU(最近最不常使用),hbase的block使用的是LRU策略,当BlockCache的大小达到上限后,会触发缓存淘汰机制,将最老的一批数据淘汰掉。
BlockCache在HBase中所处的位置如下图中所示:
Hive on Hbase
Hive + Hbase
CREATE TABLE ca_cost (key string, order_id string, user_id string, cost_1 double, cost_2 double, cost_3 double, cost_4 double, cost_5 double, cost_6 double, cost_7 double, cost_8 double, cost_9 double, cost_10 double) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,order:order_id,order:user_id,order:cost_1,order:cost_2,order:cost_3,order:cost_4,order:cost_5,order:cost_6,order:cost_7,order:cost_8,order:cost_9,order:cost_10" ) TBLPROPERTIES ("hbase.table.name"="ca_cost"); insert overwrite table ca_cost select reverse(surr_global_order_id) as key, surr_global_order_id, surr_date_id, cost_1,cost_2, cost_3,cost_4, cost_5,cost_6, cost_7,cost_8, cost_9,cost_10 from ca_cost_tmp limit 100;
phoenix和hbase的映射
如果已经有的表
• 通过视图映射(只读)
• 通过表映射(读写)
HBase行级事务强一致性保证
1.写写并发控制
提供一个基于行的独占锁来保证对同一行写的独立性。所以写的顺序是:
- 获取行锁
- 写WAL文件
- 更新memStore :将每个cell 写入到memStore
- 释放行锁
2. 批量写入多行的写写并发
两阶段锁协议 ,即:
• 获取所有待写入 更新 行记录的行锁
• 开始执行写入 更新 操作
• 写入完成之后再统一释放所有行记录的行锁
3. 读写并发控制
MVCC机制,类似于mysql的undolog
Hbase事务原理
Hbase是Regin行级的事务
Mysql事务是集群级别的事务
参考文章
HBase BlockCache机制讲解&源码分析_进一步有一步的欢喜-CSDN博客_blockcache