hadoop之HBase

传统的关系型,按行存储。行结构是固定的,即使你不用,也必须空到那里,而不能没有。此非关系型数据库,是按列来存储的。不会造成空间浪费。
	
HBase管理超级大表-数十亿行 * 数百万列。模仿谷歌的BigTable。底层使用HDFS。 

Hbase的表在放入数据前需要确定下来的东西,列族。
人员基本信息,教育经历信息,工作经历信息,这三个类别其实就相当于三个列族。
人员基本信息里有姓名、电话、出生年月等,叫做列修饰符。
	
在Hbase中一个列族和一个列修饰符组合起来才叫一个列,使用冒号(:)分割,列族:列修饰符,在传统数据库中每一行的唯一标识符叫做主键,在Hbase中叫做row key(行键)。
数据在进入Hbase时都会被打上一个时间戳,这个时间戳可以作为版本号来使用。在t1时间存入一个人的基本信息在t2时间又更新了姓名,并不会去更新原来的那条数据,而是又插入一条新数据且打上新时间戳。此时去查询获取的是新数据,仿佛是更新了,但其实只是默认返回了最新版本的数据而已。
	
一个行键、列族、列修饰符、数据和时间戳组合起来叫做一个Cell。一个行键、一到多列(包括数据)组合起来叫做一行(Row)。
	
在Hbase中,只要确定了列族,表就确定了。HBase以表的形式存储数据。存储时,数据按照Row key的字典序 排序存储。
	
hbase表中的每个列,都归属与某个列族。列族是表的schema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀,例如courses:history。
	
时间戳,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。hbase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本。
	
表在行的方向上分割为多个Hregion。region按大小分割的,每个表一开始只有一个region,随着数据不断插入表,region到一个阀值的时候,Hregion就会等分会两个新的Hregion。
Hregion是Hbase中分布式存储和负载均衡的最小单元,最小单元就表示不同的Hregion可以分布在不同的HRegion server上。但一个Hregion是不会拆分到多个server上的。

HRegion由一个或者多个Store组成,每个Strore又由一个memStore和0至多个StoreFile组成。StoreFile以HFile格式保存在HDFS上,里面有:datablocks段(很多datablock,里面存的是kv),fileinfo段 ,dataindex段(每个datablock的index),trailer段(存了fileinfo的offset,dataindex的offset )。
DataBlock 段–保存表中的数据,这部分可以被压缩。Trailer–这一段是定长的。保存了每一段的偏移量,读取一个HFile时,会首先读取Trailer,Trailer保存了每个段的起始位置,DataBlock Index会被读取到内存中,当检索某个key时,不需要扫描整个HFile,而只需从内存中找到key所在的block,通过一次磁盘io将整个block读取到内存中,再找到需要的key。

HLog(WAL log)Write ahead log:所有写入、更新、删除操作都会把数据先写入HLog,再写入MemStore。大多数情况下,HLog并不会被读取。
但是在HBase的RegionServer故障,MemStore中数据尚未flush到磁盘,这时就需要回放HLog进行数据恢复。此外,HBase主从集群数据复制也是通过将HLog日志发送给从集群,然后从集群再执行回放来完成。

一个region server 里面有很多个region和一个Hlog,每个Region Server维护一个Hlog,而不是每个Region一个。不断追加单个文件。如果一台region server下线,为了恢复其上的region,需要将region server上的log进行拆分,然后分发到其它region server上进行恢复。

系统架构:zookeeper集群 ,client,master,regionserver集群 
Client包含访问hbase的接口,client维护着一些cache来加快对hbase的访问,比如region的位置信息。
Zookeeper:
1 保证任何时候,集群中只有一个master。
2 存所有Region的寻址入口。(master操作的很多东西存它这的)3 实时监控RegionServer的状态,将Regionserver的上线和下线信息实时通知给Master。
4 存Hbase的schema,包括有哪些table,每个table有哪些列族(master操作的很多东西存它这的)。

Master:
1 为Region server分配region。
2 负责region server的负载均衡。
3 发现失效的region server并重新分配其上的region。
4 处理schema更新请求。

Region Server:
1 Region server维护Master分配给它的region,处理对这些region的IO请求。
2 Region server负责切分在运行过程中变得过大的region。

client访问hbase上数据的过程并不需要master参与(寻址访问zookeeper和region server,数据读写访问region server),master仅仅维护table和region的元数据信息,负载很低。

系统如何找到某个row key所在的region:
使用三层树状结构来保存region位置。
第一层是保存zookeeper里面的文件,它持有root region的位置。
第二层root region是META表的第一个region其中保存了META表其它region的位置。通过root region,我们就可以访问META表的数据。
META是第三层,它是一个特殊的表,保存了hbase中所有数据表的region位置信息。
	
