HBase是一种支持自动负载均衡的分布式KV数据库,在开启balance的开关(balance_switch)后,HBase的HMaster进程会自动根据指定策略挑选出一些Region,并将这些Region分配给负载比较低的RegionServer上。官方目前支持两种挑选Region的策略,一种叫做DefaultLoadBalancer,另一种叫做StochasticLoadBalancer,这两种策略后面会具体讲到。由于HBase的所有数据(包括HLog/Meta/HStoreFile等)都是写入到HDFS文件系统中的, 因此HBase的Region移动其实非常轻量级。在做Region移动的时候,保持这个Region对应的HDFS文件位置不变,只需要将Region的Meta数据分配到相关的RegionServer即可,整个Region移动的过程取决于RegionClose以及RegionOpen的耗时,这个时间一般都很短。
本文来讲讲hbase的balance实现。
其中, unassign region的具体流程为:
assgin region的具体流程为:
这种策略能够保证每个RS的regions个数基本上都相等,确切来说,假设一共有n个RS,第i个RS有Ai个region,记average=sigma(Ai)/n , 那么这种策略能够保证所有的RS的region个数都在[floor(average), ceil(average)]之间。这种策略的实现简单,应用广泛。
但是,这种策略考虑的因素比较单一, 没有考虑到每台region server的读写qps/负载压力等等,这样就可能导致出现一种情况:虽然每个region server的regions都非常接近,但是90%的请求还是落在了一台RS上,因为这台RS上的region全部都是热点数据,这样还是没有达到负载均衡的目的。 但我觉得balance的首要目的是保证数据均衡,如果在数据均衡的情况下,负载还是集中,这时候就要考虑下rowKey的选择是否有问题了。因此, 我个人还是比较推荐采用DefaultLoadBalancer的。
StochasticLoadBalancer 这种策略真的是非常复杂,简单来讲,是一种综合权衡一下6个因素的均衡策略:
对于cluster的每一种region分布, 采用6个因素加权的方式算出一个代价值,这个代价值就用来评估当前region分布是否均衡,越均衡代价值越低。然后通过成千上万次随机迭代来找到一组RegionMove的序列,使得最终的代价值严格递减。 得到的这一组RegionMove就是HMaster最终执行的region迁移方案。
这里用一段伪代码来描述这个迭代的过程:
currentCost = MAX ;
plans = []
for(step = 0 ; step < 1000000; step ++ ){
action = cluster.generateMove()
doAction( action );
newCost = computeCost(action) ;
if (newCost < currentCost){
currentCost = newCost;
}else{
undoAction(action);
}
plans.add( action )
}
其中generateMove()每次随机选择以下3种策略之一来生成RegionMove:
对于这种策略,JavaDoc上说效果比较好,但其中的合理性个人觉得有待测试数据的证明(官方基本没有给出这方面的测试结果)。如果6个因素每个参数占据的权重如果没有调好的话,会导致线上的Region大量不均衡。按照我的一次线上经历,采用如下blance配置,出现过每次balance都只选择60个左右的plan去移动, 但真实的情况是145个RS,其中region数量最多的有700+个, 最少的region数量有2个,然后其他RS的region数量在2~700不等,这时候按理来讲应该需要进行大量的balance,但HMaster每隔一个period只生成60个plan左右去移动,这样balance太慢导致很长一段时间内负载不均,有的RS非常清闲,有的RS非常繁忙经常超时。
hbase.master.loadbalancer.class=\
org.apache.hadoop.hbase.master.StochasticLoadBalancer
hbase.master.balancer.stochastic.regionCountCost=10
hbase.master.balancer.stochastic.tableSkewCost=5
hbase.master.balancer.stochastic.readRequestCost=5
hbase.master.balancer.stochastic.writeRequestCost=5
hbase.master.balancer.stochastic.localityCost=10
hbase.master.balancer.stochastic.moveCost=4
hbase.master.balancer.stochastic.maxMovePercent=1
后面对比了下了官方的默认配置,应该是regionCountCost一项权重太低, 但是,我想说的是除非线下有一个测试结果支撑具体的权重配置下 balance是符合预期的,否则线上操作时一般对权重很难有一个准确的把握,所以像这么复杂的策略还是要比较谨慎的选择,最好有过历史测试数据来评估balance的效果。