文章目录
前言
本文主要分析一下HRegionServer上的MovedRegionsCleaner工作线程
MovedRegionsCleaner
MovedRegionsCleaner是什么呢?看下它在HRegionServer上的定义:是HRegionServer上一个被移动Region列表的定期清理工作线程。
/**
* Chore to clean periodically the moved region list
* 被移动Region列表的定期清理工作线程
*/
private MovedRegionsCleaner movedRegionsCleaner;
它的类的定义如下:
/**
* Creates a Chore thread to clean the moved region cache.
*/
protected static class MovedRegionsCleaner extends Chore implements Stoppable {
private HRegionServer regionServer;
Stoppable stoppable;
// 私有构造方法
private MovedRegionsCleaner(
HRegionServer regionServer, Stoppable stoppable){
super("MovedRegionsCleaner for region "+regionServer, TIMEOUT_REGION_MOVED, stoppable);
this.regionServer = regionServer;
this.stoppable = stoppable;
}
// 静态方法,通过其创建MovedRegionsCleaner实例
static MovedRegionsCleaner createAndStart(HRegionServer rs){
Stoppable stoppable = new Stoppable() {
private volatile boolean isStopped = false;
@Override public void stop(String why) { isStopped = true;}
@Override public boolean isStopped() {return isStopped;}
};
return new MovedRegionsCleaner(rs, stoppable);
}
}
它继承自Chore类,并且线程工作的频率为TIMEOUT_REGION_MOVED,也就是2分钟。这与HRegionServer上检查合并请求的compactionChecker、检查刷新请求的periodicFlusher是一样的,都继承了Chore类。
看下它的构造方法,只有一个private的私有构造方法,同时它又提供了一个静态方法createAndStart(),这个方法被HRegionServer调用以构造MovedRegionsCleaner对象。而在HRegionServer中,MovedRegionsCleaner是如此被初始化的,代码如下:
// Create the thread to clean the moved regions list
// 创建movedRegionsCleaner工作线程去清理被移动Region列表
movedRegionsCleaner = MovedRegionsCleaner.createAndStart(this);
那么,MovedRegionsCleaner线程是如何工作的呢?集成自Chore的线程会周期性的调用chore()方法来执行需要做的工作。看下它的chore()方法,代码如下:
// chore()方法就是调用HRegionServer的cleanMovedRegions()方法
@Override
protected void chore() {
regionServer.cleanMovedRegions();
}
它实际调用的是regionServer实例的cleanMovedRegions()方法,代码如下:
/**
* Remove the expired entries from the moved regions list.
*/
protected void cleanMovedRegions() {
// 计算超时时间,当前时间减去固定值2分钟
final long cutOff = System.currentTimeMillis() - TIMEOUT_REGION_MOVED;
// 获取movedRegions集合的迭代器it
Iterator<Entry<String, MovedRegionInfo>> it = movedRegions.entrySet().iterator();
// 利用迭代器it遍历movedRegions集合中的元素
while (it.hasNext()){
// 取出movedRegions集合中的元素e,它是key-value类型,key为String类型的Region名称,value为MovedRegionInfo
Map.Entry<String, MovedRegionInfo> e = it.next();
// 根据MovedRegionInfo的MoveTime,即ts,与当前时间比较,
// 如果当前时间已超过TIMEOUT_REGION_MOVED,则移除,
// ts实际上是MovedRegionInfo的创建时间,也就是Region被移动的时间
if (e.getValue().getMoveTime() < cutOff) {
it.remove();
}
}
}
逻辑比较清晰,大体如下:
1、首先计算超时时间,当前时间减去固定值2分钟,赋值给cutOff;
2、获取movedRegions集合的迭代器it,实际上movedRegions就是HRegionServer上存储已被移动Regions的集合;
3、利用迭代器it遍历movedRegions集合中的元素:
3.1、取出movedRegions集合中的元素e,它是key-value类型,key为String类型的Region名称,value为MovedRegionInfo;
3.2、根据MovedRegionInfo的MoveTime,即ts,与当前时间比较,如果当前时间已超过TIMEOUT_REGION_MOVED,则移除,ts实际上是MovedRegionInfo的创建时间,也就是Region被移动的时间。
实际上,整个处理流程很简单,而MovedRegionInfo的代码如下:
private static class MovedRegionInfo {
private final ServerName serverName;
private final long seqNum;
private final long ts;
public MovedRegionInfo(ServerName serverName, long closeSeqNum) {
this.serverName = serverName;
this.seqNum = closeSeqNum;
ts = EnvironmentEdgeManager.currentTime();
}
public ServerName getServerName() {
return serverName;
}
public long getSeqNum() {
return seqNum;
}
public long getMoveTime() {
return ts;
}
}
就包括一个重要的变量long类型的ts,它在构造方法中被赋值为当前时间,而被移动Region加入movedRegions时,是通过HRegionServer的addToMovedRegions()方法实现的,具体代码如下:
protected void addToMovedRegions(String encodedName, ServerName destination, long closeSeqNum) {
if (ServerName.isSameHostnameAndPort(destination, this.getServerName())) {
LOG.warn("Not adding moved region record: " + encodedName + " to self.");
return;
}
LOG.info("Adding moved region record: "
+ encodedName + " to " + destination + " as of " + closeSeqNum);
movedRegions.put(encodedName, new MovedRegionInfo(destination, closeSeqNum));
}
movedRegions集合中,key就是Region的encodedName,而value则是构造的一个对应包含目的地ServerName和关闭序列号closeSeqNum的MovedRegionInfo实例,而MovedRegionInfo在构造时,其ts的赋值上面已经展示了,就是当前时间啊。
总结
以上就是今天要讲的内容,MovedRegionsCleaner是HRegionServer上一个工作线程,它周期性的清理已被移动Region列表movedRegions中的到达时间的MovedRegionInfo信息,而线程工作的频率和MovedRegionInfo存活时间,均是TIMEOUT_REGION_MOVED,也就是2分钟。