HBase--读写数据
HBase(Hadoop Database),是一个高可靠性
、高性能
、面向列
、可伸缩
的分布式存储系统。HBase是基于hadoop分布式文件系统(HDFS),模仿了Google文件系统BigTable数据库所有功能。
本博客主要介绍HBase的体系结构,如HMaster
、HRegionServer
、HRegion
、Store
、MemStore
、StoreFile
、HLog
、HFile
、KeyValue
等、HBase数据的读写流程,以及读写流程中所用到LSM树
、墓碑标记
、布隆过滤器
等。
体系结构
HBASE的基本架构组成如下:
- Zookeeper 协调管理
- 保证每个时刻只有一个HMaster在运行,一旦Zookeeper感知不到HMaster就会重新选举出一个新的HMaster;
- 实时监控Region Server的状态,将Region server的上线和下线信息实时通知给Master;
- 存贮所有Region的寻址入口;
- 存储Hbase的schema,包括有哪些table,每个table有哪些column family。
- HMaster
- 负责维护表和元数据(包括region);
- 负责region切分、合并、负载均衡等;
- 处理schema更新请求;
- 如果HMaster挂掉,还可以进行正常的数据读写,提供服务。
- HRegionServe
- 一个 HBase 实例包括多个HRegionServer ;
- HRegionServer包含了一个HLog部分和HRegion部分(多个HRegion,即内部管理了一系列HRegion对象)。
- HRegion
- 每个HRegion对应了Table中的一个Region;
- HRegion中由多个HStore组成;
- 每个HStore对应了Table中的一个Column Family的存储;
注:可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。
- HStore
- HBase 存储的核心,包含两部分 memStore(内存)和多个StoreFile(HDFS文件);
- MemStore:用户写入的数据首先会放入MemStore,当MemStore满了以后会Flush成一个StoreFile;
- StoreFiles:底层实现是HFile,当StoreFile文件数量增长到一定阈值,会触发Compact合并操作,将多个StoreFiles合并成一个StoreFile。
读写数据
- 下面我们来看一下HBase具体的读写数据的流程:
写数据
- Hbase写数据流程:
- Client 发起了一个 HTable.put(Put) 请求给 HRegionServer;
- HRegionServer 会将请求定位到某个具体的HRegion上面;
- 决定是否写WAL log ,即图中的 Hlog;
- WAL结束后,Put数据保存到MemStore中,同时检查MemStore状态,如果满了,则触发Flush to Disk请求;
- 每次flush就会将数据写成HFile文件并存到HDFS上,并且存储最后写入的数据序列号,这样就可以知道哪些数据已经存入了永久存储的HDFS中;
- 当文件达到一定数量(默认3)就会触发Compact操作 -> 多个HFile合并成一个的HFile文件,同时进行版本合并和数据删除;
- 并保证文件的总数在可控范围之内,major合并最后将文件集中的合并成一个文件,此后刷写又会不断创建小文件。
- 当HFile越来越大 -> 单个HFile大小超过一定阈值(默认10G)后,触发Split操作,把当前Region Split成2个Region;
- Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer 上,使得原先1个Region的压力得以分流到2个Region上
- 由此过程可知,HBase只是增加数据,有所得更新和删除操作,都是在Compact阶段做的,所以,用户写操作只需要进入到内存即可立即返回,从而保证I/O高性能。
当HRegionServer意外终止: HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的 HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应region的目录下,然后再将失效的region重新分配,领取 到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。
WAL(Write Ahead Log)文件: 是一个标准的Hadoop SequenceFile,文件中存储了HLogKey,这些Keys包含了和实际数据对应的序列号,主要用于崩溃恢复。在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中,HLog文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据),因为HLog是顺序写入的所以非常高效。
HFile文件: HFile文件是不定长的,长度固定的只有其中的两块:Trailer中有指针指向其他数据块的起始点,File Info中记录了文件的一些Meta信息,Data Index和Meta Index块记录了每个Data块和Meta块的起始点。
LSM树(log-structured merge-tree):
- 数据首先被存储在日志文件,这些文件内的数据完全有序。当有日志文件被修改时,对应的更新会被先保存在内存中来加速查询;
- 当多次修改,使内存空间被逐渐被占满后,LSM树会把有序的“键-记录”对写到磁盘中,同时创建一个新的数据存储文件。此时,因为最近的修改都被持久化了,内存中保存的最近更新就可以被丢弃了;
- 所有节点都是满的并按页存储。修改数据文件的操作通过滚动合并完成;
- 多次数据刷写之后会创建许多数据存储文件,后台线程就会自动将小文件聚合成大文件,这样磁盘查找就会被限制在少数几个数据存储文件中。磁盘上的树结构也可以拆分成独立的小单元,这样更新就可以被分散到多个数据存储文件中;
- 查询: 先查找内存中的存储,然后再查找磁盘上的文件。这样在客户端看来数据存储文件的位置是透明的;
- 删除: 是一种特殊的更改,当删除标记被存储之后,查找会跳过这些删除过的键。当页被重写时,有删除标记的键会被丢弃。此外,后台运维过程可以处理预先设定的删除请求。这些请求由TTL(time-to-live)触发,例如,当TTL设为20天后,合并进程会检查这些预设的时间戳,同时在重写数据块时丢弃过期的记录。
读数据
- Hbase读数据流程:
- Client会通过内部缓存的相关的-ROOT-中的信息和.META.中的信息直接连接与请求数据匹配的HRegionserver(0.98.8版本是在系统表meta中);
- 然后直接定位到该服务器上与客户请求对应的region,客户请求首先会查询该region在内存中的缓存——memstore(memstore是是一个按key排序的树形结构的缓冲区);
- 如果在memstore中查到结果则直接将结果返回给client;
- 在memstore中没有查到匹配的数据,接下来会读已持久化的storefile文件(HFile)中的数据。storefile也是按key排序的树形结构的文件——并且是特别为范围查询或block查询优化过的;另外hbase读取磁盘文件是按其基本I/O单元(即 hbase block)读数据的;
- 如果在BlockCache中能查到要造的数据则这届返回结果,否则就读去相应的storefile文件中读取一block的数据,如果还没有读到要查的数据,就将该数据block放到HRegion Server的blockcache中,然后接着读下一block块儿的数据,一直到这样循环的block数据直到找到要请求的数据并返回结果;如果将该region中的数据都没有查到要找的数据,最后接直接返回null,表示没有找的匹配的数据。当然blockcache会在其大小大于一的阀值(heapsize hfile.block.cache.size 0.85)后启动基于LRU算法的淘汰机制,将最老最不常用的block删除。
墓碑标记: 由于所有的存储文件都是不可变的,从这些文件中删除一个特定的值是做不到的,通过重写存储文件将已经被删除的单元格移除也是毫无意义的,墓碑标记就是用于此类情况的,它标记着”已删除”信息,这个标记可以是单独一个单元格、多个单元格或一整行。
布隆过滤器: 提高随机读的性能,具体讲解可查看参考资料
- 参考资料