请求链路
配置
RegionServer启动的时候,初始化加载配置
参数 | 含义 | 下文简称 |
|
---|---|---|---|
hbase.regionserver.throughput.controller | 对应的策略类 | 目前只有两种,一种限流,一种不限流 | |
hbase.hstore.compaction.throughput.lower.bound | 非空闲期,一般为白天忙时的最低阈值 | lower | 单位B (逻辑流量) 默认10MB |
hbase.hstore.compaction.throughput.higher.bound | 非空闲期,一般为白天忙时的最高阈值 | higher | 单位B (逻辑流量) 默认20MB 白天忙时流量阈值在lower和higher之间波动 |
hbase.offpeak.start.hour | 空闲期开始小时 | start hour | 例如 0 |
hbase.offpeak.end.hour | 空闲期结束小时 | end hour | 例如 6 , 1.06:00以后都不在offpeak的时间内
|
hbase.hstore.compaction.throughput.offpeak | start~end hour之间,空闲期的阈值 | OffpeakLimitSize | 单位B(逻辑流量) 默认:Long.MAX_VALUE 相当于不限流 |
阈值计算
1.计算当前RegionServer的compactPressure
PressureAwareCompactionThroughputController类中定期根据compactPressure计算实际流量阈值
每个HStore(一个region的其中一个列簇对应一个HStore)做下面计算,去这个机器上下面值最大的一个
计算逻辑
2.计算server级别的maxThroughput
compactPressure计算出来之后如何应用?
compactPressure > 1 ——说明现在hstore下文件数量大于 blockingfiles数量,已经出现阻塞flush的情况,写入内存的数据不能及时被持久化
maxThroughput = Long.MAX_VALUE
else if ( 在offpeak start~end时间内 )
maxThroughput=配置的OffpeakLimitSize
else
maxThroughput=lower + (higher - lower) * compactionPressure; —— 此时流量阈值在lower 和 higher之间随store下面文件数量 波动
3.计算每个compact的sleep时间,并进行sleep
每个compact 任务可用流量 = maxThroughput /当前active compact 任务数量
允许的时长 = ( 当前compact 任务的delta size / 每个compact 任务可用流量 ) * 1000 (单位ms)
已经流失时长=当前时间-上次实际执行compact时间
if 已经流失时长 >= 允许的时长 不执行sleep
else sleepTime = 已经流失时长 - 允许的时长
PressureAwareCompactionThroughputController里面的tuneChore定期获取server.getCompactionPressure()
用来做流量的计算
获取本server上所有region的所有store,store.getCompactionPressure最大的一个
store.getCompactionPressure如何计算
public double getCompactionPressure() {
return storeEngine.getStoreFileManager().getCompactionPressure();
}
@Override
public double getCompactionPressure() {
int storefileCount = getStorefileCount(); //文件数量
int minFilesToCompact = comConf.getMinFilesToCompact(); "hbase.hstore.compaction.min" 旧配置 “hbase.hstore.compactionThreshold” 未配置的为3
if (storefileCount <= minFilesToCompact) {
return 0.0;
}
//blockingFileCount = "hbase.hstore.blockingStoreFiles" 默认为7
//这个公式含义: 现在可compact的文件数是否超过需要blocking的数量
return (double) (storefileCount - minFilesToCompact) / (blockingFileCount - minFilesToCompact);
}
private void tune(double compactionPressure) {
double maxThroughputToSet;
// compactionPressure > 1.0 //超过了blocking File 不限流
if (compactionPressure > 1.0) {
// set to unlimited if some stores already reach the blocking store file count
maxThroughputToSet = Double.MAX_VALUE;
// 在空闲时间内
} else if (offPeakHours.isOffPeakHour()) {
maxThroughputToSet = maxThroughputOffpeak;
}
//不在空闲时间内
else {
// compactionPressure is between 0.0 and 1.0, we use a simple linear formula to
// calculate the throughput limitation.
maxThroughputToSet =
maxThroughputLowerBound + (maxThroughputHigherBound - maxThroughputLowerBound)
* compactionPressure;
}
if (LOG.isDebugEnabled()) {
LOG.debug("compactionPressure is " + compactionPressure + ", tune compaction throughput to "
+ throughputDesc(maxThroughputToSet));
}
this.maxThroughput = maxThroughputToSet;
}
//=====================================================================================================
@Override
public long control(String compactionName, long size) throws InterruptedException {
ActiveCompaction compaction = activeCompactions.get(compactionName);
compaction.totalSize += size;//当前这个compact的size累加
long deltaSize = compaction.totalSize - compaction.lastControlSize; //变化的值
//controlPerSize = max; 如果变化的值大于controlPerSize直接返回0
if (deltaSize < controlPerSize) {
return 0;
}
long now = EnvironmentEdgeManager.currentTimeMillis();
//maxThroughputPerCompaction(每个compact 流量) = 机器compact流量最大值 / 当前活跃的Compact任务数量
double maxThroughputPerCompaction = this.maxThroughput / activeCompactions.size();
// 最小允许时间 = 本次需要的流量 / 每个compact可用流量 *1000 ( 单位 ms)
long minTimeAllowed = (long) (deltaSize / maxThroughputPerCompaction * 1000); // ms
// 从上次触发control到这次的时间
long elapsedTime = now - compaction.lastControlTime;
compaction.lastControlSize = compaction.totalSize;
//如果 已经经过的时间 大于 最小控制时间 (说明时间已经充足了,直接返回0)
if (elapsedTime >= minTimeAllowed) {
compaction.lastControlTime = EnvironmentEdgeManager.currentTimeMillis();
return 0;
}
// 如果经过的时间,小于等于最小允许时间 说明:too fast
// sleepTime 可允许的时间-已经等待的时间
long sleepTime = minTimeAllowed - elapsedTime;
if (LOG.isDebugEnabled()) {
// do not log too much
if (now - compaction.lastLogTime > 60L * 1000) {
LOG.debug(compactionName + " sleep " + sleepTime + " ms because current throughput is "
+ throughputDesc(deltaSize, elapsedTime) + ", max allowed is "
+ throughputDesc(maxThroughputPerCompaction) + ", already slept "
+ compaction.numberOfSleeps + " time(s) and total slept time is "
+ compaction.totalSleepTime + " ms till now.");
compaction.lastLogTime = now;
}
}
Thread.sleep(sleepTime);
compaction.numberOfSleeps++;
compaction.totalSleepTime += sleepTime;
compaction.lastControlTime = EnvironmentEdgeManager.currentTimeMillis();
return sleepTime;
}