Region Server宕机总述
HBase一个很大的特色是扩展性极其友好,可以通过简单地加机器实现集群规模的线性扩展,而且机器的配置并不需要太好,通过大量廉价机器代替价格昂贵的高性能机器。但也正因为廉价机器,由于网络硬盘等各方面的原因,机器宕机的概率就会相对比较大。RegionServer作为HBase集群中实际的执行节点,不可避免地也会出现宕机。
宕机并不十分可怕,因为不会丢数据。HBase集群中一台RegionServer宕机(实指RegionServer进程挂掉,下文同)并不会导致已经写入的数据丢失,和MySQL等数据库一样,HBase采用WAL机制保证这点:它会先写HLog,再写缓存,缓存写满后一起落盘。即使意外宕机导致很多缓存数据没有及时落盘,也可以通过HLog日志恢复出来。
可是没有数据丢失并不意味着宕机对业务方没有任何影响。众所周知,RegionServer宕机是由zookeeper首先感知到的,而zookeeper感知到RegionServer宕机事件是需要一定时间的,这段时间默认会有3min。也就是说,在RegionServer宕机之后的3min之内系统并不知晓它实际上已经宕机了,所有的读写路由还会正常落到它上面,可想而知,这些读写必然都会失败。(当然,并不是所有RegionServer宕机都需要3min中才能被Zookeeper感知。如果RegionServer在运行过程中产生自身难以解决的问题,它会自己abort自己,并且RegionServer会主动通知Zookeeper自己已经宕机的事实。这种场景下,影响用户读写的时间会极大的缩短到秒级)
Zookeeper一旦感知到RegionServer宕机之后,就会第一时间通知集群的管理者Master,Master首先会将这台RegionServer上所有Region移到其他RegionServer上,再将HLog分发给其他RegionServer进行回放,这个过程通常会很快。完成之后再修改路由,业务方的读写才会恢复正常。
既然,在分布式领域RegionServer宕机无法避免,那我们就有必要研究一旦宕机应该如何应对,即RegionServer宕机应对之道。另外,RegionServer宕机一定程度上会影响业务方的读写请求,所以我们也有必要研究如何定位宕机原因并设法避免。
Region Server宕机应对之道
理论基础
HBase底层数据存储依赖于HDFS组件,HDFS中数据是按照block块来存储,一个块默认是64M。为了实现数据不丢失,线上HDFS存储普遍为多副本存储,默认为3副本。因此一个大文件在HDFS中存储,首先会被切分成多个block块,然后每个block块会被存放到3台不同的机器上,实现3副本存储。
考虑到读性能以及数据的高可用性,HDFS在实现3副本的时候采取了一定的算法策略。HDFS总是为第一份副本优先选择本地节点作为存储空间,对于第二份副本,则是优先选择另一个机架的节点。如果前两份副本位于不同机架,第三份副本偏向于选择与第一份副本相同机架的节点,否则选择不同机架。整个写的流程如下图所示:
整个集群有两个机架Rank1和Rank2,每个机架分别有三台机器作为存储节点,其中最左边的节点为Region Server进程所在节点,称为本地节点。整个写入过程可以描述为:
1.本地一个192M大小的文件首先被切分为3个64M大小的block块
2.以最上面的绿色块为例,HDFS首先会选择本地节点存储第一个副本,然后在Rank2上随机找个节点存储第二个副本,最后再在Rank1上找一个非本地节点存第三个副本
3.3个block块最终的存储位置如图所示,只有本地节点完整保存了整个文件,其他节点都只有整个文件的一部分
理解了HDFS写文件的流程之后,我们还需要引入HBase中和读性能息息相关的一个概念:本地性(Locality)。HBase系统中,一个Region Server由多个Region构成,每个Region可以认为是一个计算节点,它会写入大量数据,这些数据落在本地节点的比例称为Locality。如上图所示,假如上图192M文件全部由Region 1产生,那么Region 1如果身处本地节点,因为所有数据都在本地节点上存在,所以Locality就是100%。而Region 1如果身处节点2,因为只有两个block块在节点2,Locality就只有66%。同理,一旦Region 1落到节点3,Locality就只有33%。那么Locality如何影响读性能呢?很显然,如果Locality越高,说明计算所需数据块都在本地,不需要远程访问,必然性能最高。反正,性能也就会越差。
接下来根据节点1上RegionServer宕掉前后,分三阶段来理解HBase在各种情况下的Locality变化:
阶段一:正常情况下,节点1上RegionServer产生的所有文件都在本地有一个副本,Locality就是100%。
阶段二:一旦节点上的RegionServer进程宕机,Master会把宕机节点上的Region根据系统的负载均衡情况分配到其他节点,负载最低的节点被分配到的Region会越多。假如此时不幸,节点3上的负载最低,那分配到节点3上的Region就会越多,落到节点3上的读请求数就会越多。然而节点3上只有一份block块,即Locality只有33%,此时一旦读取请求要读另外两份block块的数据,就只能通过网络访问其他节点,读取性能必然不高。
阶段三:再假如第一时间我们发现RegionServer进程宕掉了,我们只是手动拉了起来,没有其他处理措施,Master会简单地根据当前系统负载情况执行balance操作将其他负载较高节点上的Region重新移到恢复后的节点1上。从文件块的角度看,系统整体表现越来越混乱,整体Locality也会越来越低(当然,HBase也在致力于重新设计balance算法,能够尽量保证每个Region被分配给拥有最多Block的Region Server,提高系统Locality)
通过上述理论分析,如果仅仅依赖HBase本身的balance操作,就会使得系统整体Locality越来越低,读性能越来越差。那不禁要问,能不能人工执行balance操作呢?当然,我们可以在手动拉起RegionServer之后,将宕掉RegionServer上的Region全部又手动移回来,实际上就恢复到了阶段一的情形,Locality基本接近100%。接下来具体介绍如何实际操作。
运维实践
根据上述理论分析,RegionServer宕机之后一方面需要马上将其拉起来,另一方面在拉起来之后需要将该RegionServer上原有的Regions全部迁移回来。其中第二步又可以分为两小步,先找到该RegionServer上所有Regions,再执行迁移命令将所有Regions迁回。具体运维操作如下:
·拉起Region Server:./bin/hbase-daemon.sh start regionserver
·找到该RegionServer上所有原有Regions:RegionServer宕机之后会由Master将所有Regions迁移到其他节点上,这些操作都记录在了Master日志中,所以可以通过查看Master日志(类似于hbase-hadoop-master-hbase10.log.2016-01-04)找到所有迁移的Regions,下图是日志中的一个片段:
其中master.AssignmentManaager字段表示有多少个Region被移动到了哪个节点,上图表示有18个节点移动到hbase11节点。字段Transition表示具体的迁移Region信息,可以通过如下脚本解析这部分日志得到所有的Regions:
cat ‘hbase-hadoop-master-hbase10.log’ | grep ‘GeneralBulkAssigner-[0-9]]master.RegionStates: Transition’ | awk -F ‘{‘ ‘{print $2}’ |awk -F ‘ ‘ ‘{print $1}’ | uniq
·迁移Regions回原RegionServer:使用HBase提供的move命令可以迁移Region到原RegionServer。Region比较多的话也可以使用脚本批量迁移。
RegionServer宕机原因定位
紧急处理完宕机的RegionServer之后,就应该着手定位宕机原因,确定是否可以设法避免。所有系统Bug原因定位无非三大招,查日志、查监控、查代码。RegionServer宕机排查主要依赖前两点。下面以一个具体事例来简单说明排查RegionServer宕机的过程:线上有一个HBase集群,由4个RegionServer组成,这个集群每隔一段时间就会出现一个RegionServer宕掉的情况,首先想到排查日志,如下:
排查日志
HBase系统日志主要包括master日志(上文已提到),regionserver日志以及gc日志。很显然,regionserver宕机主要查看regionserver日志,经过排查,在对应时间点找到如下日志片段:
从中我们明显可以看到,hbase8这台机器已经无法绑定到端口0,端口0表示内核自动会分配一个可用端口,这个端口是随机的。无法绑定到端口0实际上就表示内核已经无法分配出可用的端口,即端口被耗尽。这种情况就属于上文提到的Region Server遇到了自己无法解决的问题,然后它就默默地自己abort了自己,见下图:
排查监控
系统可用端口被耗尽,立马联想到HBase所有读写HDFS操作都会发起RPC请求,如果并发RPC请求太多,会不会导致端口耗尽?带着这样的疑问排查了监控系统中这台主机的网卡流量图,如下图:
确实发现hbase8上的流量高达100M字节每秒,网卡基本被打满,和业务方确认后得知是业务方配置问题导致一张表的查询流量太高导致,和业务方沟通之后修改配置,流量就掉到40M字节每秒,后续我们还进一步将这张表进行了split操作,并且移到了其他几个节点上。
到此为止,我们以为RegionServer再也不会频繁宕机了。直到有一天,又有另一台RegionServer宕机,查看日志发现是同样的端口耗尽错误,然而排查监控发现网卡流量却正常。偶然一次例行排查监控,却意外获得了rs宕机的规律性事实,见下图:
上图是节点上连接状态统计图,红线表示处于CLOSE_WAIT状态的socket数。很显然,系统中处于CLOSE_WAIT状态的socket数不断上升直至50k+,然后跳水式下跌,联想到RegionServer会每隔一段时间宕机以及端口被耗尽,这不就是规律么。显而易见,既然是周期性地宕机,我们就可以根据监控数据知道下一次宕机大约发生在什么时候,然后在发生之前平滑重启Region Server就可以保证不影响上层业务请求。
但是,这并没有说明宕机的真正原因,但是却给了我们足够多的提示信息。带着CLOSE_WAIT关键字,在HBase官方Jira上一搜就很容易得到很多这方面问题,具体详见:HBASE-13488 HDFS-1836等等。基于当前的HDFS和HBase版本,针对这个问题暂时没有好的解决方案,只能通过定期重启来避免宕机,好在HBase也提供了平滑重启一个RegionServer的命令graceful_stop,执行这个重启命令不会对上层业务有任何影响,具体执行过程如下:
RegionServer宕机总结
RegionServer宕机是HBase系统不可完全避免的场景,本文分三个部分从运维角度介绍RegionServer宕机这一事件。首先介绍宕机对应用方会造成什么影响、数据会不会丢等,第二部分接着介绍一旦RegionServer宕机之后应该如何正确地处理,第三部分使用一个具体事例介绍如何通过排查日志以及监控定位RegionServer宕机原因并设法避免宕机发生。看官阅览之后如果能对HBase中RegionServer宕机有一个基础的了解,俺心甚慰!