001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.mockito.Mockito.mock; 022import static org.mockito.Mockito.when; 023 024import java.util.ArrayList; 025import java.util.List; 026import java.util.OptionalDouble; 027import java.util.OptionalLong; 028import java.util.concurrent.atomic.AtomicInteger; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.HBaseConfiguration; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.HDFSBlocksDistribution; 033import org.apache.hadoop.hbase.ServerName; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.ipc.RpcServerInterface; 036import org.apache.hadoop.hbase.testclassification.RegionServerTests; 037import org.apache.hadoop.hbase.testclassification.SmallTests; 038import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 039import org.apache.hadoop.hbase.util.ManualEnvironmentEdge; 040import org.apache.hadoop.hbase.wal.WALFactory; 041import org.apache.hadoop.hbase.wal.WALProvider; 042import org.junit.jupiter.api.Tag; 043import org.junit.jupiter.api.Test; 044import org.mockito.Mockito; 045import org.mockito.stubbing.Answer; 046 047import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 048 049@Tag(SmallTests.TAG) 050@Tag(RegionServerTests.TAG) 051public class TestMetricsRegionServerAggregate { 052 053 @Test 054 public void test() { 055 AtomicInteger retVal = new AtomicInteger(0); 056 Answer defaultAnswer = invocation -> { 057 Class<?> returnType = invocation.getMethod().getReturnType(); 058 059 if (returnType.equals(Integer.TYPE) || returnType.equals(Integer.class)) { 060 return retVal.get(); 061 } else if (returnType.equals(Long.TYPE) || returnType.equals(Long.class)) { 062 return (long) retVal.get(); 063 } 064 return Mockito.RETURNS_DEFAULTS.answer(invocation); 065 }; 066 067 ServerName serverName = mock(ServerName.class); 068 when(serverName.getHostname()).thenReturn("foo"); 069 WALFactory walFactory = mock(WALFactory.class); 070 RpcServerInterface rpcServer = mock(RpcServerInterface.class); 071 AtomicInteger storeFileCount = new AtomicInteger(1); 072 HRegion regionOne = getMockedRegion(defaultAnswer, "a", "foo", true, storeFileCount); 073 HRegion regionTwo = getMockedRegion(defaultAnswer, "b", "bar", true, storeFileCount); 074 HRegion regionThree = getMockedRegion(defaultAnswer, "c", "foo", false, storeFileCount); 075 HRegion regionFour = getMockedRegion(defaultAnswer, "d", "bar", false, storeFileCount); 076 List<HRegion> regions = Lists.newArrayList(regionOne, regionTwo, regionThree, regionFour); 077 078 int numStoresPerRegion = 2; 079 for (HRegion region : regions) { 080 // if adding more stores, update numStoresPerRegion so that tests below continue working 081 assertEquals(numStoresPerRegion, region.getStores().size()); 082 } 083 084 HRegionServer regionServer = mock(HRegionServer.class, defaultAnswer); 085 when(regionServer.getWalFactory()).thenReturn(walFactory); 086 when(regionServer.getOnlineRegionsLocalContext()).thenReturn(regions); 087 when(regionServer.getServerName()).thenReturn(serverName); 088 Configuration conf = HBaseConfiguration.create(); 089 int metricsPeriodSec = 600; 090 // set a very long period so that it doesn't actually run during our very quick test 091 conf.setLong(HConstants.REGIONSERVER_METRICS_PERIOD, metricsPeriodSec * 1000); 092 when(regionServer.getConfiguration()).thenReturn(conf); 093 when(regionServer.getRpcServer()).thenReturn(rpcServer); 094 095 MetricsRegionServerWrapperImpl wrapper = new MetricsRegionServerWrapperImpl(regionServer); 096 097 // we need to control the edge because rate calculations expect a 098 // stable interval relative to the configured period 099 ManualEnvironmentEdge edge = new ManualEnvironmentEdge(); 100 EnvironmentEdgeManager.injectEdge(edge); 101 102 try { 103 for (int i = 1; i <= 10; i++) { 104 edge.incValue(wrapper.getPeriod()); 105 retVal.incrementAndGet(); 106 wrapper.forceRecompute(); 107 108 int numRegions = regions.size(); 109 int totalStores = numRegions * numStoresPerRegion; 110 111 // there are N regions, and each has M stores. everything gets aggregated, so 112 // multiply expected values accordingly 113 int expectedForRegions = retVal.get() * numRegions; 114 int expectedForStores = retVal.get() * totalStores; 115 116 assertEquals(totalStores, wrapper.getNumStores()); 117 assertEquals(expectedForStores, wrapper.getFlushedCellsCount()); 118 assertEquals(expectedForStores, wrapper.getCompactedCellsCount()); 119 assertEquals(expectedForStores, wrapper.getMajorCompactedCellsCount()); 120 assertEquals(expectedForStores, wrapper.getFlushedCellsSize()); 121 assertEquals(expectedForStores, wrapper.getCompactedCellsSize()); 122 assertEquals(expectedForStores, wrapper.getMajorCompactedCellsSize()); 123 assertEquals(expectedForRegions, wrapper.getCellsCountCompactedFromMob()); 124 assertEquals(expectedForRegions, wrapper.getCellsCountCompactedToMob()); 125 assertEquals(expectedForRegions, wrapper.getCellsSizeCompactedFromMob()); 126 assertEquals(expectedForRegions, wrapper.getCellsSizeCompactedToMob()); 127 assertEquals(expectedForRegions, wrapper.getMobFlushCount()); 128 assertEquals(expectedForRegions, wrapper.getMobFlushedCellsCount()); 129 assertEquals(expectedForRegions, wrapper.getMobFlushedCellsSize()); 130 assertEquals(expectedForRegions, wrapper.getMobScanCellsCount()); 131 assertEquals(expectedForRegions, wrapper.getMobScanCellsSize()); 132 assertEquals(expectedForRegions, wrapper.getCheckAndMutateChecksFailed()); 133 assertEquals(expectedForRegions, wrapper.getCheckAndMutateChecksPassed()); 134 assertEquals(expectedForStores, wrapper.getStoreFileIndexSize()); 135 assertEquals(expectedForStores, wrapper.getTotalStaticIndexSize()); 136 assertEquals(expectedForStores, wrapper.getTotalStaticBloomSize()); 137 assertEquals(expectedForStores, wrapper.getBloomFilterRequestsCount()); 138 assertEquals(expectedForStores, wrapper.getBloomFilterNegativeResultsCount()); 139 assertEquals(expectedForStores, wrapper.getBloomFilterEligibleRequestsCount()); 140 assertEquals(expectedForRegions, wrapper.getNumMutationsWithoutWAL()); 141 assertEquals(expectedForRegions, wrapper.getDataInMemoryWithoutWAL()); 142 assertEquals(expectedForRegions, wrapper.getAverageRegionSize()); 143 assertEquals(expectedForRegions, wrapper.getBlockedRequestsCount()); 144 assertEquals(expectedForStores, wrapper.getNumReferenceFiles()); 145 assertEquals(expectedForStores, wrapper.getMemStoreSize()); 146 assertEquals(expectedForStores, wrapper.getOnHeapMemStoreSize()); 147 assertEquals(expectedForStores, wrapper.getOffHeapMemStoreSize()); 148 assertEquals(expectedForStores, wrapper.getStoreFileSize()); 149 assertEquals(expectedForRegions, wrapper.getReadRequestsCount()); 150 assertEquals(expectedForRegions, wrapper.getCpRequestsCount()); 151 assertEquals(expectedForRegions, wrapper.getFilteredReadRequestsCount()); 152 assertEquals(expectedForRegions, wrapper.getWriteRequestsCount()); 153 assertEquals(expectedForRegions * 2, wrapper.getTotalRowActionRequestCount()); 154 155 // If we have N regions, each with M stores. That's N*M stores in total. In creating those 156 // stores, we increment the number and age of storefiles for each one. So the first 157 // store has 1 file of 1 age, then 2 files of 2 age, etc. 158 // formula for 1+2+3..+n 159 assertEquals((totalStores * (totalStores + 1)) / 2, wrapper.getNumStoreFiles()); 160 assertEquals(totalStores, wrapper.getMaxStoreFiles()); 161 assertEquals(totalStores, wrapper.getMaxStoreFileAge()); 162 assertEquals(1, wrapper.getMinStoreFileAge()); 163 assertEquals(totalStores / 2, wrapper.getAvgStoreFileAge()); 164 165 // there are four regions, two are primary and the other two secondary 166 // for each type, one region has 100% locality, the other has 0%. 167 // this just proves we correctly aggregate for each 168 assertEquals(50.0, wrapper.getPercentFileLocal(), 0.0001); 169 assertEquals(50.0, wrapper.getPercentFileLocalSecondaryRegions(), 0.0001); 170 171 // readRequestCount and writeRequestCount are tracking the value of i, which increases by 1 172 // each interval. There are N regions, so the delta each interval is N*i=N. So the rate is 173 // simply N / period. 174 assertEquals((double) numRegions / metricsPeriodSec, wrapper.getReadRequestsRatePerSecond(), 175 0.0001); 176 assertEquals((double) numRegions / metricsPeriodSec, 177 wrapper.getWriteRequestsRatePerSecond(), 0.0001); 178 // total of above, so multiply by 2 179 assertEquals((double) numRegions / metricsPeriodSec * 2, wrapper.getRequestsPerSecond(), 180 0.0001); 181 // Similar logic to above, except there are M totalStores and each one is of 182 // size tracking i. So the rate is just M / period. 183 assertEquals((double) totalStores / metricsPeriodSec, wrapper.getStoreFileSizeGrowthRate(), 184 0.0001); 185 } 186 } finally { 187 EnvironmentEdgeManager.reset(); 188 } 189 } 190 191 @Test 192 public void testWalMetricsForRegionServer() throws InterruptedException { 193 long numLogFiles = 10; 194 long logFileSize = 10240; 195 String hostname = "foo"; 196 Configuration conf = HBaseConfiguration.create(); 197 conf.setLong(HConstants.REGIONSERVER_METRICS_PERIOD, 1000); 198 199 HRegionServer regionServer = mock(HRegionServer.class); 200 when(regionServer.getConfiguration()).thenReturn(conf); 201 RpcServerInterface rpcServer = mock(RpcServerInterface.class); 202 when(regionServer.getRpcServer()).thenReturn(rpcServer); 203 WALFactory walFactory = mock(WALFactory.class); 204 WALProvider walProvider = mock(WALProvider.class); 205 when(walProvider.getNumLogFiles()).thenReturn(numLogFiles); 206 when(walProvider.getLogFileSize()).thenReturn(logFileSize); 207 List<WALProvider> providers = new ArrayList<>(); 208 providers.add(walProvider); 209 when(walFactory.getAllWALProviders()).thenReturn(providers); 210 when(regionServer.getWalFactory()).thenReturn(walFactory); 211 ServerName serverName = mock(ServerName.class); 212 when(serverName.getHostname()).thenReturn(hostname); 213 when(regionServer.getServerName()).thenReturn(serverName); 214 215 MetricsRegionServerWrapperImpl wrapper = new MetricsRegionServerWrapperImpl(regionServer); 216 MetricsRegionServerWrapperImpl.RegionServerMetricsWrapperRunnable runnable = 217 wrapper.new RegionServerMetricsWrapperRunnable(); 218 runnable.run(); 219 assertEquals(numLogFiles, wrapper.getNumWALFiles()); 220 assertEquals(logFileSize, wrapper.getWALFileSize()); 221 222 runnable.run(); 223 assertEquals(numLogFiles, wrapper.getNumWALFiles()); 224 assertEquals(logFileSize, wrapper.getWALFileSize()); 225 } 226 227 private HRegion getMockedRegion(Answer defaultAnswer, String name, String localOnHost, 228 boolean isPrimary, AtomicInteger storeFileCount) { 229 RegionInfo regionInfo = mock(RegionInfo.class); 230 when(regionInfo.getEncodedName()).thenReturn(name); 231 if (!isPrimary) { 232 when(regionInfo.getReplicaId()).thenReturn(RegionInfo.DEFAULT_REPLICA_ID + 1); 233 } 234 HDFSBlocksDistribution distribution = new HDFSBlocksDistribution(); 235 distribution.addHostsAndBlockWeight(new String[] { localOnHost }, 100); 236 237 HStore store = getMockedStore(HStore.class, defaultAnswer, storeFileCount); 238 HMobStore mobStore = getMockedStore(HMobStore.class, defaultAnswer, storeFileCount); 239 240 HRegion region = mock(HRegion.class, defaultAnswer); 241 when(region.getRegionInfo()).thenReturn(regionInfo); 242 when(region.getHDFSBlocksDistribution()).thenReturn(distribution); 243 when(region.getStores()).thenReturn(Lists.newArrayList(store, mobStore)); 244 return region; 245 } 246 247 private <T extends HStore> T getMockedStore(Class<T> clazz, Answer defaultAnswer, 248 AtomicInteger storeFileCount) { 249 T store = mock(clazz, defaultAnswer); 250 int storeFileCountVal = storeFileCount.getAndIncrement(); 251 when(store.getStorefilesCount()).thenReturn(storeFileCountVal); 252 when(store.getAvgStoreFileAge()).thenReturn(OptionalDouble.of(storeFileCountVal)); 253 when(store.getMaxStoreFileAge()).thenReturn(OptionalLong.of(storeFileCountVal)); 254 when(store.getMinStoreFileAge()).thenReturn(OptionalLong.of(storeFileCountVal)); 255 MemStoreSize memStore = mock(MemStoreSize.class, defaultAnswer); 256 when(store.getMemStoreSize()).thenReturn(memStore); 257 return store; 258 } 259 260}