root region不会被split,保证了三次跳转,就能定位到任意region 。
META表每行保存一个region的位置信息,有start key (end key存疑)等信息。
为了加快访问,META表的全部region都保存在内存中。
	
假设,META表的一行在内存中大约占用1KB。并且每个region限制为128MB。那么上面的三层结构可以保存的region数目为:(128MB/1KB) * (128MB/1KB) = = 2(34)个region

hbase使用MemStore和StoreFile存储对表的更新,数据在更新时首先写入WAL 和内存(MemStore)中,MemStore中的数据是排序的,当MemStore累计到一定阈值时,就会创建一个新的MemStore,将老的MemStore添加到flush队列,
由单独的线程flush到磁盘上,成为一个StoreFile。同时,系统会在zookeeper中记录一个redo point,表示这个时刻之前的变更已经持久化了。
	
当系统出现意外时,可能导致内存(MemStore)中的数据丢失,此时使用Log(WAL log)来恢复checkpoint之后的数据。
	
前面提到过StoreFile是只读的,一旦创建后就不可以再修改。因此Hbase的更新其实是不断追加的操作。当一个Store中的StoreFile达到一定的阈值后,就会进行一次合并,将对同一个key的修改合并到一起,形成一个大的StoreFile。
	
由于对表的更新是不断追加的,处理读请求时,需要访问Store中全部的StoreFile和MemStore,将它们按照row key进行合并,由于StoreFile和MemStore都是经过排序的,并且StoreFile带有索引,合并过程比较快。

client向region server提交写请求:
1、region server找到目标region
2、region检查数据是否与schema一致
3、如果客户端没有指定版本,则获取当前系统时间作为数据版本
4、将更新写入WAL log
5、将更新写入Memstore
6、判断Memstore的是否需要flush为Store文件。

任何时刻,一个region只能分配给一个region server。master记录了当前有哪些可用的region server。以及当前哪些region分配给了哪些region server,哪些region还没有分配。
当存在未分配的region,并且有一个region server上有可用空间时,master就给这个region server发送一个装载请求,把region分配给这个region server。region server得到请求后,就开始对此region提供服务。

master使用zookeeper来跟踪region server状态。当某个region server启动时,会首先在zookeeper上的server目录下建立代表自己的文件,并获得该文件的独占锁。
由于master订阅了server目录上的变更消息,当server目录下的文件出现新增或删除操作时,master可以得到来自zookeeper的实时通知。因此一旦region server上线,master能马上得到消息。
	
当region server下线时,它和zookeeper的会话断开,zookeeper而自动释放代表这台server的文件上的独占锁。而master不断轮询server目录下文件的锁状态。如果master发现某个regionserver丢失了它自己的独占锁,
(或者master连续几次和region server通信都无法成功),master就是尝试去获取代表这个region server的读写锁,一旦获取成功,就可以确定:
region server和zookeeper之间的网络断开或region server挂了。
region server无法继续为它的region提供服务了,此时master会删除server目录下代表这台region server的文件,并将这台region server的region分配给其它还活着的。
如果网络短暂出现问题导致region server丢失了它的锁,那么region server重新连接到zookeeper之后,只要代表它的文件还在,它就会不断尝试获取这个文件上的锁,一旦获取到了,就可以继续提供服务。

master上线
1、 从zookeeper上获取唯一个代码master的锁,用来阻止其它master成为master。
2、 扫描zookeeper上的server目录,获得当前可用的region server列表。
3、 和2中的每个region server通信,获得当前已分配的region和region server的对应关系。
4、 扫描METAregion的集合,计算得到当前还未分配的region,将他们放入待分配region列表。

master下线
由于master只维护表和region的元数据,而不参与表数据IO的过程,master下线仅导致所有元数据的修改被冻结(无法创建删除表,无法修改表的schema,无法进行region的负载均衡,无法处理region上下线,唯一例外的是region的split可以正常进行,因为只有region server参与),
表的数据读写还可以正常进行。因此master下线短时间内对整个hbase集群没有影响。从上线过程可以看到,master保存的信息全是可以冗余信息(都可以从系统其它地方收集到或者计算出来),一般hbase集群中总是有一个master在提供服务,还有一个以上的master在等待时机抢占它的位置。

尽管已经有许多数据存储和访问的策略和实现方法,但事实上大多数解决方案,特别是一些关系类型的,在构建时并没有考虑超大规模和分布式的特点。
许多商家通过复制和分区的方法来扩充数据库使其突破单个节点的界限,但这些功能通常都是事后增加的,安装和维护都和复杂。同时,也会影响RDBMS的特定功能,例如联接、复杂的查询、触发器、视图和外键约束这些操作在大型的RDBMS上的代价相当高,甚至根本无法实现。HBase是从另一个角度处理伸缩性问题。

