摘要: 基于时间线一致的高可用读(Timeline-consistent High Available Reads),又称Region replica,为HBase带来了高可用读的能力。本文主要介绍region replica这个功能设计的背景,技术细节和使用方法,同时会仔细分析这个功能的优缺点并给出使用建议。html
基于时间线一致的高可用读(Timeline-consistent High Available Reads),又称Region replica。其实早在HBase-1.2版本的时候,这个功能就已经开发完毕了,可是仍是不太稳定,离生产可用级别还有一段距离,后来社区又陆陆续续修复了一些bug,好比说HBASE-18223。这些bug不少在HBase-1.4以后的版本才修复,也就是说region replica功能基本上在HBase-1.4以后才稳定下来。介于HBase-1.4版本目前实际生产中使用的还比较少,把region replica功能说成是HBase2.0中的新功能也不为过。shell
在CAP理论中,HBase一直是一个CP(Consistency&Partition tolerance)系统。HBase一直以来都在遵循着读写强一致的语义。因此说虽然在存储层,HBase依赖HDFS实现了数据的多副本,可是在计算层,HBase的region只能在一台RegionServer上线提供读写服务,来保持强一致。若是这台服务器发生宕机时,Region须要从WAL中恢复还缓存在memstore中未刷写成文件的数据,才能从新上线服务。
apache
因为HBase的RegionServer是使用Zookeeper与Master保持lease。而为了避免让JVM GC停顿致使RegionServer被master“误判”死亡,这个lease时间一般都会设置为20~30s,若是RegionServer使用的Heap比较大时,这个lease可能还会设的更长。加上宕机后,region须要re-assign,WAL可能须要 recoverlease和被replay操做,一个典型的region宕机恢复时间可能长达一分钟!这就意味着在这一分钟内,这个region都没法被读写。因为HBase是一个分布式系统,同一张表的数据可能分布在很是多的RegionServer和region里。若是这是一个大HBase集群,有100台RegionServer机器,那么宕机一台的话,可能只有1%的用户数据被影响了。可是若是这是小用户的HBase集群,一共就只有2台RegionServer,宕机一台意味着50%的用户数据都在1~2分钟以内没法服务,这是不少用户都没法忍受的。缓存
其实,很大一部分用户对读可用性的需求,可能比读强一致的需求还要高。在故障场景下,只要保证读继续可用,“stale read”,即读到以前的数据也能够接受。这就是为何咱们须要read replica这个功能。安全
Region replica的本质,就是让同一个region host在多个regionserver上。原来的region,称为Default Replica(主region),提供了与以前相似的强一致读写体验。而与此同时,根据配置的多少,会有一个或者多个region的副本,统称为 region replica,在另外的RegionServer上被打开。而且由Master中的LoadBalancer来保证region和他们的副本,不会在同一个RegionServer打开,防止一台服务器的宕机致使多个副本同时挂掉。
服务器
Region Replica的设计巧妙之处在于,额外的region副本并不意味着数据又会多出几个副本。这些region replica在RegionServer上open时,使用的是和主region相同的HDFS目录。也就是说主region里有多少HFile,那么在region replica中,这些数据都是可见的,都是能够读出来的。
region replica相对于主region,有一些明显的不一样。
首先,region replica是不可写的。这其实很容易理解,若是region replica也能够写的话,那么同一个region会在多个regionserver上被写入,连主region上的强一致读写都无法保证了。
再次,region replica是不能被split和merge的。region replica是主region的附属品,任何发向region replica的split和merge请求都会被拒绝掉。只有当主region split/merge时,才会把这些region replica从meta表中删掉,创建新生成region的region的replica。网络
那么,既然region replica不能接受写,它打开以后,怎么让新写入的数据变的可见呢?这里,region replica有两种更新数据的方案:运维
这个方案很是好理解,region replica按期检查一下它本身对应的HDFS目录,若是发现文件有变更,好比说flush下来新的文件,文件被compaction掉,它就刷新一下本身的文件列表,这个过程很是像compaction完成以后删除被compact掉的文件和加入新的文件的流程。StoreFile Refresher方案很是简单,只须要在RegionServer中起一个定时执行的Chroe,按期去检查一下它上面的region哪些是region replica,哪些到了设置好的刷新周期,而后刷新就能够了。但这个方案缺点也十分明显,主region写入的数据,只有当flush下来后,才能被region replica看到。并且storeFile Refresher自己还有一个刷新的周期,设的过短了,list文件列表对NN的冲击太频繁,设的太长,就会形成数据长时间在region replica中都不可见异步
咱们知道,HBase是有replication链路的,支持把一个HBase集群的数据经过replication复制到另一个集群。那么,一样的原理,能够在HBase集群内部创建一条replication通道,把一个Server上的主region的数据,复制到另外一个Server的region replica上。那么region replica接收到这些数据以后,会把他们写入memstore中。对,你没看错,刚才我说了region replica是不接受写的,这是指replica不接受来自客户端的写,若是来自主region的replication的数据,它仍是会写入memstore的。可是,这个写和普通的写有很明显的区别。第一个,replica region在写入来自主region的时候,是不写WAL的,由于这些数据已经在主region所在的WAL中持久化了,replica中无需再次落盘。第二个,replica region的memstore中的数据是不会被flush成HFile。咱们知道,HBase的replication是基于复制WAL文件实现的,那么在主region进行flush时,也会写入特殊的标记Flush Marker。当region replica收到这样的标记时,就直接会把全部memstore里的数据丢掉,再作一次HDFS目录的刷新,把主region刚刚刷下去的那个HFile include进来。一样,若是主region发生了compaction,也会写入相应的Compaction Marker。读到这样的标记后,replica region也会作相似的动做。分布式
Internal replication加快了数据在region replica中的可见速度。经过replication方案,只要replication自己不发生阻塞和延迟,region replica中的数据能够作到和主region只差几百ms。可是,replication方案自己也存在几个问题:
下面的两个问题虽然能够经过配置一些参数解决,可是列在这里,仍然须要注意,由于一旦参数没有配对,就会产生这样的问题。
不管是StoreFile Refresher仍是Internal replication,主region和replica之间的数据更新都是异步的,这就致使在replica region中读取数据时,都不是强一致的。read replica的做者把从region replica中读数据的一致性等级定为Timeline Consistency。只有用户明确表示可以接受Timeline consistency,客户端的请求才会发往replica中。
好比说上图中,若是客户端是须要强一致读,那么客户端的请求只会发往主region,即replica_id=0的region,他就会读到X=3.若是他选择了Timeline consistency读,那么根据配置,他的读可能落在主上,那么他仍然会读到X=3,若是他的读落在了replica_id=1的region上,由于复制延迟的存在,他就只能读到X=2.若是落在了replica_id=2上,因为replication链路出现了问题,他就只能读到X=1。
hbase.regionserver.storefile.refresh.period
若是要使用StoreFile Refresher来作为Region replica之间同步数据的策略,就必须把这个值设置为一个大于0的数,即刷新storefile的间隔周期(单位为ms)上面的章节讲过,这个值要不能太大,也不能过小。
hbase.regionserver.meta.storefile.refresh.period
因为Meta表的region replica不能经过replication来同步,因此若是要开启meta表的region replica,必须把这个参数设成一个不为0的值,具体做用参见上一个参数,这个参数只对meta表生效。
hbase.region.replica.replication.enabled hbase.region.replica.replication.memstore.enabled
若是要使用Internal replication的方式在Region replica之间同步数据的策略,必须把这两个参数都设置为true
hbase.master.hfilecleaner.ttl
在主region发生compaction以后,被compact掉的文件会放入Achieve文件夹内,超过hbase.master.hfilecleaner.ttl时间后,文件就会被从HDFS删除掉。而此时,可能replica region正在读取这个文件,这会形成用户的读取抛错返回。若是不想要这种状况发生,就能够把这个参数设为一个很大的值,好比说3600000(一小时),总没有读操做须要读一个小时了吧?
hbase.meta.replica.count
mata表的replica份数,默认为1,即不开启meta表的replica。若是想让meta表有额外的一个replica,就能够把这个值设为2,依次类推。此参数只影响meta表的replica份数。用户表的replica份数是在表级别配置的,这个我后面会讲
hbase.region.replica.storefile.refresh.memstore.multiplier
这个参数我在上面的章节里有讲,默认为4
hbase.region.replica.wait.for.primary.flush
这个参数我在上面的章节里有讲,默认为true
须要注意的是,开启region replica以后,Master的balancer必定要用默认的StochasticLoadBalancer,只有这个balancer会尽可能使主region和他的replica不在同一台机器上。其余的balaner会无区别对待全部的region。
hbase.ipc.client.specificThreadForWriting
由于当存在region replica时,当客户端发往主region的请求超时后,会发起一个请求到replica region,当其中一个请求放回后,就无需再等待另外一个请求的结果了,一般要中断这个请求,使用专门的的线程来发送请求,比较容易处理中断。因此若是要使用region replica,这个参数要配为true。
hbase.client.primaryCallTimeout.get hbase.client.primaryCallTimeout.multiget hbase.client.replicaCallTimeout.scan
分别对应着,get、multiget、scan时等待主region返回结果的时间。若是把这个值设为1000ms,那么客户端的请求在发往主region超过1000ms还没返回后,就会再发一个请求到replica region(若是有多个replica的话,就会同时发往多个replica)
hbase.meta.replicas.use
若是服务端上开启了meta表的replica后,客户端可使用这个参数来控制是否使用meta表的replica的region。
在shell建表时,只需在表的属性里加上REGION_REPLICATION => xx就能够了,如
create 't1', 'f1', {REGION_REPLICATION => 2}
Replica的份数支持动态修改,但修改以前必须disable表
diable 't1' alter 't1', {REGION_REPLICATION => 1} enable 't1'
若是能够按请求设置一致性级别,若是把请求的一致性级别设为Consistency.TIMELINE,即有可能读到replica上
Get get1 = new Get(row); get1.setConsistency(Consistency.TIMELINE); ... ArrayList<Get> gets = new ArrayList<Get>(); gets.add(get1); ... Result[] results = table.get(gets);
另外,用户能够经过Result.isStale()方法来得到返回的result是否来自主region,若是为isStale为false,则结果来自主region。
Result result = table.get(get); if (result.isStale()) { ... }
Region Replica功能给HBase用户带来了高可用的读能力,提升了HBase的可用性,但同时也存在必定的缺点:
Region Replica只带来了高可用的读,宕机状况下的写,仍然取决于主region的恢复时间,所以MTTR时间并无随着使用Region replica而改善。虽说region replica的做者在规划中有写计划在宕机时把一个replica提高为主,来优化MTTR时间,但截至目前为止,尚未实现。
我的建议,region replica功能适合于用户集群规模较小,对读可用性很是在乎,同时又能够接受非强一致性读的状况下开启。若是集群规模较大,或者读写流量很是大的集群上开启此功能,须要留意内存使用和网络带宽。Memstore占用内存太高可能会致使region频繁刷盘,影响写性能,同时cache容量的翻倍会致使一部分读请求击穿cache直接落盘,致使读性能的降低。
阿里HBase目前已经在阿里云提供商业化服务,任何有需求的用户均可以在阿里云端使用深刻改进的、一站式的HBase服务。云HBase版本与自建HBase相比在运维、可靠性、性能、稳定性、安全、成本等方面均有不少的改进,更多内容欢迎你们关注 https://www.aliyun.com/product/hbase
同时,云HBase2.0 在2018年6月6日将正式发布,点击了解更多: https://promotion.aliyun.com/ntms/act/hbase20.html