一、HRegion的负载均衡
负载均衡主要用来解决热点问题,使请求更均匀的发送给不同的应用服务器,Hbase是一个典型的主从架构,HMaster负载整个集群的资源调度,任务分配,而数据的IO操作是在HRegionServer上,每个HRegionServer会有N个HRegion,存的是每张表的一部分数据,而HRegionServer里的HRegion之间的负载影响着整个Hbase集群的读写性能。
二、负载均衡实现
HRegion的负载调度由HMaster负责,所以负载的实现类在HMaster类里面。先看HMaster里面用到的涉及负载的几个变量
/**触发balacer的线程 */
private BalancerChore balancerChore;
// Tracker for load balancer state
//负载均衡的追踪类
LoadBalancerTracker loadBalancerTracker;
//负载均衡实现类
LoadBalancer balancer;
用来实现HRegion在各个HReginServer之间的迁移的相关操作类在HMaster构造函数中进行了相关初始化工作。
public HMaster(final Configuration conf, CoordinatedStateManager csm)
throws IOException, KeeperException, InterruptedException {
super(conf, csm);
this.rsFatals = new MemoryBoundedLogMessageBuffer(
conf.getLong("hbase.master.buffer.for.rs.fatals", 1*1024*1024));
LOG.info("hbase.rootdir=" + FSUtils.getRootDir(this.conf) +
", hbase.cluster.distributed=" + this.conf.getBoolean(HConstants.CLUSTER_DISTRIBUTED, false));
// Disable usage of meta replicas in the master
this.conf.setBoolean(HConstants.USE_META_REPLICAS, false);
Replication.decorateMasterConfiguration(this.conf);
// Hack! Maps DFSClient => Master for logs. HDFS made this
// config param for task trackers, but we can piggyback off of it.
if (this.conf.get("mapreduce.task.attempt.id") == null) {
this.conf.set("mapreduce.task.attempt.id", "hb_m_" + this.serverName.toString());
}
// should we check the compression codec type at master side, default true, HBASE-6370
this.masterCheckCompression = conf.getBoolean("hbase.master.check.compression", true);
// should we check encryption settings at master side, default true
this.masterCheckEncryption = conf.getBoolean("hbase.master.check.encryption", true);
this.metricsMaster = new MetricsMaster(new MetricsMasterWrapperImpl(this));
// preload table descriptor at startup
this.preLoadTableDescriptors = conf.getBoolean("hbase.master.preload.tabledescriptors", true);
// Do we publish the status?
boolean shouldPublish = conf.getBoolean(HConstants.STATUS_PUBLISHED,
HConstants.STATUS_PUBLISHED_DEFAULT);
Class<? extends ClusterStatusPublisher.Publisher> publisherClass =
conf.getClass(ClusterStatusPublisher.STATUS_PUBLISHER_CLASS,
ClusterStatusPublisher.DEFAULT_STATUS_PUBLISHER_CLASS,
ClusterStatusPublisher.Publisher.class);
if (shouldPublish) {
if (publisherClass == null) {
LOG.warn(HConstants.STATUS_PUBLISHED + " is true, but " +
ClusterStatusPublisher.DEFAULT_STATUS_PUBLISHER_CLASS +
" is not set - not publishing status");
} else {
clusterStatusPublisherChore = new ClusterStatusPublisher(this, conf, publisherClass);
getChoreService().scheduleChore(clusterStatusPublisherChore);
}
}
// Some unit tests don't need a cluster, so no zookeeper at all
if (!conf.getBoolean("hbase.testing.nocluster", false)) {
activeMasterManager = new ActiveMasterManager(zooKeeper, this.serverName, this);
int infoPort = putUpJettyServer();
/** 开启状态为Active的master的各种管理器 */
startActiveMasterManager(infoPort);
} else {
activeMasterManager = null;
}
}
然后会调到 finishActiveMasterInitialization,这里面最重要的是对后台负责触发负载执行的线程的初始化(其它分支挺多,我们只看主干)
this.balancerChore = new BalancerChore(this);
BalancerChore类继承了ScheduledChore,ScheduledChore类里面的run方法调用了chore(),然后会调到真正的balance方法,也就是说会周期性的去判断是否需要执行HRegion在HRegionServer间的负载迁移操作。
public class BalancerChore extends ScheduledChore {
private static final Log LOG = LogFactory.getLog(BalancerChore.class);
private final HMaster master;
//默认每隔5分钟触发一次balance方法,去判断此时集群是否需要进行HRegion的负载
public BalancerChore(HMaster master) {
super(master.getServerName() + "-BalancerChore", master, master.getConfiguration().getInt(
"hbase.balancer.period", 300000));
this.master = master;