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