1、组件架构图
2、相关概念
1)Region
table在行的方向上分隔为多个Region,或者说是根据rowkey分割。Region是HBase中分布式存储和负载均衡的最小单元,即不同的region可以分别在不同的Region Server上,但同一个Region是不会拆分到多个server上。Region按大小分隔,表中每一行只能属于一个region。随着数据不断插入表,region不断增大,当region的某个列族达到一个阈值(默认256M)时就会分成两个新的region。
2)Store
每一个region有一个或多个store组成,至少是一个store,hbase会把一起访问的数据放在一个store里面,即为每个ColumnFamily建一个store(即有几个ColumnFamily,也就有几个Store)。一个Store由一个memStore和0或多个StoreFile组成。
HBase以store的大小来判断是否需要切分region。
3)MemStore
MemStore是放在内存里的。保存修改的数据即keyValues
。当MemStore的大小达到一个阀值(默认64MB
)时,MemStore会被flush
到文件,即生成一个快照。目前hbase 会有一个线程来负责MemStore的flush
操作。
4)StoreFile
memStore内存中的数据写到文件后就是StoreFile(即memstore的每次flush操作都会生成一个新的StoreFile),StoreFile底层是以HFile的格式保存。
5. HFile
HFile是HBase中KeyValue数据的存储格式,是hadoop的二进制格式文件。一个StoreFile对应着一个HFile。而HFile是存储在HDFS之上的。HFile文件格式是基于Google Bigtable中的SSTable,如下图所示:
首先HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。Trailer中又指针指向其他数据块的起始点,FileInfo记录了文件的一些meta信息。
3、数据写入流程
第一部分:客户端的写入流程
客户端流程解析:
1、用户提交put请求后,HBase客户端会将put请求添加到本地buffer中,符合一定条件就会通过AsyncProcess异步批量提交。
HBase默认设置autoflush=true,表示put请求直接会提交给服务器进行处理;
2、用户可以设置autoflush=false,这样的话put请求会首先放到本地buffer,等到本地buffer大小超过一定阈值(默认为2M,可以通过配置文件配置)之后才会提交。很显然,后者采用group commit机制提交请求,可以极大地提升写入性能,但是因为没有保护机制,如果客户端崩溃的话会导致提交的请求丢失。
//提示:
cdh集群中hbase默认是使用autoflush=false 也就是首先会把数据放在本地的buffer中
HBase 客户端写入缓冲
hbase.client.write.buffer = 2M //写入缓冲区大小(以字节为单位)。较大缓冲区需要客户端和服务器中有较大内存,因为服务器将实例化已通过的写入缓冲区并进行处理,这会降低远程过程调用 (RPC) 的数量。为了估计服务器已使用内存的数量,请用值“hbase.client.write.buffer”乘以“hbase.regionserver.handler.count”。
HBase Region Server 处理程序计数
hbase.regionserver.handler.count = 30 //RegionServer 中启动的 RPC 服务器实例数量
3、在提交给服务端之前,HBase会在元数据表.meta.中根据rowkey找到它们归属的region server,这个定位的过程是通过HConnection的locateRegion方法获得的。如果是批量请求的话还会把这些rowkey按照HRegionLocation分组,每个分组可以对应一次RPC请求。
4、HBase会为每个HRegionLocation构造一个远程RPC请求MultiServerCallable<Row>,然后通过rpcCallerFactory.<MultiResponse> newCaller()执行调用,忽略掉失败重新提交和错误处理,客户端的提交操作到此结束。
第二部分:服务端写入流程
服务端流程解析
(1)获取行锁、Region更新共享锁 -》(2)开始写事务 -》(3)写缓存memstore -》(4)构造waledit并append hlog - 》 (5)
释放行锁,共享锁 - 》 (6)sync hlog -》(7)结束写事务 - 》(8) flush memstore
//解释
(1)获取行锁、Region更新共享锁: HBase中使用行锁保证对同一行数据的更新都是互斥操作,用以保证更新的原子性,要么更新成功,要么失败。
(2)开始写事务:获取write number,用于实现MVCC,实现数据的非锁定读,在保证读写一致性的前提下提高读取性能。
(3)写缓存memstore:HBase中每列族都会对应一个store,用来存储该列数据。每个store都会有个写缓存memstore,用于缓存写入数据。HBase并不会直接将数据落盘,而是先写入缓存,等缓存满足一定大小之后再一起落盘。
(4)Append HLog:HBase使用WAL机制保证数据可靠性,即首先写日志再写缓存,即使发生宕机,也可以通过恢复HLog还原出原始数据。该步骤就是将数据构造为WALEdit对象,然后顺序写入HLog中,此时不需要执行sync操作。0.98版本采用了新的写线程模式实现HLog日志的写入,可以使得整个数据更新性能得到极大提升,具体原理见下一个章节。
(5)释放行锁以及共享锁
(6)Sync HLog:HLog真正sync到HDFS,在释放行锁之后执行sync操作是为了尽量减少持锁时间,提升写性能。如果Sync失败,执行回滚操作将memstore中已经写入的数据移除。
(7)结束写事务:此时该线程的更新操作才会对其他读请求可见,更新才实际生效。具体分析见文章《数据库事务系列-HBase行级事务模型》
(8)flush memstore:当写缓存满128M之后,会启动flush线程将数据刷新到硬盘。刷新操作涉及到HFile相关结构,后面会详细对此进行介绍。
//HBase Memstore 刷新大小
hbase.hregion.memstore.flush.size = 128M //如 memstore 大小超过此值(字节数),Memstore 将刷新到磁盘。通过运行由 hbase.server.thread.wakefrequency 指定的频率的线程检查此值。
//提示:
我们需要注意,在服务器端写数据的时候,有很多资料是先写到memstore中,再写到wal log中,但是,这样理解不是很准确,因为这好像,违背了wal log的容灾机制,所有,我们可以理解为
先写入到wal log中再写入到memstore中的 //这一步源码中并没有完全的体现出来,可以理解为同步进行。
理论上应该是先写wal log中,HBase这块实现是先写mem,后写WAL,hbase能够保证只有这两个都写完了用户才会可见(mvcc机制),而且如果mem写成功,wal写失败,mem会被回滚。
这样做之所以it’s ok,是由于MVCC来保证的,在每个写线程开启事务的开头就会创建全局递增的write num,但是在HLog更新完毕之后才会去向前推进(roll forward)全局读取点。
所以在此期间内,任何读取线程采用MVCC机制根据读取点读取数据,任何写入/更新操作在HLog未更新完毕之前是不会向前推进读取点的,因此即使数据已经写入memstore,对读线程也是不可见的。
第三部分:WAL机制解析
1、WAL(Write-Ahead Logging)是一种高效的日志算法,几乎是所有非内存数据库提升写性能的不二法门,
2、基本原理是在数据写入之前首先顺序写入日志,然后再写入缓存,等到缓存写满之后统一落盘。
3、之所以能够提升写性能,是因为WAL将一次随机写转化为了一次顺序写加一次内存写。
4、提升写性能的同时,WAL可以保证数据的可靠性,即在任何情况下数据不丢失。
5、假如一次写入完成之后发生了宕机,即使所有缓存中的数据丢失,也可以通过恢复日志还原出丢失的数据。
WAL持久化等级
HBase中可以通过设置WAL的持久化等级决定是否开启WAL机制、以及HLog的落盘方式。
WAL的持久化等级分为如下四个等级:
-
SKIP_WAL:只写缓存,不写HLog日志。这种方式因为只写内存,因此可以极大的提升写入性能,但是数据有丢失的风险。在实际应用过程中并不建议设置此等级,除非确认不要求数据的可靠性。
-
ASYNC_WAL:异步将数据写入HLog日志中。
-
SYNC_WAL:同步将数据写入日志文件中,需要注意的是数据只是被写入文件系统中,并没有真正落盘。
-
FSYNC_WAL:同步将数据写入日志文件并强制落盘。最严格的日志写入等级,可以保证数据不会丢失,但是性能相对比较差。
- USER_DEFAULT:默认如果用户没有指定持久化等级,HBase使用SYNC_WAL等级持久化数据。
用户可以通过客户端设置WAL持久化等级,代码:put.setDurability(Durability. SYNC_WAL );
//cdh中
WAL 提供程序
hbase.wal.provider = //可选项为: //RegionServer 应用于提前写入日志的实施。
RegionServer Default Group
多个 HDFS WAL
单个 HDFS WAL
HBase 默认设置(Single HDFS WAL)
WAL HSM 存储策略
hbase.wal.storage.policy
RegionServer Default Group
所有副本都在 SSD 上
一个副本在 SSD 上,其他副本均在 HDD 上
无(全部在 HDD 上)
关于wal 和 hlog概念的的升入研究 见参考链接
//HLog的写入模型。HLog的写入可以分为三个阶段,首先将数据对<HLogKey,WALEdit>写入本地缓存,然后再将本地缓存写入文件系统,最后执行sync操作同步到磁盘。