org.apache.hadoop.hbase.regionserver.throttle.PressureAwareThroughputController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hbase-server Show documentation
Show all versions of hbase-server Show documentation
Server functionality for HBase
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.regionserver.throttle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.Stoppable;
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
import org.apache.hadoop.hbase.regionserver.compactions.OffPeakHours;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
public abstract class PressureAwareThroughputController extends Configured
implements ThroughputController, Stoppable {
private static final Logger LOG =
LoggerFactory.getLogger(PressureAwareThroughputController.class);
/**
* Stores the information of one controlled compaction.
*/
private static final class ActiveOperation {
private final long startTime;
private long lastControlTime;
private long lastControlSize;
private long totalSize;
private long numberOfSleeps;
private long totalSleepTime;
// prevent too many debug log
private long lastLogTime;
ActiveOperation() {
long currentTime = EnvironmentEdgeManager.currentTime();
this.startTime = currentTime;
this.lastControlTime = currentTime;
this.lastLogTime = currentTime;
}
}
protected long maxThroughputUpperBound;
protected long maxThroughputLowerBound;
protected OffPeakHours offPeakHours;
protected long controlPerSize;
protected int tuningPeriod;
private volatile double maxThroughput;
private volatile double maxThroughputPerOperation;
protected final ConcurrentMap activeOperations =
new ConcurrentHashMap<>();
@Override
public abstract void setup(final RegionServerServices server);
protected String throughputDesc(long deltaSize, long elapsedTime) {
return throughputDesc((double) deltaSize / elapsedTime * 1000);
}
protected String throughputDesc(double speed) {
if (speed >= 1E15) { // large enough to say it is unlimited
return "unlimited";
} else {
return String.format("%.2f MB/second", speed / 1024 / 1024);
}
}
@Override
public void start(String opName) {
activeOperations.put(opName, new ActiveOperation());
maxThroughputPerOperation = getMaxThroughput() / activeOperations.size();
}
@Override
public long control(String opName, long size) throws InterruptedException {
ActiveOperation operation = activeOperations.get(opName);
operation.totalSize += size;
long deltaSize = operation.totalSize - operation.lastControlSize;
if (deltaSize < controlPerSize) {
return 0;
}
long now = EnvironmentEdgeManager.currentTime();
long minTimeAllowed = (long) (deltaSize / maxThroughputPerOperation * 1000); // ms
long elapsedTime = now - operation.lastControlTime;
operation.lastControlSize = operation.totalSize;
if (elapsedTime >= minTimeAllowed) {
operation.lastControlTime = EnvironmentEdgeManager.currentTime();
return 0;
}
// too fast
long sleepTime = minTimeAllowed - elapsedTime;
if (LOG.isDebugEnabled()) {
// do not log too much
if (now - operation.lastLogTime > 5L * 1000) {
LOG.debug("deltaSize: " + deltaSize + " bytes; elapseTime: " + elapsedTime + " ns");
LOG.debug(opName + " sleep=" + sleepTime + "ms because current throughput is "
+ throughputDesc(deltaSize, elapsedTime) + ", max allowed is "
+ throughputDesc(maxThroughputPerOperation) + ", already slept "
+ operation.numberOfSleeps + " time(s) and total slept time is "
+ operation.totalSleepTime + " ms till now.");
operation.lastLogTime = now;
}
}
Thread.sleep(sleepTime);
operation.numberOfSleeps++;
operation.totalSleepTime += sleepTime;
operation.lastControlTime = EnvironmentEdgeManager.currentTime();
return sleepTime;
}
@Override
public void finish(String opName) {
ActiveOperation operation = activeOperations.remove(opName);
maxThroughputPerOperation = getMaxThroughput() / activeOperations.size();
long elapsedTime = EnvironmentEdgeManager.currentTime() - operation.startTime;
LOG.info(opName + " average throughput is " + throughputDesc(operation.totalSize, elapsedTime)
+ ", slept " + operation.numberOfSleeps + " time(s) and total slept time is "
+ operation.totalSleepTime + " ms. " + activeOperations.size()
+ " active operations remaining, total limit is " + throughputDesc(getMaxThroughput()));
}
private volatile boolean stopped = false;
@Override
public void stop(String why) {
stopped = true;
}
@Override
public boolean isStopped() {
return stopped;
}
public double getMaxThroughput() {
return maxThroughput;
}
public void setMaxThroughput(double maxThroughput) {
this.maxThroughput = maxThroughput;
maxThroughputPerOperation = getMaxThroughput() / activeOperations.size();
}
}