欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。 ✨✨ 欢迎订阅本专栏 ✨✨
优点:HBase 底层基于HDFS存储,高可用、高扩展、强一致性,支持上亿级别数据
10亿数据 性能测试结果
1. 写性能:集群吞吐量最大可以达到70000+ ops/sec,延迟在几个毫秒左右。网络带宽是主要瓶颈,如果将千兆网卡换成万兆网卡,吞吐量还可以继续增加,甚至达到目前吞吐量的两倍。
2. 读性能:很多人对HBase的印象可能都是写性能很好、读性能很差,但实际上HBase的读性能远远超过大家的预期。集群吞吐量最大可以达到26000+,单台吞吐量可以达到8000+左右,延迟在几毫秒~20毫秒左右。IO和CPU是主要瓶颈。
3. Range 扫描性能:集群吞吐量最大可以达到14000左右,系统平均延迟在几毫秒~60毫秒之间(线程数越多,延迟越大);其中IO和网络带宽是主要瓶颈。
缺点:
占用内存很大,且鉴于建立在为批量分析而优化的HDFS上,导致读取性能不高
HBase是一个开源的、分布式的、可伸缩的、非关系型数据库,设计用来存储大量的数据表,这些数据表由行和列组成,非常适合存储非结构化和半结构化数据。HBase的名称来源于它是Hadoop Database的一个变种,用于构建在Hadoop Distributed File System (HDFS)之上,利用MapReduce进行数据处理。HBase的设计模仿了Google的BigTable系统,提供了高可靠性、高性能的数据存储服务。
HBase的主要特点包括:
HBase的数据模型基于行键(RowKey)和列族(Column Family),每行数据由多个列组成,每列都可以存储多个版本的数据,这些数据通过时间戳进行索引。HBase的架构设计使得它能够处理大规模的数据存储和快速的数据检索需求。
此外,HBase还支持数据的版本控制,每个cell可以保存多个数据版本,这些版本通过时间戳进行索引,提供了数据的历史版本查询功能。HBase的这种设计使得它非常适合用于需要频繁读写大量数据的场景,如大数据分析、日志数据分析等
HBase适合存储 PB 级别的海量数据,能在几十到百毫秒内返回数据。
HBase是根据列族
来存储数据的。列族下面可以有非常多的列,在创建表的时候列族就必须指定。
在并发的情况下,HBase的单个IO延迟下降并不多,能获得高并发、低延迟的服务。
HBase的列具有灵活性,在列族中,你可以指定任意多的列,在列数据为空的情况下,是不会占用存储空间的。
2.2 HBase 逻辑结构
表由一个或者多个列族
构成。数据的属性如name、age、TTL(超时时间)等都在列族里边定义。定义完列族的表是个空表,只有添加了数据行以后,表才有数据。
HBase 中的每个列都由 Column Family(列族) 和 Column Qualifier(列限定符)进行限定,例如 info:name、info:age。建表时只需指明列族,而列限定符无需预先定义。
组合
成一个列族。建表时不用创建列,在 HBase 中列是可增减变化
的!唯一要确定的是列族
,表有几个列族在开始创建时就定好的。表的很多属性,比如数据过期时间、数据块缓存以及是否使用压缩等都是定义在列族上的。 一行包含多个列,这些列通过列族来分类。行中的数据所属的列族从该表所定义的列族中选取。由于HBase是一个面向列存储的数据库,所以一个行中的数据可以分布在不同的服务器上
。
RowKey 类似 MySQL 中的主键,在 HBase 中 RowKey 必须有且 RowKey 是按照字典排序的,如果用户不指定 RowKey 系统会自动生成不重复字符串。查询数据时只能根据 RowKey 进行检索,所以 Table 的 RowKey 设计十分重要。
RegionServer 就是存放Region的容器,直观上说就是服务器上的一个服务。负责管理维护 Region。
以上只是一个基本的逻辑结构,底层的物理存储结构才是重中之重的内容,看下图
命名空间,类似关系型数据库 DatabBase 概念,每个命名空间下有多个表。HBase有两个自带的命名空间,分别是hbase
和default
,hbase 中存放的是 HBase 内置的表,default 表是用户默认使用的命名空间。
时间戳,用于标识数据的不同版本(version),每条数据写入时如果不指定时间戳,系统会自动添加为其写入 HBase 的时间。并且读取数据的时候一般只拿出数据的Type符合,时间戳最新的数据。之所以按照Type取数据是因为HBase的底层HDFS支持增删查,但不支持改
。
单元格,由 {rowkey, column Family:column Qualifier, time Stamp} 唯一确定的单元。cell 中的数据是没有
类型的,全部是字节码
形式存储。
3.1 Client
Client 包含了访问 Hbase 的接口,另外 Client 还维护了对应的 cache 来加速 Hbase 的访问,比如缓存元数据的信息。
HBase 通过 Zookeeper 来做 Master 的高可用、RegionServer 的监控、元数据的入口以及集群配置的维护等工作。Zookeeper 职责如下:
Master 在 HBase 中的地位比其他类型的集群弱很多!数据的读写操作与他没有关系,它挂了之后,集群照样运行。但是Master 也不能宕机太久,有很多必要的操作,比如创建表、修改列族配置等DDL跟Region的分割与合并都需要它的操作。
HBase 中可以启动多个Master,通过 Zookeeper 的 Master Election 机制保证总有一个 Master 运行。
HregionServer 直接对接用户的读写请求,是真正的干活的节点。它的功能概括如下:
WAL (Write-Ahead-Log) 预写日志是 HBase 的 RegionServer 在处理数据插入和删除的过程中用来记录操作内容的一种日志。每次Put、Delete等一条记录时,首先将其数据写入到 RegionServer 对应的HLog文件中去。只有当WAL日志写入成功的时候,客户端才会被告诉提交数据成功。如果写WAL失败会告知客户端提交失败,这其实就是数据落地的过程。
WAL是保存在HDFS上的持久化文件。数据到达 Region 时先写入WAL,然后被加载到MemStore中。这样就算Region宕机了,操作没来得及执行持久化,也可以再重启的时候从WAL加载操作并执行。跟Redis的AOF类似。
每一个 Region 都有起始 RowKey 和结束 RowKey,代表了存储的Row的范围。从大图中可知一个Region有多个Store,一个Store就是对应一个列族的数据,Store 由 MemStore 和 HFile 组成的。
Store 由 MemStore 跟 HFile 两个重要的部分。
3.6.1 MemStore
每个 Store 都有一个 MemStore 实例,数据写入到 WAL 之后就会被放入 MemStore 中。MemStore是内存的存储对象,当 MemStore 的大小达到一个阀值(默认64MB)时,MemStore 会被 flush到文件,即生成一个快照。目前HBase 会有一个线程来负责MemStore 的flush操作。
3.6.2 StoreFile
MemStore 内存中的数据写到文件后就是StoreFile,StoreFile底层是以 HFile 的格式保存。HBase以Store的大小来判断是否需要切分Region。
3.6.3 HFile
在Store中有多个HFile,每次刷写都会形成一个HFile文件落盘在HDFS上。HFile文件也会动态合并,它是数据存储的实体。
这里提出一点疑问:操作到达Region时,数据进入HFile之前就已经被持久化到WAL了,而WAL就是在HDFS上的,为什么还要从WAL加载到MemStore中,再刷写成HFile呢?
HDFS 为 HBase 提供最终的底层数据存储服务,HBase 底层用HFile格式 (跟hadoop底层的数据存储格式类似) 将数据存储到HDFS中,同时为HBase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:
在HBase集群中如果我们做 DML 操作是不需要关心 HMaster 的,只需要从 ZooKeeper 中获得hbase:meta 数据地址,然后从RegionServer中增删查数据即可。
HBase 在实现中提供了两种缓存结构 MemStore(写缓存) 和 BlockCache(读缓存)。写缓存前面说过不再重复。
重点:
读数据时不要理解
为先从 MemStore 中读取,读不到再读 BlockCache 中,还读不到再从HFile中读取,然后将数据写入到 BlockCache 中。因为如果人为设置导致磁盘数据new,内存数据old。你读取的时候会出错的!
结论:
HBase 把磁盘跟内存数据一起读,然后把磁盘数据放到 BlockCache中,BlockCache 是磁盘数据的缓存。HBase 是个读比写慢的工具。
对于用户来说数据写到 MemStore 中就算OK,但对于底层代码来说只有数据刷到硬盘中才算彻底搞定了!因为数据是要写入到WAL(Hlog)中再写入到MemStore中的,flush有如下几个时机。
由于 MemStore 每次刷写都会生成一个新的 HFile,且同一个字段的不同版本(timestamp) 和不同类型(Put/Delete)有可能会分布在不同的 HFile 中,因此查询时需要遍历所有的 HFile。为了减少 HFile 的个数跟清理掉过期和删除的数据,会进行 StoreFile Compaction。
Compaction 分为两种,分别是 Minor Compaction 和 Major Compaction。
5.3 Region Split
每个 Table 起初只有一个 Region,随着不断写数据 Region 会自动进行拆分。刚拆分时,两个子 Region 都位于当前的 Region Server,但出于负载均衡的考虑, HMaster 有可能会将某个 Region 转移给其他的 Region Server。
Region Split 时机:
当 1 个 Region 中的某个 Store 下所有 StoreFile 的总大小超过 hbase.hregion.max.filesize(默认10G), 该 Region 就会进行拆分。
当 1 个 Region 中的某个 Store 下所有 StoreFile 的总大小超过 Min(R^2 * “hbase.hregion.memstore.flush.size=128M”,hbase.hregion.max.filesize"),该 Region 就会进行拆分,其 中 R 为当前 Region Server 中属于该 Table 的个数。
举例:
官方不建议用多个列族,比如有CF1,CF2,CF3,但是 CF1数据很多而CF2跟CF3数据很少,那么当触发了region切分的时候,会把CF2跟CF3分成若干小份,不利于系统维护。
二进制码流RowKey 最大长度 64Kb,实际应用中一般为 10-100bytes,以 byte[] 形式保存,一般设计定长。建议越短越好,因为HFile是按照KV存储的Key太大浪费空间。
RowKey 在设计时候要尽可能的实现可以将数据均衡的分布在每个 RegionServer 上。
RowKey 必须在设计上保证其唯一性,RowKey 是按照字典顺序排序存储的,因此设计 RowKey 时可以将将经常读取的数据存储到一块。
其实就简单的把HBase当成大数据体系下的DataBase来用就行,任何可以分析HBase的引擎比如MR、Hive、Spark等框架连接上HBase都可以实现控制。比如你可以把Hive跟HBase进行关联,Hive中数据不再由HDFS存储而是存储到HBase中,并且关联后Hive中添加数据在HBase中可看到,HBase中添加数据Hive也可看到。
指标 | 传统关系数据库 | HBase |
---|---|---|
数据类型 | 有丰富的数据类型 | 字符串 |
数据操作 | 丰富操作,复杂联表查询 | 简单CRUD |
存储模式 | 基于行存储 | 基于列存储 |
数据索引 | 复杂的多个索引 | 只有RowKey索引 |
数据维护 | 新覆盖旧 | 多版本 |
可伸缩性 | 难实现横向扩展 | 性能动态伸缩 |