HBase源码分析4—Region Balance

30. 1 月 2018 hbase, 数据库 0

易于水平拓展是HBase高性能的重要原因之一。但是随着数据分散到不同节点,容易出现数据倾斜的问题,使得整个集群的效率下降。本章详细讨论下HBase中负载均衡的问题。

入口

HBase源码分析3—HMaster启动过程中提到过,在HMaster启动的最后阶段 finishActiveMasterInitialization 中,HBase会启动一些定时任务,其中就包括负责Region负载均衡的BalanceChore

而balancer对象是在 initializeZKBasedSystemTrackers 中产生的

 

HBase提供了很多种Balancer,曾经默认的叫 SimpleLoadBalancer ,现在默认的是 StochasticLoadBalancer (随机梯度……啊不是,随机负载均衡)。两种balancer的实现都在包 org.apache.hadoop.hbase.master.balancer 中。

Balance过程

BalanceChore 通过调用 HMaster.balance() 来启动balance过程。

首先函数做了一些检查,看集群是否满足做balance的条件,比如正在进行region splitting的时候就不能进行balance,有其他balance进行的时候也不能再进行balance( this.balancer 是用 syncronized 修饰的)。

宏观上看,balance的过程主要分三步:

  • 获取集群信息
  • 获得每个表的balance plan
  • 执行所有plan

plan指的是一个balance的步骤,其中保存了需要移动的region,当前所在的serverName和目的地serverName。

下面展开分析一下三个步骤。

获取集群信息

assignmentManager 是一个与zk集群交互的组件,包含了一些关于node分配方面的函数。 getRegionStates() 方法返回regionStates,这个是 assignmentManager 内使用的管理region状态的一个数据结构,里面的内容跟 hbase:meta 表的内容是一致的。 getAssignmentsByTable() 返回的是以table为聚合维度的region信息,返回的结构为 Map<TableName, Map<ServerName, List<HRegionInfo>>> ,比较直观。

获得balance plan

getClusterStatusWithoutCoprocessor() 用于获取集群信息。为什么要without coprocessor以后再找机会分析下。

接下来就是对每个tabel计算它的balance plan。以默认的方案 StochasticLoadBalancer为例看下这个方案是怎么得到的。

实际调用的方法是 org.apache.hadoop.hbase.master.balancer 包中的 balanceCluster

step 1  balanceMasterRegions()

顾名思义就是对master上的region做平衡操作。分两种:把不该出现在master上的region换出去,把该在master上的region换回来。

这个方法的前半部分实现了“换出去”操作,对maste上的每个region判断一下,如果不必要,就随便找个region server丢了(通过生成RegionPlan实现的,这里并不做真正操作)。如何判断是否要存在master region server上呢?通过方法 shouldBeOnMaster(region)实现。这个方法会去检查regionName是否在一个“免死列表”中( tablesOnMaster ),这个列表中默认包含 hbase:meta,如果想增加其他的region需要在配置中通过配置 hbase.balancer.tablesOnMaster 实现。

方法的后半部分实现的是“换回来”操作,会遍历所有server的所有region进行判断(还用刚才那个函数),如果该回来就生成相应的plan。

如果在这一步中,master region需要做balance,那么cluster的balance plan就不再继续生成了,这一轮就只做master region的balance。

step 2 判断是否有balance的必要

如果除了master region server之外,就剩一个Server了,那就没必要做balance了。在后面几行还有一个 needsBalance(cluster) ,用于计算当前cluster的负载是否需要做balance,具体是对 costFunctions 中的所有估价函数记性计算求和(带权重的),看是否小于某个阈值。估价函数包括:

每个函数都考虑了某方面的问题,比如locality、备份复杂度等等……

step 3 生成balance方案

生成方案的流程很暴力:首先算出一个当前的负载(用needBalance里一样的方法),然后随机生成一个动作,计算操作后是不是比之前更好,如果好就保留,不行就回滚。这种随机的尝试动作有次数上限。最后将cluster的变化组合成plan返回。

执行balance plan

代码来到HMaster.java的1489行左右。之前我们已经获得了一个RegionPlan的ArrayList,下面就是要顺序执行里面的所有plan。主要代码如下:

this.assignmentManager.balance(plan) 这行进行了plan的实际执行操作,具体是(删减了无用代码)

读到这自然地会有个疑问:就把plan put到一个array里就完了???region的移动到底谁干的???

其实实际的代码在 unassign 这个方法里,这个方法看起来是“把某个region下线”的意思,但是实际上他带了一个 dest 参数,默认是null。当这个 dest 是null的时候,他干的就是字面的unassign的事情;但是如果不为空的时候,会顺带把move的事情给干了。追进去还会发现一个东西:

sendRegionClose 这个东西表面上看起来是给region发close rpc指令的,但是注意他参数里也有个dest,当他不为null的时候,也会顺便给移动下。

这俩方法写的。。不说不对吧,但是名字确实起的有点让人误解,在这里卡了一段时间才发现搞的什么鬼。。

这部分具体的实现逻辑要追的非常深,region server那边还不是特别了解,暂时马克一下,以后再具体看。

 

region balance的代码基本就分析到这里。另外看了下其他的balancer,感觉各有各的道理,但是目前的stochastic balancer大概是在性能和效果之间有trade off吧,后面看有没有相关资料可以研究下。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.