HBASE-19924 hbase rpc throttling does not work for multi() with request count rater.

This commit is contained in:
Huaxiang Sun 2018-04-26 10:43:59 -07:00
parent ec131784e7
commit eb67d4e308
5 changed files with 63 additions and 27 deletions

View File

@ -61,13 +61,13 @@ public class DefaultOperationQuota implements OperationQuota {
for (final QuotaLimiter limiter : limiters) {
if (limiter.isBypass()) continue;
limiter.checkQuota(writeConsumed, readConsumed);
limiter.checkQuota(numWrites, writeConsumed, numReads + numScans, readConsumed);
readAvailable = Math.min(readAvailable, limiter.getReadAvailable());
writeAvailable = Math.min(writeAvailable, limiter.getWriteAvailable());
}
for (final QuotaLimiter limiter : limiters) {
limiter.grabQuota(writeConsumed, readConsumed);
limiter.grabQuota(numWrites, writeConsumed, numReads + numScans, readConsumed);
}
}

View File

@ -28,12 +28,13 @@ final class NoopQuotaLimiter implements QuotaLimiter {
}
@Override
public void checkQuota(long estimateWriteSize, long estimateReadSize) throws ThrottlingException {
public void checkQuota(long writeReqs, long estimateWriteSize, long readReqs,
long estimateReadSize) throws ThrottlingException {
// no-op
}
@Override
public void grabQuota(long writeSize, long readSize) {
public void grabQuota(long writeReqs, long writeSize, long readReqs, long readSize) {
// no-op
}

View File

@ -31,11 +31,13 @@ public interface QuotaLimiter {
/**
* Checks if it is possible to execute the specified operation.
*
* @param writeReqs the write requests that will be checked against the available quota
* @param estimateWriteSize the write size that will be checked against the available quota
* @param readReqs the read requests that will be checked against the available quota
* @param estimateReadSize the read size that will be checked against the available quota
* @throws ThrottlingException thrown if not enough avialable resources to perform operation.
*/
void checkQuota(long estimateWriteSize, long estimateReadSize)
void checkQuota(long writeReqs, long estimateWriteSize, long readReqs, long estimateReadSize)
throws ThrottlingException;
/**
@ -43,10 +45,12 @@ public interface QuotaLimiter {
* At this point the write and read amount will be an estimate,
* that will be later adjusted with a consumeWrite()/consumeRead() call.
*
* @param writeReqs the write requests that will be removed from the current quota
* @param writeSize the write size that will be removed from the current quota
* @param readReqs the read requests that will be removed from the current quota
* @param readSize the read size that will be removed from the current quota
*/
void grabQuota(long writeSize, long readSize);
void grabQuota(long writeReqs, long writeSize, long readReqs, long readSize);
/**
* Removes or add back some write amount to the quota.

View File

@ -110,47 +110,50 @@ public class TimeBasedLimiter implements QuotaLimiter {
}
@Override
public void checkQuota(long writeSize, long readSize) throws ThrottlingException {
if (!reqsLimiter.canExecute()) {
public void checkQuota(long writeReqs, long estimateWriteSize, long readReqs,
long estimateReadSize) throws ThrottlingException {
if (!reqsLimiter.canExecute(writeReqs + readReqs)) {
ThrottlingException.throwNumRequestsExceeded(reqsLimiter.waitInterval());
}
if (!reqSizeLimiter.canExecute(writeSize + readSize)) {
ThrottlingException.throwRequestSizeExceeded(reqSizeLimiter
.waitInterval(writeSize + readSize));
if (!reqSizeLimiter.canExecute(estimateWriteSize + estimateReadSize)) {
ThrottlingException.throwRequestSizeExceeded(
reqSizeLimiter.waitInterval(estimateWriteSize + estimateReadSize));
}
if (writeSize > 0) {
if (!writeReqsLimiter.canExecute()) {
if (estimateWriteSize > 0) {
if (!writeReqsLimiter.canExecute(writeReqs)) {
ThrottlingException.throwNumWriteRequestsExceeded(writeReqsLimiter.waitInterval());
}
if (!writeSizeLimiter.canExecute(writeSize)) {
ThrottlingException.throwWriteSizeExceeded(writeSizeLimiter.waitInterval(writeSize));
if (!writeSizeLimiter.canExecute(estimateWriteSize)) {
ThrottlingException.throwWriteSizeExceeded(
writeSizeLimiter.waitInterval(estimateWriteSize));
}
}
if (readSize > 0) {
if (!readReqsLimiter.canExecute()) {
if (estimateReadSize > 0) {
if (!readReqsLimiter.canExecute(readReqs)) {
ThrottlingException.throwNumReadRequestsExceeded(readReqsLimiter.waitInterval());
}
if (!readSizeLimiter.canExecute(readSize)) {
ThrottlingException.throwReadSizeExceeded(readSizeLimiter.waitInterval(readSize));
if (!readSizeLimiter.canExecute(estimateReadSize)) {
ThrottlingException.throwReadSizeExceeded(
readSizeLimiter.waitInterval(estimateReadSize));
}
}
}
@Override
public void grabQuota(long writeSize, long readSize) {
public void grabQuota(long writeReqs, long writeSize, long readReqs, long readSize) {
assert writeSize != 0 || readSize != 0;
reqsLimiter.consume(1);
reqsLimiter.consume(writeReqs + readReqs);
reqSizeLimiter.consume(writeSize + readSize);
if (writeSize > 0) {
writeReqsLimiter.consume(1);
writeReqsLimiter.consume(writeReqs);
writeSizeLimiter.consume(writeSize);
}
if (readSize > 0) {
readReqsLimiter.consume(1);
readReqsLimiter.consume(readReqs);
readSizeLimiter.consume(readSize);
}
}

View File

@ -184,6 +184,34 @@ public class TestQuotaState {
assertNoopLimiter(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
}
@Test(timeout = 60000)
public void testTableThrottleWithBatch() {
final TableName TABLE_A = TableName.valueOf("TableA");
final int TABLE_A_THROTTLE_1 = 3;
final long LAST_UPDATE_1 = 10;
UserQuotaState quotaInfo = new UserQuotaState();
assertEquals(0, quotaInfo.getLastUpdate());
assertTrue(quotaInfo.isBypass());
// Add A table limiters
UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE_1);
otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_1));
assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
assertFalse(otherQuotaState.isBypass());
quotaInfo.update(otherQuotaState);
assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
assertFalse(quotaInfo.isBypass());
QuotaLimiter limiter = quotaInfo.getTableLimiter(TABLE_A);
try {
limiter.checkQuota(TABLE_A_THROTTLE_1 + 1, TABLE_A_THROTTLE_1 + 1, 0, 0);
fail("Should have thrown ThrottlingException");
} catch (ThrottlingException e) {
// expected
}
}
private Quotas buildReqNumThrottle(final long limit) {
return Quotas
.newBuilder()
@ -196,7 +224,7 @@ public class TestQuotaState {
private void assertThrottleException(final QuotaLimiter limiter, final int availReqs) {
assertNoThrottleException(limiter, availReqs);
try {
limiter.checkQuota(1, 1);
limiter.checkQuota(1, 1, 0, 0);
fail("Should have thrown ThrottlingException");
} catch (ThrottlingException e) {
// expected
@ -206,11 +234,11 @@ public class TestQuotaState {
private void assertNoThrottleException(final QuotaLimiter limiter, final int availReqs) {
for (int i = 0; i < availReqs; ++i) {
try {
limiter.checkQuota(1, 1);
limiter.checkQuota(1, 1, 0, 0);
} catch (ThrottlingException e) {
fail("Unexpected ThrottlingException after " + i + " requests. limit=" + availReqs);
}
limiter.grabQuota(1, 1);
limiter.grabQuota(1, 1, 0, 0);
}
}
@ -218,4 +246,4 @@ public class TestQuotaState {
assertTrue(limiter == NoopQuotaLimiter.get());
assertNoThrottleException(limiter, 100);
}
}
}