Region迁移
在一个分布式系统中,分片迁移是最基础的核心功能。集群的负载均衡、故障恢复等功能都是建立在分片迁移基础之上的。负载均衡,可以简单理解为集群中所有节点上的分片个数保持相同,即分片在集群中不断迁移。
一、What
在HBase系统中,一个Region就是一个数据分片,所以分片迁移就是Region迁移。HBase的Region迁移是一个非常轻量级的操作。之所以说它轻量,是因为HBase的数据存储在HDFS上,不需要独立管理。HBase在迁移Region时不需要迁移实际数据,只要将读写服务迁移即可。在实际执行分片迁移时主要有两个步骤:
-
第一步,根据负载均衡策略执行分片迁移计划;
-
第二步,根据迁移计划执行分片的实际迁移。
HBase的Region迁移虽然是一个轻量级操作,但实现逻辑比较复杂。其复杂性主要表现在以下两个方面:
-
其一,迁移过程中涉及多种状态的转变;
-
其二,迁移过程中涉及多个组件(Master、ZooKeeper以及RegionServer)的协调;
二、How
Region迁移操作分为两个阶段:unassign阶段和assign阶段。从总体上来看,整个unassign/assign操作是一个比较复杂的过程,会涉及Master、RegionServer和ZooKeeper三个组件,它们的主要职责如下:
-
Master负责维护Region在整个操作过程中的状态变化,起到枢纽的作用。
-
RegionServer负责执行具体的unassign/assign操作,实际上就是关闭Region或者打开Region操作。
-
ZooKeeper负责存储操作过程中的事件。ZooKeeper上有一个路径为/hbase/region-in-transition的节点,一旦Region发生unssign操作,就会在这个节点下生成一个子节点(内容是“事件”经过序列化的字符串),并且Master会在这个子节点上监听,一旦发生任何事件,Master会即时更新Region的状态。
2.1、unassign阶段
unassign表示Region从源RegionServer下线,整个过程如下:
-
Master生成M_ZK_REGION_CLOSING事件并更新到ZooKeeper,同时将本地内存中该Region的状态改为PENDING_CLOSE。
-
Master通过RPC发送close命令给拥有该Region的RegionServer,令其关闭该Region。
-
RegionServer接收到Master发送过来的命令后,生成一个RS_ZK_REGION_CLOSING事件并更新到ZooKeeper。
-
Master监听到ZooKeeper节点变动后,更新内存中Region的状态为CLOSING。
-
RegionServer执行Region关闭操作。如果该Region正在执行flush或者Compaction,就等待操作完成;否则将该Region下的所有MemStore强制flush,然后关闭Region相关的服务。
-
关闭完成后,生成RS_ZK_REGION_CLOSE事件并更新到ZooKeeper。Master监听到ZooKeeper节点变动后,更新该Region的状态为CLOSED。
2.2、assign阶段
assign表示Region在目标RegionServer上线,整个过程如下:
-
Master生成M_ZK_REGION_OPENING事件并更新到ZooKeeper,同时将本地内存中该Region的状态改为PENDING_OPEN。
-
Master通过RPC发送open命令给拥有该Region的RegionServer,令其打开该Region。
-
RegionServer接收到Master发送过来的命令后,生成一个RS_ZK_REGION_OPENING事件并更新到ZooKeeper。
-
Master监听到ZooKeeper节点变动后,更新内存中Region的状态为OPENING。
-
RegionServer执行Region打开操作,初始化相应的服务。
-
打开完成后,生成RS_ZK_REGION_OPENED事件并更新到ZooKeeper。Master监听到ZooKeeper节点变动后,更新该Region的状态为OPEN。
三、How Good
在Region迁移的过程中,会伴随Region状态的不断改变。此时,我们可能会有疑问:
为什需要设置这些状态?
这些状态是如何管理的?
首先,我们需要知道的是,无论是unnassign操作还是assign操作,都是由多个子操作组成的,同时还会涉及多个组件的协调合作,只有通过记录Region状态才能知道当前unassign或者assign的进度,在发生异常后才能根据具体的状态继续执行。
其次,我们需要知道的是,Region的这些状态会存储在三个区域:meta表、Master内存以及ZooKeeper的region-in-transition节点,并且它们的作用各不相同:
-
meta表存储Region所在的RegionServer(不存储迁移过程中的中间状态)。如果Region从RS1成功迁移到RS2,那么meta表中就持久化存有Region与RS2的对应关系,而如果迁移中间出现异常,那么meta表就持久化存有Region与RS1的对应关系。
-
Master内存存储整个集群所有的Region信息。根据这些信息可以得出Region当前以什么状态位于哪个RegionServer上。Master存储的Region状态变更都是由RegionServer通过ZooKeeper通知给Master的,所以Master上的Region状态变更总是滞后于实际的Region状态。需要注意的是,我们在HBase Master WebUI上看到的Region状态都来自于Master内存信息。
-
ZooKeeper中存储临时性的状态转变信息。作为Master和RegionServer之间反馈Region状态的中介。如果Master(或RegionServer)在某个阶段发生异常,ZooKeeper上存储的状态可以在新Master(或RegionServer)启动之后作为依据继续进行迁移操作。
最后,我们需要知道的是,只有上述三个存储区域内的状态保持一致时,对应的Region才处于正常的工作状态。但在很多异常情况下,Region状态在三个地方并不能保持一致,这就会出现region-in-transition(RIT)现象。
举个例子,RegionServer已经将Region成功打开,但是在远程更新hbase:meta元数据时出现异常(网络异常、RegionServer宕机、hbase:meta异常等)。此时,Master维护的Region状态为OPENING,ZooKeeper维护的Region状态为RS_ZK_REGION_OPENING,hbase:meta存储的Region所在RS为null。但是,Region已经在新的RegionServer上打开了,此时在Web UI上就会看到Region处于RIT状态。
了解了RIT的由来,我们就会知道Region在迁移过程中必然会出现暂时的RIT状态,这种场景并不需要任何人工干预。
四、参考
[HBase原理与实践](HBase原理与实践 (豆瓣))