hbase 中HRegion 手动分裂无效
答案:1 悬赏:30 手机版
解决时间 2021-11-20 20:35
- 提问者网友:刺鸟
- 2021-11-20 09:01
hbase 中HRegion 手动分裂无效
最佳答案
- 五星知识达人网友:归鹤鸣
- 2021-11-20 09:47
对于一个曾经运维过几百个节点的HBase集群的运维人员,并且Request每秒在5w以上,一定遇到过如下类似的问题。
ZooKeeper服务在不停地报警指示在zookeeper的unassigned路径由一些节点在会一直存在,而且它的版本在不断增加。此时,HRegionServer和HMaster都会打印大量log,而且会持续给ZooKeeper带来压力,另外整个HBase集群没有报告出现任何Region offline的现象。如果你也是遇到同样的问题,那么请继续看本文的内容。
背景:
注册到zookeeper的unassgined路径下的节点,是处于Transition状态的Region,这主要有如下几种:
public enum State {
OFFLINE, // region is in an offline state
PENDING_OPEN, // sent rpc to server to open but has not begun
OPENING, // server has begun to open but not yet done
OPEN, // server opened region and updated meta
PENDING_CLOSE, // sent rpc to server to close but has not begun
CLOSING, // server has begun to close but not yet done
CLOSED, // server closed region and updated meta
SPLITTING, // server started split of a region
SPLIT // server completed split of a region
}
几个常见场景:
1)在一个RegionServer下线,在进行了log split之后,它上面的Region需要迁移到其它RegionServer的时候,会首先将其放入PENDING_OPEN的Region放入unassigned路径下。
2)在Region进行split时,会有Region经历SPLITTING -〉SPLIT的过程,对于SPLIT的操作,下面将努力还原这个过程。
HRegionServer有两种方式触发split操作:
1)用户直接通过API指定splitkey,然后进行Region Split
2)HRegionServer上CompactionSplitThread被触发。
无论哪种方式,最后的核心处理逻辑都是类似的,都是由SplitTransction来进行。
核心操作的步骤为:
1)创建两个子女Region。此时,Parent Region的信息被创建在unassgined路径下,状态为SPLITTING,此时该Region处于Off-line。
2)让两个子女Region上线。在first region 和 second Region上线的选择中,https://issues.apache.org/jira/browse/HBASE-4335 给出了一个小小的trick,让second Region先上线。
orignal Region:[starkey, endkey) example {a, b ,c}
first Region : [startkey,midkey) example {a}
second Region: [midkey, endkey) example {b, c}
如果让first Region 先于 second Region上线,那么根据Get(key)查找离key最匹配的Region的区间时,会根据startkey进行匹配,由于second Region还没上线,则get(c)最后直接会在first Region中查找,找不到该值,直接返回null,而如果second Region先于first Region上线,则get(a)仍然会找到original Region,从而触发客户端的retry。
3)结束整个split操作工作。这一步相当于打扫卫生的工作,然而就是这步操作,出现了一个问题。
SplitTransaction将parent region的状态由SPLITTING 转换成SPLIT,这是在提醒HMaster端的AssignmentManager,你可以回收这个parent region了。
AssignmentManager由nodeChanged发现了SPLIT的event之后,立刻就开始清理工作,它通过ExecutorThreadPool提交了SplitRegionHandler,接下来它的顺序就特别重要了:
1)它会清空在AssignmentManager内存中该Parent Region记录的状态;
2)然后删除unassigned节点的内容。注意这个步骤是time-consuming过程。
同时,在SplitTransaction内,如果在sleep 100 ms之后,会醒来,如果发现AssignmentManager没有处理该路径,会重新创建一个新的version,状态仍然是SPLIT。可怕的事情是,如果ZooKeeper是顺序执行这个操作,如果某个时序上,AssignmentManager删除了该路径,而此时,HRegionServer上SplitTransaction又正好更新该ZNode,就悲剧了。
此时,AssignmentManager由于内存已经清空了该数据,不再认定该Region是正常的Region,所以,就会报出Warning,而SplitTransaction只是100ms反复更新znode。分布式交互的死循环即将开始。
对于该bug,深层次原因在于,对于zookeeper上一个node的创建与修改都是加锁的,而且是time-consuming的过程。如果在HMaster节点和HRegionServer节点高并发,多线程调度情况下,很容易出现上述的状态。
基于此,我的解决方案是:
增加HRegionServer上SplitTransaction的sleep的时间,可以由100ms改成4000ms,让等待时间足够长,同时保留之前循环检查来比避免ZK的event丢失问题。
hbase-0.92.1 SplitTransaction.java
412 Thread.sleep(100); => Thread.sleep(4000);
注意,由于分裂的Region已经上线,修改该时间,不会带来性能上的影响。只是确保HMaster的AssignmentManager 可以更好进行相应的操作。
ZooKeeper服务在不停地报警指示在zookeeper的unassigned路径由一些节点在会一直存在,而且它的版本在不断增加。此时,HRegionServer和HMaster都会打印大量log,而且会持续给ZooKeeper带来压力,另外整个HBase集群没有报告出现任何Region offline的现象。如果你也是遇到同样的问题,那么请继续看本文的内容。
背景:
注册到zookeeper的unassgined路径下的节点,是处于Transition状态的Region,这主要有如下几种:
public enum State {
OFFLINE, // region is in an offline state
PENDING_OPEN, // sent rpc to server to open but has not begun
OPENING, // server has begun to open but not yet done
OPEN, // server opened region and updated meta
PENDING_CLOSE, // sent rpc to server to close but has not begun
CLOSING, // server has begun to close but not yet done
CLOSED, // server closed region and updated meta
SPLITTING, // server started split of a region
SPLIT // server completed split of a region
}
几个常见场景:
1)在一个RegionServer下线,在进行了log split之后,它上面的Region需要迁移到其它RegionServer的时候,会首先将其放入PENDING_OPEN的Region放入unassigned路径下。
2)在Region进行split时,会有Region经历SPLITTING -〉SPLIT的过程,对于SPLIT的操作,下面将努力还原这个过程。
HRegionServer有两种方式触发split操作:
1)用户直接通过API指定splitkey,然后进行Region Split
2)HRegionServer上CompactionSplitThread被触发。
无论哪种方式,最后的核心处理逻辑都是类似的,都是由SplitTransction来进行。
核心操作的步骤为:
1)创建两个子女Region。此时,Parent Region的信息被创建在unassgined路径下,状态为SPLITTING,此时该Region处于Off-line。
2)让两个子女Region上线。在first region 和 second Region上线的选择中,https://issues.apache.org/jira/browse/HBASE-4335 给出了一个小小的trick,让second Region先上线。
orignal Region:[starkey, endkey) example {a, b ,c}
first Region : [startkey,midkey) example {a}
second Region: [midkey, endkey) example {b, c}
如果让first Region 先于 second Region上线,那么根据Get(key)查找离key最匹配的Region的区间时,会根据startkey进行匹配,由于second Region还没上线,则get(c)最后直接会在first Region中查找,找不到该值,直接返回null,而如果second Region先于first Region上线,则get(a)仍然会找到original Region,从而触发客户端的retry。
3)结束整个split操作工作。这一步相当于打扫卫生的工作,然而就是这步操作,出现了一个问题。
SplitTransaction将parent region的状态由SPLITTING 转换成SPLIT,这是在提醒HMaster端的AssignmentManager,你可以回收这个parent region了。
AssignmentManager由nodeChanged发现了SPLIT的event之后,立刻就开始清理工作,它通过ExecutorThreadPool提交了SplitRegionHandler,接下来它的顺序就特别重要了:
1)它会清空在AssignmentManager内存中该Parent Region记录的状态;
2)然后删除unassigned节点的内容。注意这个步骤是time-consuming过程。
同时,在SplitTransaction内,如果在sleep 100 ms之后,会醒来,如果发现AssignmentManager没有处理该路径,会重新创建一个新的version,状态仍然是SPLIT。可怕的事情是,如果ZooKeeper是顺序执行这个操作,如果某个时序上,AssignmentManager删除了该路径,而此时,HRegionServer上SplitTransaction又正好更新该ZNode,就悲剧了。
此时,AssignmentManager由于内存已经清空了该数据,不再认定该Region是正常的Region,所以,就会报出Warning,而SplitTransaction只是100ms反复更新znode。分布式交互的死循环即将开始。
对于该bug,深层次原因在于,对于zookeeper上一个node的创建与修改都是加锁的,而且是time-consuming的过程。如果在HMaster节点和HRegionServer节点高并发,多线程调度情况下,很容易出现上述的状态。
基于此,我的解决方案是:
增加HRegionServer上SplitTransaction的sleep的时间,可以由100ms改成4000ms,让等待时间足够长,同时保留之前循环检查来比避免ZK的event丢失问题。
hbase-0.92.1 SplitTransaction.java
412 Thread.sleep(100); => Thread.sleep(4000);
注意,由于分裂的Region已经上线,修改该时间,不会带来性能上的影响。只是确保HMaster的AssignmentManager 可以更好进行相应的操作。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