HBASE-25026 Create a metric to track full region scans RPCs

Add new metric rpcFullScanRequestCount to track number of requests that are full region scans. Can be used to notify user to check if this is truly intended.

Signed-off-by Anoop Sam John <anoopsamjohn@apache.org>
Signed-off-by Ramkrishna S Vasudevan <ramkrishna@apache.org>
This commit is contained in:
gkanade 2020-11-18 20:25:33 -08:00 committed by GitHub
parent fdff8ef46d
commit 024349bd5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 213 additions and 4 deletions

View File

@ -565,6 +565,9 @@ public interface MetricsRegionServerSource extends BaseSource, JvmPauseMonitorSo
String RPC_SCAN_REQUEST_COUNT = "rpcScanRequestCount"; String RPC_SCAN_REQUEST_COUNT = "rpcScanRequestCount";
String RPC_SCAN_REQUEST_COUNT_DESC = String RPC_SCAN_REQUEST_COUNT_DESC =
"Number of rpc scan requests this RegionServer has answered."; "Number of rpc scan requests this RegionServer has answered.";
String RPC_FULL_SCAN_REQUEST_COUNT = "rpcFullScanRequestCount";
String RPC_FULL_SCAN_REQUEST_COUNT_DESC =
"Number of rpc scan requests that were possible full region scans.";
String RPC_MULTI_REQUEST_COUNT = "rpcMultiRequestCount"; String RPC_MULTI_REQUEST_COUNT = "rpcMultiRequestCount";
String RPC_MULTI_REQUEST_COUNT_DESC = String RPC_MULTI_REQUEST_COUNT_DESC =
"Number of rpc multi requests this RegionServer has answered."; "Number of rpc multi requests this RegionServer has answered.";

View File

