2011年毕玄和竹庄两位大神将HBase引入阿里技术体系,2014年接力棒转到东8区第一位HBase commiter天梧手中,多年来与淘宝、旺旺、菜鸟、支付宝、高德、大文娱、阿里妈妈等几乎全BU合做伙伴携手共进,支撑了双十一大屏、支付宝帐单、支付宝风控、物流详情等核心业务。2018年双十一,HBase全天处理请求2.4万亿行,单集群吞吐达到千万级别。从一个婴儿成长为青年,阿里HBase摔过不少次,甚至头破血流,咱们在客户的信任之下幸运的成长,感激不尽。2017年开始阿里HBase走向公有云,咱们有计划的在逐步将阿里内部的高可用技术提供给外部客户,目前已经上线了同城主备,将做为咱们后续高可用能力发展的一个基础平台。本文分四个部分回顾阿里HBase在高可用方面的发展:大集群、MTTF&MTTR、容灾、极致体验,但愿能给你们带来一些共鸣和思考。html
一个业务一个集群在初期很简便,但随着业务增多会加剧运维负担,更重要的是没法有效利用资源。首先每个集群都要有Zookeeper、Master、NameNode这三种角色,固定的消耗3台机器。其次有些业务重计算轻存储,有些业务重存储轻计算,分离模式没法削峰填谷。所以从2013年开始阿里HBase就走向了大集群模式,单集群节点规模达到700+。算法
隔离性是大集群的关键难题。保障A业务异常流量不会冲击到B业务,是很是重要的能力,不然用户可能拒绝大集群模式。阿里HBase引入了分组概念“group”,其核心思想为:共享存储、隔离计算apache
如上图所示,一个集群内部被划分红多个分组,一个分组至少包含一台服务器,一个服务器同一时间只能属于一个分组,可是容许服务器在分组之间进行转移,也就是分组自己是能够扩容和缩容的。一张表只能部署在一个分组上,能够转移表到其它的分组。能够看到,表T1读写通过的RegionServer和表T2读写通过的RegionServer是彻底隔离的,所以在CPU、内存上都物理隔离,可是下层使用的HDFS文件系统是共享的,所以多个业务能够共享一个大的存储池子,充分提高存储利用率。开源社区在HBase2.0版本上引入了RegionServerGroup。缓存
坏盘对共享存储的冲击:因为HDFS机制上的特色,每个Block的写入会随机选择3个节点做为Pipeline,若是某一台机器出现了坏盘,那么这个坏盘可能出如今多个Pipeline中,形成单点故障全局抖动。现实场景中就是一块盘坏,同一时间影响到几十个客户给你发信息打电话!特别若是慢盘、坏盘不及时处理,最终可能致使写入阻塞。阿里HBase目前规模在1万+台机器,每周大概有22次磁盘损坏问题。咱们在解决这个问题上作了两件事,第一是缩短影响时间,对慢盘、坏盘进行监控报警,提供自动化处理平台。第二是在软件上规避单点坏盘对系统的影响,在写HDFS的时候并发的写三个副本,只要两个副本成功就算成功,若是第三个副本超时则将其放弃。另外若是系统发现写WAL异常(副本数少于3)会自动滚动产生一个新的日志文件(从新选择pipeline,大几率规避坏点)。最后HDFS自身在高版本也具有识别坏盘和自动剔除的能力。服务器
客户端链接对Zookeeper的冲击:客户端访问hbase会和Zookeeper创建长链接,HBase自身的RegionServer也会和Zookeeper创建长链接。大集群意味着大量业务,大量客户端的连接,在异常状况下客户端的连接过多会影响RegionServer与Zookeeper的心跳,致使宕机。咱们在这里的应对首先是对单个IP的连接数进行了限制,其次提供了一种分离客户端与服务端连接的方案 HBASE-20159网络
稳定性是生命线,随着阿里业务的发展,HBase逐步扩大在线场景的支持,对稳定性的要求是一年更比一年高。衡量系统可靠性的经常使用指标是MTTF(平均失效时间)和MTTR(平均恢复时间)session
形成系统失效的来源有:
硬件失效,好比坏盘、网卡损坏、机器宕机等
自身缺陷,通常指程序自身的bug或者性能瓶颈
运维故障,因为不合理的操做致使的故障
服务过载,突发热点、超大的对象、过滤大量数据的请求
依赖失效,依赖的HDFS、Zookeeper组件出现不可用致使HBase进程退出架构
下面我介绍一下阿里云HBase在稳定性上遇到的几个表明性问题:(注:慢盘、坏盘的问题已经在大集群一节中涉及,这里再也不重复)并发
在支持菜鸟物流详情业务的时候,咱们发现机器大概每隔两个月就会abort一次,由于内存碎片化问题致使Promotion Fail,进而引起FGC。因为咱们使用的内存规格比较大,因此一次FGC的停顿时间超过了与Zookeeper的心跳,致使ZK session expired,HBase进程自杀。咱们定位问题是因为BlockCache引发的,因为编码压缩的存在,内存中的block大小是不一致的,缓存的换入换出行为会逐步的切割内存为很是小的碎片。咱们开发了BucketCache,很好的解决了内存碎片化的问题,而后进一步发展了SharedBucketCache,使得从BlockCache里面反序列化出来的对象能够被共享复用,减小运行时对象的建立,从而完全的解决了FGC的问题。运维
HBase依赖俩大外部组件,Zookeeper和HDFS。Zookeeper从架构设计上就是高可用的,HDFS也支持HA的部署模式。当咱们假设一个组件是可靠的,而后基于这个假设去写代码,就会产生隐患。由于这个“可靠的”组件会失效,HBase在处理这种异常时很是暴力,当即执行自杀(由于发生了不可能的事情),寄但愿于经过Failover来转移恢复。有时HDFS可能只是暂时的不可用,好比部分Block没有上报而进入保护模式,短暂的网络抖动等,若是HBase所以大面积重启,会把原本10分钟的影响扩大到小时级别。咱们在这个问题上的方案是优化异常处理,对于能够规避的问题直接处理掉,对于没法规避的异常进行重试&等待。
HBase的大查询,一般指那些带有Filter的Scan,在RegionServer端读取和过滤大量的数据块。若是读取的数据常常不在缓存,则很容易形成IO过载;若是读取的数据大多在缓存中,则很容易由于解压、序列化等操做形成CPU过载;总之当有几十个这样的大请求并发的在服务器端执行时,服务器load会迅速飙升,系统响应变慢甚至表现的像卡住了。这里咱们研发了大请求的监控和限制,当一个请求消耗资源超过必定阈值就会被标记为大请求,日志会记录。一个服务器容许的并发大请求存在上限,若是超过这个上限,后来的大请求就会被限速。若是一个请求在服务器上运行了好久都没有结束,但客户端已经判断超时,那么系统会主动中断掉这个大请求。该功能的上线解决了支付宝帐单系统由于热点查询而致使的性能抖动问题。
在线上咱们偶尔会遇到某个分区的数量在几十GB到几个TB,通常都是因为分区不合理,而后又在短期内灌入了大量的数据。这种分区不但数据量大,还常常文件数量超级多,当有读落在这个分区时,必定会是一个大请求,若是不及时分裂成更小的分区就会形成严重影响。这个分裂的过程很是慢,HBase只能从1个分区分裂为2个分区,而且要等待执行一轮Compaction才能进行下一轮分裂。假设分区大小1TB,那么分裂成小于10GB的128个分区须要分裂7轮,每一轮要执行一次Compaction(读取1TB数据,写出1TB数据),并且一个分区的Compaction只能由一台机器执行,因此第一轮最多只有2台机器参与,第二轮4台,第三轮8台。。。,而且实际中须要人为干预balance。整个过程作下来超过10小时,这仍是假设没有新数据写入,系统负载正常。面对这个问题咱们设计了“级联分裂”,能够不执行Compaction就进入下一次分裂,先快速的把分区拆分完成,而后一把执行Compaction。
前面讲的都是点,关于如何解决某个顽疾。致使系统失效的状况是多种多样的,特别一次故障中可能交叉着多个问题,排查起来异常困难。现代医学指出医院应当更多投入预防而不是治疗,增强体检,鼓励早就医。早一步也许就是个感冒,晚一步也许就变成了癌症。这也适用于分布式系统,由于系统的复杂性和自愈能力,一些小的问题不会当即形成不可用,好比内存泄漏、Compaction积压、队列积压等,但终将在某一刻引起雪崩。应对这种问题,咱们提出了“健康诊断”系统,用来预警那些暂时尚未使系统失效,但明显超过正常阈值的指标。“健康诊断”系统帮助咱们拦截了大量的异常case,也在不停的演进其诊断智能。
百密终有一疏,系统老是会失效,特别的像宕机这种Case是低几率但必定会发生的事件。咱们要作的是去容忍,下降影响面,加速恢复时间。HBase是一个可自愈的系统,单个节点宕机触发Failover,由存活的其它节点来接管分区服务,在分区对外服务以前,必须首先经过回放日志来保证数据读写一致性。整个过程主要包括Split Log、Assign Region、Replay Log三个步骤。hbase的计算节点是0冗余,因此一个节点宕机,其内存中的状态必须所有回放,这个内存通常能够认为在10GB~20GB左右。咱们假设整个集群的数据回放能力是 R GB/s,单个节点宕机须要恢复 M GB的数据,那么宕机N个节点就须要 M * N / R 秒,这里表达的一个信息是:若是R不足够大,那么宕机越多,恢复时间越不可控,那么影响R的因素就相当重要,在Split Log、Assign Region、Replay Log三个过程当中,一般Split Log、Assign Region的扩展性存在问题,核心在于其依赖单点。Split Log是把WAL文件按分区拆分红小的文件,这个过程当中须要建立大量的新文件,这个工做只能由一台NameNode来完成,而且其效率也并不高。Assign Region是由HBase Master来管理,一样是一个单点。阿里HBase在Failover方面的核心优化是采用了全新的MTTR2架构,取消了Split Log这一步骤,在Assign Region上也作了优先Meta分区、Bulk Assign、超时优化等多项优化措施,相比社区的Failover效率提高200%以上
从客户角度看故障,是2分钟的流量跌零可怕仍是10分钟的流量降低5%可怕?我想多是前者。因为客户端的线程池资源有限,HBase的单机宕机恢复过程可能形成业务侧的流量大跌,由于线程都阻塞在访问异常机器上了,2%的机器不可用形成业务流量下跌90%是很难接受的。咱们在客户端开发了一种Fast Fail的机制,能够主动发现异常服务器,并快速拒绝发往这个服务器的请求,从而释放线程资源,不影响其它分区服务器的访问。项目名称叫作DeadServerDetective
容灾是重大事故下的求生机制,好比地震、海啸等天然灾害形成毁灭性打击,好比软件变动等形成彻底不可控的恢复时间,好比断网形成服务瘫痪、恢复时间未知。从现实经验来看,天然灾害在一我的的一辈子中都难遇到,断网通常是一个年级别的事件,而软件变动引起的问题多是月级别的。软件变动是对运维能力、内核能力、测试能力等全方位的考验,变动过程的操做可能出错,变动的新版本可能存在未知Bug。另外一个方面为了避免断知足业务的需求又须要加速内核迭代,产生更多的变动。
容灾的本质是基于隔离的冗余,要求在资源层面物理隔离、软件层面版本隔离、运维层面操做隔离等,冗余的服务之间保持最小的关联性,在灾难发生时至少有一个副本存活。阿里HBase在几年前开始推动同城主备、异地多活,目前99%的集群至少有一个备集群,主备集群是HBase能够支持在线业务的一个强保障。主备模式下的两个核心问题是数据复制和流量切换
选择什么样的复制方式,是同步复制仍是异步复制,是否要保序?主要取决于业务对系统的需求,有些要求强一致,有些要求session一致,有些能够接受最终一致。占在HBase的角度上,咱们服务的大量业务在灾难场景下是能够接受最终一致性的(咱们也研发了同步复制机制,但只有极少的场景),所以本文主要专一在异步复制的讨论上。很长一段时间咱们采用社区的异步复制机制(HBase Replication),这是HBase内置的同步机制。
同步延迟的根因定位是第一个难题,由于同步链路涉及发送方、通道、接受方3个部分,排查起来有难度。咱们加强了同步相关的监控和报警。
热点容易引起同步延迟是第二个难题。HBase Replication采用推的方式进行复制,读取WAL日志而后进行转发,发送线程和HBase写入引擎是在同一台RegionServer的同一个进程里。当某台RegionServer写入热点时,就须要更多的发送能力,但写入热点自己就挤占了更多的系统资源,写入和同步资源争抢。阿里HBase作了两个方面的优化,第一提升同步性能,减小单位MB同步的资源消耗;第二研发了远程消耗器,使其它空闲的机器能够协助热点机器同步日志。
资源需求、迭代方式的不匹配是第三个难题。数据复制自己是不须要磁盘IO的,只消耗带宽和CPU,而HBase对磁盘IO有重要依赖;数据复制的worker本质上是无状态的,重启不是问题,能够断点续传,而HBase是有状态的,必须先转移分区再重启,不然会触发Failover。一个轻量级的同步组件和重量级的存储引擎强耦合在一块儿,同步组件的每一次迭代升级必须同时重启HBase。一个重启就能够解决的同步问题,由于同时要重启hbase而影响线上读写。一个扩容CPU或者总带宽的问题被放大到要扩容hbase总体。
综上所述,阿里HBase最终将同步组件剥离了出来做为一个独立的服务来建设,解决了热点和耦合的问题,在云上这一服务叫作BDS Replication。随着异地多活的发展,集群之间的数据同步关系开始变得复杂,为此咱们开发了一个关于拓扑关系和链路同步延迟的监控,而且在类环形的拓扑关系中优化了数据的重复发送问题。
在具有主备集群的前提下,灾难期间须要快速的把业务流量切换到备份集群。阿里HBase改造了HBase客户端,流量的切换发生在客户端内部,经过高可用的通道将切换命令发送给客户端,客户端会关闭旧的连接,打开与备集群的连接,而后重试请求。
切换瞬间对Meta服务的冲击:hbase客户端首次访问一个分区前须要请求Meta服务来获取分区的地址,切换瞬间全部客户端并发的访问Meta服务,现实中并发可能在几十万甚至更多形成服务过载,请求超时后客户端又再次重试,形成服务器一直作无用功,切换一直没法成功。针对这个问题咱们改造了Meta表的缓存机制,极大地提升了Meta表的吞吐能力,能够应对百万级别的请求。同时在运维上隔离了Meta分区与数据分区,防止相互影响。
从一键切换走向自动切换。一键切换仍是要依赖报警系统和人工操做,现实中至少也要分钟级别才能响应,若是是晚上可能要10分钟以上。阿里HBase在演进自动切换过程当中有两个思路,最先是经过增长一个第三方仲裁,实时的给每个系统打健康分数,当系统健康分低于一个阈值,而且其备库是健康的状况下,自动执行切换命令。这个仲裁系统仍是比价复杂的,首先其部署上要保持网络独立,其次其自身必须是高可靠的,最后健康分的正确性须要保证。仲裁系统的健康判断是从服务器视角出发的,但从客户端角度来说,有些时候服务器虽然活着可是已经不正常工做了,可能持续的FGC,也可能出现了持续网络抖动。因此第二个思路是在客户端进行自动切换,客户端经过失败率或其它规则来断定可用性,超过必定阈值则执行切换。
在风控和推荐场景下,请求的RT越低,业务在单位时间内能够应用的规则就越多,分析就越准确。要求存储引擎高并发、低延迟、低毛刺,要高速且平稳的运行。阿里HBase团队在内核上研发CCSMAP优化写入缓存,SharedBucketCache优化读取缓存,IndexEncoding优化块内搜索,加上无锁队列、协程、ThreadLocal Counter等等技术,再结合阿里JDK团队的ZGC垃圾回收算法,在线上作到了单集群P999延迟小于15ms。另外一个角度上,风控和推荐等场景并不要求强一致,其中有一些数据是离线导入的只读数据,因此只要延迟不大,能够接受读取多个副本。若是主备两个副本之间请求毛刺是独立事件,那么理论上同时访问主备能够把毛刺率降低一个数量级。咱们基于这一点,利用现有的主备架构,研发了DualService,支持客户端并行的访问主备集群。在通常状况下,客户端优先读取主库,若是主库必定时间没有响应则并发请求到备库,而后等待最早返回的请求。DualService的应用得到的很是大的成功,业务接近零抖动。
主备模式下还存在一些问题。切换的粒度是集群级别的,切换过程影响大,不能作分区级别切换是由于主备分区不一致;只能提供最终一致性模型,对于一些业务来说很差写代码逻辑;加上其它因素(索引能力,访问模型)的推进,阿里HBase团队基于HBase演进了自研的Lindorm引擎,提供一种内置的双Zone部署模式,其数据复制采用推拉组合的模式,同步效率大大提高;双Zone之间的分区由GlobalMaster协调,绝大部分时间都是一致的,所以能够实现分区级别切换;Lindorm提供强一致、Session一致、最终一致等多级一致性协议,方便用户实现业务逻辑。目前大部分阿里内部业务已经切换到Lindorm引擎。
零抖动是咱们追求的最高境界,但必须认识到致使毛刺的来源能够说无处不在,解决问题的前提是定位问题,对每个毛刺给出解释既是用户的诉求也是能力的体现。阿里HBase开发了全链路Trace,从客户端、网络、服务器全链路监控请求,丰富详尽的Profiling将请求的路径、资源访问、耗时等轨迹进行展现,帮助研发人员快速定位问题。
本文介绍了阿里HBase在高可用上的一些实践经验,结尾之处与你们分享一些看可用性建设上的思考,抛砖引玉但愿欢迎你们讨论。
从设计原则上
一、面向用户的可用性设计,在影响面、影响时间、一致性上进行权衡
MTTF和MTTR是一类衡量指标,但这些指标好不必定知足用户指望,这些指标是面向系统自己而不是用户的。
二、面向失败设计,你所依赖的组件老是会失败
千万不要假设你依赖的组件不会失败,好比你确信HDFS不会丢数据,而后写了一个状态机。但实际上若是多个DN同时宕机数据就是会丢失,此时可能你的状态机永远陷入混乱没法推动。再小几率的事件老是会发生,对中标的用户来说这就是100%。
从实现过程上
一、完善的监控体系
监控是基础保障,是最早须要投入力量的地方。100%涵盖故障报警,先于用户发现问题是监控的第一任务。其次监控须要尽量详细,数据展现友好,能够极大的提升问题定位能力。
二、基于隔离的冗余
冗余是可用性上治本的方法,遇到未知问题,单集群很是难保障SLA。因此只要不差钱,必定至少来一套主备。
三、精细的资源控制
系统的异常每每是由于资源使用的失控,对CPU、内存、IO的精细控制是内核高速稳定运行的关键。须要投入大量的研发资源去迭代。
四、系统自我保护能力
在请求过载的状况下,系统应该具有类如Quota这样的自我保护能力,防止雪崩发生。系统应该能识别一些异常的请求,进行限制或者拒绝。
五、Trace能力
实时跟踪请求轨迹是排查问题的利器,须要把Profiling作到尽可能详细。
本文做者:daniel.meng
本文为云栖社区原创内容,未经容许不得转载。