面向列:面向列族的存储和权限控制,列族独立检索。

HBase的高并发和实时处理数据:Hadoop是一个高容错、高延时的分布式文件系统和高并发的批处理系统,不适用于提供实时计算;HBase是可以提供实时计算的分布式数据库,数据被保存在HDFS分布式文件系统上,由HDFS保证期高容错性,在生产环境中,HBase是如何基于hadoop提供实时性呢?

在内存初始化一些memstore,相应的这就在一定程度上加快系统响应,从根本上说,HBase能提供实时计算服务主要原因是由其架构和底层的数据结构决定的,即由LSM-Tree + region分区 + Cache决定,
客户端可以直接定位到要查数据所在的HRegion server服务器,然后直接在服务器的一个region上查找要匹配的数据,并且这些数据部分是经过cache缓存的。

如果在BlockCache中能查到则返回结果,否则就读去相应的StoreFile文件中读取block的数据,如果还没有读到要查的数据,就将该数据block放到HRegion Server的blockcache中,然后接着读下一block块儿的数据,
一直循环直到找到要请求的数据并返回结果;当然blockcache会在其大小大于阀值后启动基于LRU算法的淘汰机制。
	
client访问hbase上的数据时不需要master的参与,因为数据寻址访问zookeeper和region server,而数据读写访问region server。
master仅仅维护(更新)table和region的元数据信息,而table的元数据信息保存在zookeeper上,因此master负载很低。

LogFlusher,数据以KeyValue形式到达HRegionServer,将写入WAL之后,写入一个SequenceFile。看过去没问题,但是因为数据流在写入文件系统时,经常会缓存以提高性能。
这样,有些本以为在日志文件中的数据实际在内存中,可强行刷入磁盘。

当用户需要进行Table和Region的管理工作时,就需要和HMaster进行通信。HBase中可以启动多个HMaster,通过Zookeeper的Master Eletion机制保证总有一个Master运行。

当StoreFile文件数量增长到一定阀值,就会触发Compact合并操作,并将多个StoreFile合并成一个StoreFile,合并过程中会进行版本合并和数据删除,因此可以看出HBase其实只有增加数据,
所有的更新和删除操作都是在后续的compact过程中进行的,这使得用户的读写操作只要进入内存中就可以立即返回,保证了HBase I/O的高性能。

Region Split成2个Region,这是旧的Region会下线,新Split出的2个Region会被HMaster分配到相应的HregionServer上,使得原先1个Region的压力得以分散到2个Region上。

Data Block是hbase io的基本单元,为了提高效率,HRegionServer中有基于LRU的block cache机制。

每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每一次用户操作写入MemStore的同时,也会写一份数据到HLog文件中,HLog文件定期(当文件已持久化到StoreFile中的数据)会滚出新的,并且删除旧的文件。
当HRegionServer意外终止 后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的Hlog文件,将其中不同Region的Log数据进行拆分,分别放到相应Region的目录下,然后再将失效的Region重新分配,
领取到这些Region的Regionserver在Load Region的过程中,会发现历史HLog需要处理,因此Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

WAL在处理插入和删除过程中,用来记录操作内容的日志,只有日志写入成功,才会通知客户端操作成功。

Master节点的HA机制:Master为一主多备。当Master主节点宕机后,剩下的备节点通过选举,产生主节点。

LSM树(Log-Structured Merge Tree),存储引擎和B树存储引擎一样,同样支持增、删、读、改、顺序扫描操作。而且通过批量存储技术规避磁盘随机写入问题。当然凡事有利有弊,LSM树和B+树相比,LSM树牺牲了部分读性能,用来大幅提高写性能。

通过以上的分析,应该知道LSM树的由来了,LSM树的设计思想非常朴素:将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘,不过读取的时候稍微麻烦,
需要合并磁盘中历史数据和内存中最近修改操作,写入性能大大提升,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件。
极端的说,基于LSM树实现的HBase的写性能比Mysql高了一个数量级,读性能低了一个数量级。

LSM树原理把一棵大树拆分成N棵小树,它首先写入内存中,随着小树越来越大,内存中的小树会flush到磁盘中,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。
因为小树先写到内存中,为了防止内存数据丢失,写内存的同时需要暂时持久化到磁盘,对应了HBase的MemStore和HLog。

MemStore上的树达到一定大小之后,需要flush到HRegion磁盘中(一般是Hadoop DataNode),这样MemStore就变成了DataNode上的磁盘文件StoreFile,定期HRegionServer对DataNode的数据做merge操作,彻底删除无效空间,多棵小树在这个时机合并成大树,来增强读性能。
  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成长是自己的事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值