@ -482,6 +482,11 @@ public interface MetricsRegionServerWrapper {
*/ */
long getRpcScanRequestsCount(); long getRpcScanRequestsCount();
/**
* Get the number of full region rpc scan requests to this region server.
*/
long getRpcFullScanRequestsCount();
/** /**
* Get the number of rpc multi requests to this region server. * Get the number of rpc multi requests to this region server.
*/ */

View File

@ -349,6 +349,8 @@ public class MetricsRegionServerSourceImpl
rsWrap.getWriteRequestsCount()) rsWrap.getWriteRequestsCount())
.addCounter(Interns.info(RPC_GET_REQUEST_COUNT, RPC_GET_REQUEST_COUNT_DESC), .addCounter(Interns.info(RPC_GET_REQUEST_COUNT, RPC_GET_REQUEST_COUNT_DESC),
rsWrap.getRpcGetRequestsCount()) rsWrap.getRpcGetRequestsCount())
.addCounter(Interns.info(RPC_FULL_SCAN_REQUEST_COUNT, RPC_FULL_SCAN_REQUEST_COUNT_DESC),
rsWrap.getRpcFullScanRequestsCount())
.addCounter(Interns.info(RPC_SCAN_REQUEST_COUNT, RPC_SCAN_REQUEST_COUNT_DESC), .addCounter(Interns.info(RPC_SCAN_REQUEST_COUNT, RPC_SCAN_REQUEST_COUNT_DESC),
rsWrap.getRpcScanRequestsCount()) rsWrap.getRpcScanRequestsCount())
.addCounter(Interns.info(RPC_MULTI_REQUEST_COUNT, RPC_MULTI_REQUEST_COUNT_DESC), .addCounter(Interns.info(RPC_MULTI_REQUEST_COUNT, RPC_MULTI_REQUEST_COUNT_DESC),

View File

@ -2792,6 +2792,7 @@ public class HRegionServer extends Thread implements
rpcServices.requestCount.reset(); rpcServices.requestCount.reset();
rpcServices.rpcGetRequestCount.reset(); rpcServices.rpcGetRequestCount.reset();
rpcServices.rpcScanRequestCount.reset(); rpcServices.rpcScanRequestCount.reset();
rpcServices.rpcFullScanRequestCount.reset();
rpcServices.rpcMultiRequestCount.reset(); rpcServices.rpcMultiRequestCount.reset();
rpcServices.rpcMutateRequestCount.reset(); rpcServices.rpcMutateRequestCount.reset();
LOG.info("reportForDuty to master=" + masterServerName + " with port=" LOG.info("reportForDuty to master=" + masterServerName + " with port="

View File

@ -487,6 +487,11 @@ class MetricsRegionServerWrapperImpl
return regionServer.rpcServices.rpcScanRequestCount.sum(); return regionServer.rpcServices.rpcScanRequestCount.sum();
} }
@Override
public long getRpcFullScanRequestsCount() {
return regionServer.rpcServices.rpcFullScanRequestCount.sum();
}
@Override @Override
public long getRpcMultiRequestsCount() { public long getRpcMultiRequestsCount() {
return regionServer.rpcServices.rpcMultiRequestCount.sum(); return regionServer.rpcServices.rpcMultiRequestCount.sum();

View File

@ -311,6 +311,9 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
// Request counter for rpc scan // Request counter for rpc scan
final LongAdder rpcScanRequestCount = new LongAdder(); final LongAdder rpcScanRequestCount = new LongAdder();
// Request counter for scans that might end up in full scans
final LongAdder rpcFullScanRequestCount = new LongAdder();
// Request counter for rpc multi // Request counter for rpc multi
final LongAdder rpcMultiRequestCount = new LongAdder(); final LongAdder rpcMultiRequestCount = new LongAdder();
@ -455,15 +458,18 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
private final RpcCallback shippedCallback; private final RpcCallback shippedCallback;
private byte[] rowOfLastPartialResult; private byte[] rowOfLastPartialResult;
private boolean needCursor; private boolean needCursor;
private boolean fullRegionScan;
public RegionScannerHolder(String scannerName, RegionScanner s, HRegion r, public RegionScannerHolder(String scannerName, RegionScanner s, HRegion r,
RpcCallback closeCallBack, RpcCallback shippedCallback, boolean needCursor) { RpcCallback closeCallBack, RpcCallback shippedCallback, boolean needCursor,
boolean fullRegionScan) {
this.scannerName = scannerName; this.scannerName = scannerName;
this.s = s; this.s = s;
this.r = r; this.r = r;
this.closeCallBack = closeCallBack; this.closeCallBack = closeCallBack;
this.shippedCallback = shippedCallback; this.shippedCallback = shippedCallback;
this.needCursor = needCursor; this.needCursor = needCursor;
this.fullRegionScan = fullRegionScan;
} }
public long getNextCallSeq() { public long getNextCallSeq() {
@ -1322,7 +1328,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
} }
private RegionScannerHolder addScanner(String scannerName, RegionScanner s, Shipper shipper, private RegionScannerHolder addScanner(String scannerName, RegionScanner s, Shipper shipper,
HRegion r, boolean needCursor) throws LeaseStillHeldException { HRegion r, boolean needCursor, boolean fullRegionScan) throws LeaseStillHeldException {
Lease lease = regionServer.getLeaseManager().createLease( Lease lease = regionServer.getLeaseManager().createLease(
scannerName, this.scannerLeaseTimeoutPeriod, new ScannerListener(scannerName)); scannerName, this.scannerLeaseTimeoutPeriod, new ScannerListener(scannerName));
RpcCallback shippedCallback = new RegionScannerShippedCallBack(scannerName, shipper, lease); RpcCallback shippedCallback = new RegionScannerShippedCallBack(scannerName, shipper, lease);
@ -1332,14 +1338,30 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
} else { } else {
closeCallback = new RegionScannerCloseCallBack(s); closeCallback = new RegionScannerCloseCallBack(s);
} }
RegionScannerHolder rsh = RegionScannerHolder rsh =
new RegionScannerHolder(scannerName, s, r, closeCallback, shippedCallback, needCursor); new RegionScannerHolder(scannerName, s, r, closeCallback, shippedCallback,
needCursor, fullRegionScan);
RegionScannerHolder existing = scanners.putIfAbsent(scannerName, rsh); RegionScannerHolder existing = scanners.putIfAbsent(scannerName, rsh);
assert existing == null : "scannerId must be unique within regionserver's whole lifecycle! " + assert existing == null : "scannerId must be unique within regionserver's whole lifecycle! " +
scannerName; scannerName;
return rsh; return rsh;
} }
private boolean isFullRegionScan(Scan scan, HRegion region) {
// If the scan start row equals or less than the start key of the region
// and stop row greater than equals end key (if stop row present)
// or if the stop row is empty
// account this as a full region scan
if (Bytes.compareTo(scan.getStartRow(), region.getRegionInfo().getStartKey()) <= 0
&& (Bytes.compareTo(scan.getStopRow(), region.getRegionInfo().getEndKey()) >= 0 &&
!Bytes.equals(region.getRegionInfo().getEndKey(), HConstants.EMPTY_END_ROW)
|| Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW))) {
return true;
}
return false;
}
/** /**
* Find the HRegion based on a region specifier * Find the HRegion based on a region specifier
* *
@ -3083,7 +3105,12 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
builder.setMvccReadPoint(scanner.getMvccReadPoint()); builder.setMvccReadPoint(scanner.getMvccReadPoint());
builder.setTtl(scannerLeaseTimeoutPeriod); builder.setTtl(scannerLeaseTimeoutPeriod);
String scannerName = String.valueOf(scannerId); String scannerName = String.valueOf(scannerId);
return addScanner(scannerName, scanner, shipper, region, scan.isNeedCursorResult());
boolean fullRegionScan = !region.getRegionInfo().getTable().isSystemTable() &&
isFullRegionScan(scan, region);
return addScanner(scannerName, scanner, shipper, region, scan.isNeedCursorResult(),
fullRegionScan);
} }
private void checkScanNextCallSeq(ScanRequest request, RegionScannerHolder rsh) private void checkScanNextCallSeq(ScanRequest request, RegionScannerHolder rsh)
@ -3397,6 +3424,9 @@ public class RSRpcServices implements HBaseRPCErrorHandler,
} }
throw new ServiceException(e); throw new ServiceException(e);
} }
if (rsh.fullRegionScan) {
rpcFullScanRequestCount.increment();
}
HRegion region = rsh.r; HRegion region = rsh.r;
String scannerName = rsh.scannerName; String scannerName = rsh.scannerName;
LeaseManager.Lease lease; LeaseManager.Lease lease;

View File

@ -619,4 +619,9 @@ public class MetricsRegionServerWrapperStub implements MetricsRegionServerWrappe
public long getAverageRegionSize() { public long getAverageRegionSize() {
return 10000000; return 10000000;
} }
@Override
public long getRpcFullScanRequestsCount() {
return 10;
}
} }

View File

@ -0,0 +1,158 @@
/*
* 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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.MiniHBaseCluster.MiniHBaseClusterRegionServer;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.TestClientScannerRPCTimeout;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
@Category({ RegionServerTests.class, MediumTests.class})
public class TestScannerRPCScanMetrics {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestScannerRPCScanMetrics.class);
private static final Logger LOG = LoggerFactory.getLogger(TestScannerRPCScanMetrics.class);
private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
private static final byte[] FAMILY = Bytes.toBytes("testFamily");
private static final byte[] QUALIFIER = Bytes.toBytes("testQualifier");
private static final byte[] VALUE = Bytes.toBytes("testValue");
@Rule
public TestName name = new TestName();
@BeforeClass
public static void setupBeforeClass() throws Exception {
Configuration conf = TEST_UTIL.getConfiguration();
conf.setStrings(HConstants.REGION_SERVER_IMPL, RegionServerWithScanMetrics.class.getName());
TEST_UTIL.startMiniCluster(1);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}
@Test
public void testScannerRPCScanMetrics() throws Exception {
final TableName tableName = TableName.valueOf(name.getMethodName());
byte[][] splits = new byte[1][];
splits[0] = Bytes.toBytes("row-4");
Table ht = TEST_UTIL.createTable(tableName, FAMILY,splits);
byte[] r0 = Bytes.toBytes("row-0");
byte[] r1 = Bytes.toBytes("row-1");
byte[] r2 = Bytes.toBytes("row-2");
byte[] r3 = Bytes.toBytes("row-3");
putToTable(ht, r0);
putToTable(ht, r1);
putToTable(ht, r2);
putToTable(ht, r3);
LOG.info("Wrote our four table entries");
Scan scan1 = new Scan();
scan1.withStartRow(r0);
// This scan should not increment rpc full scan count (start row specified)
scan1.withStopRow(Bytes.toBytes("row-4"));
scanNextIterate(ht, scan1);
Scan scan2 = new Scan();
scan2.withStartRow(r1);
// This scan should increment rpc full scan count by 1 (for second region only)
scanNextIterate(ht, scan2);
Scan scan3 = new Scan();
scan3.withStopRow(Bytes.toBytes("row-5"));
// This scan should increment rpc full scan count by 1 (for firts region only)
scanNextIterate(ht, scan3);
Scan scan4 = new Scan();
scan4.withStartRow(r1);
scan4.withStopRow(r2);
// This scan should not increment rpc full scan count (both start and stop row)
scanNextIterate(ht, scan4);
Scan dummyScan = new Scan();
// This scan should increment rpc full scan count by 2 (both regions - no stop/start row)
scanNextIterate(ht, dummyScan);
RSRpcServices testClusterRSRPCServices = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0)
.rpcServices;
assertEquals(4, testClusterRSRPCServices.rpcFullScanRequestCount.intValue());
}
private void putToTable(Table ht, byte[] rowkey) throws IOException {
Put put = new Put(rowkey);
put.addColumn(FAMILY, QUALIFIER, VALUE);
ht.put(put);
}
private void scanNextIterate(Table ht, Scan scan) throws Exception{
ResultScanner scanner = ht.getScanner(scan);
for (Result result = scanner.next(); result != null; result = scanner.next())
{
// Use the result object
}
scanner.close();
}
private static class RegionServerWithScanMetrics extends MiniHBaseClusterRegionServer {
public RegionServerWithScanMetrics(Configuration conf)
throws IOException, InterruptedException {
super(conf);
}
protected RSRpcServices createRPCServices() throws IOException {
return new RSRPCServicesWithScanMetrics(this);
}
}
private static class RSRPCServicesWithScanMetrics extends RSRpcServices {
public long getScanRequestCount() {
return super.rpcScanRequestCount.longValue();
}
public long getFullScanRequestCount() {
return super.rpcFullScanRequestCount.longValue();
}
public RSRPCServicesWithScanMetrics(HRegionServer rs)
throws IOException {
super(rs);
}
}
}