View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.regionserver;
19  
20  import org.apache.commons.lang.StringUtils;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
25  import org.apache.hadoop.hbase.HDFSBlocksDistribution;
26  import org.apache.hadoop.hbase.ServerName;
27  import org.apache.hadoop.hbase.io.hfile.BlockCache;
28  import org.apache.hadoop.hbase.io.hfile.CacheConfig;
29  import org.apache.hadoop.hbase.io.hfile.CacheStats;
30  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
31  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
32  import org.apache.hadoop.metrics2.MetricsExecutor;
33  
34  import java.util.Collection;
35  import java.util.concurrent.ScheduledExecutorService;
36  import java.util.concurrent.TimeUnit;
37  
38  /**
39   * Impl for exposing HRegionServer Information through Hadoop's metrics 2 system.
40   */
41  @InterfaceAudience.Private
42  class MetricsRegionServerWrapperImpl
43      implements MetricsRegionServerWrapper {
44  
45    public static final Log LOG = LogFactory.getLog(MetricsRegionServerWrapperImpl.class);
46  
47    public static final int PERIOD = 15;
48  
49    private final HRegionServer regionServer;
50  
51    private BlockCache blockCache;
52  
53    private volatile long numStores = 0;
54    private volatile long numStoreFiles = 0;
55    private volatile long memstoreSize = 0;
56    private volatile long storeFileSize = 0;
57    private volatile double requestsPerSecond = 0.0;
58    private volatile long readRequestsCount = 0;
59    private volatile long writeRequestsCount = 0;
60    private volatile long checkAndMutateChecksFailed = 0;
61    private volatile long checkAndMutateChecksPassed = 0;
62    private volatile long storefileIndexSize = 0;
63    private volatile long totalStaticIndexSize = 0;
64    private volatile long totalStaticBloomSize = 0;
65    private volatile long numMutationsWithoutWAL = 0;
66    private volatile long dataInMemoryWithoutWAL = 0;
67    private volatile int percentFileLocal = 0;
68  
69    private CacheStats cacheStats;
70    private ScheduledExecutorService executor;
71    private Runnable runnable;
72  
73    public MetricsRegionServerWrapperImpl(final HRegionServer regionServer) {
74      this.regionServer = regionServer;
75      initBlockCache();
76  
77      this.executor = CompatibilitySingletonFactory.getInstance(MetricsExecutor.class).getExecutor();
78      this.runnable = new RegionServerMetricsWrapperRunnable();
79      this.executor.scheduleWithFixedDelay(this.runnable, PERIOD, PERIOD, TimeUnit.SECONDS);
80    }
81  
82    /**
83     * It's possible that due to threading the block cache could not be initialized
84     * yet (testing multiple region servers in one jvm).  So we need to try and initialize
85     * the blockCache and cacheStats reference multiple times until we succeed.
86     */
87    private synchronized  void initBlockCache() {
88      CacheConfig cacheConfig = this.regionServer.cacheConfig;
89      if (cacheConfig != null && this.blockCache == null) {
90        this.blockCache = cacheConfig.getBlockCache();
91      }
92  
93      if (this.blockCache != null && this.cacheStats == null) {
94        this.cacheStats = blockCache.getStats();
95      }
96    }
97  
98    @Override
99    public String getClusterId() {
100     return regionServer.getClusterId();
101   }
102 
103   @Override
104   public long getStartCode() {
105     return regionServer.getStartcode();
106   }
107 
108   @Override
109   public String getZookeeperQuorum() {
110     ZooKeeperWatcher zk = regionServer.getZooKeeperWatcher();
111     if (zk == null) {
112       return "";
113     }
114     return zk.getQuorum();
115   }
116 
117   @Override
118   public String getCoprocessors() {
119     String[] coprocessors = regionServer.getCoprocessors();
120     if (coprocessors == null || coprocessors.length == 0) {
121       return "";
122     }
123     return StringUtils.join(coprocessors, ", ");
124   }
125 
126   @Override
127   public String getServerName() {
128     ServerName serverName = regionServer.getServerName();
129     if (serverName == null) {
130       return "";
131     }
132     return serverName.getServerName();
133   }
134 
135   @Override
136   public long getNumOnlineRegions() {
137     Collection<HRegion> onlineRegionsLocalContext = regionServer.getOnlineRegionsLocalContext();
138     if (onlineRegionsLocalContext == null) {
139       return 0;
140     }
141     return onlineRegionsLocalContext.size();
142   }
143 
144   @Override
145   public long getTotalRequestCount() {
146     return regionServer.requestCount.get();
147   }
148 
149   @Override
150   public int getCompactionQueueSize() {
151     //The thread could be zero.  if so assume there is no queue.
152     if (this.regionServer.compactSplitThread == null) {
153       return 0;
154     }
155     return this.regionServer.compactSplitThread.getCompactionQueueSize();
156   }
157 
158   @Override
159   public int getFlushQueueSize() {
160     //If there is no flusher there should be no queue.
161     if (this.regionServer.cacheFlusher == null) {
162       return 0;
163     }
164     return this.regionServer.cacheFlusher.getFlushQueueSize();
165   }
166 
167   @Override
168   public long getBlockCacheCount() {
169     if (this.blockCache == null) {
170       return 0;
171     }
172     return this.blockCache.size();
173   }
174 
175   @Override
176   public long getBlockCacheSize() {
177     if (this.blockCache == null) {
178       return 0;
179     }
180     return this.blockCache.getCurrentSize();
181   }
182 
183   @Override
184   public long getBlockCacheFreeSize() {
185     if (this.blockCache == null) {
186       return 0;
187     }
188     return this.blockCache.getFreeSize();
189   }
190 
191   @Override
192   public long getBlockCacheHitCount() {
193     if (this.cacheStats == null) {
194       return 0;
195     }
196     return this.cacheStats.getHitCount();
197   }
198 
199   @Override
200   public long getBlockCacheMissCount() {
201     if (this.cacheStats == null) {
202       return 0;
203     }
204     return this.cacheStats.getMissCount();
205   }
206 
207   @Override
208   public long getBlockCacheEvictedCount() {
209     if (this.cacheStats == null) {
210       return 0;
211     }
212     return this.cacheStats.getEvictedCount();
213   }
214 
215   @Override
216   public int getBlockCacheHitPercent() {
217     if (this.cacheStats == null) {
218       return 0;
219     }
220     return (int) (this.cacheStats.getHitRatio() * 100);
221   }
222 
223   @Override
224   public int getBlockCacheHitCachingPercent() {
225     if (this.cacheStats == null) {
226       return 0;
227     }
228     return (int) (this.cacheStats.getHitCachingRatio() * 100);
229   }
230 
231   @Override public void forceRecompute() {
232     this.runnable.run();
233   }
234 
235   @Override
236   public long getNumStores() {
237     return numStores;
238   }
239 
240   @Override
241   public long getNumStoreFiles() {
242     return numStoreFiles;
243   }
244 
245   @Override
246   public long getMemstoreSize() {
247     return memstoreSize;
248   }
249 
250   @Override
251   public long getStoreFileSize() {
252     return storeFileSize;
253   }
254 
255   @Override public double getRequestsPerSecond() {
256     return requestsPerSecond;
257   }
258 
259   @Override
260   public long getReadRequestsCount() {
261     return readRequestsCount;
262   }
263 
264   @Override
265   public long getWriteRequestsCount() {
266     return writeRequestsCount;
267   }
268 
269   @Override
270   public long getCheckAndMutateChecksFailed() {
271     return checkAndMutateChecksFailed;
272   }
273 
274   @Override
275   public long getCheckAndMutateChecksPassed() {
276     return checkAndMutateChecksPassed;
277   }
278 
279   @Override
280   public long getStoreFileIndexSize() {
281     return storefileIndexSize;
282   }
283 
284   @Override
285   public long getTotalStaticIndexSize() {
286     return totalStaticIndexSize;
287   }
288 
289   @Override
290   public long getTotalStaticBloomSize() {
291     return totalStaticBloomSize;
292   }
293 
294   @Override
295   public long getNumMutationsWithoutWAL() {
296     return numMutationsWithoutWAL;
297   }
298 
299   @Override
300   public long getDataInMemoryWithoutWAL() {
301     return dataInMemoryWithoutWAL;
302   }
303 
304   @Override
305   public int getPercentFileLocal() {
306     return percentFileLocal;
307   }
308 
309   @Override
310   public long getUpdatesBlockedTime() {
311     if (this.regionServer.cacheFlusher == null) {
312       return 0;
313     }
314     return this.regionServer.cacheFlusher.getUpdatesBlockedMsHighWater().get();
315   }
316 
317 
318   /**
319    * This is the runnable that will be executed on the executor every PERIOD number of seconds
320    * It will take metrics/numbers from all of the regions and use them to compute point in
321    * time metrics.
322    */
323   public class RegionServerMetricsWrapperRunnable implements Runnable {
324 
325     private long lastRan = 0;
326     private long lastRequestCount = 0;
327 
328     @Override
329     synchronized public void run() {
330       initBlockCache();
331       cacheStats = blockCache.getStats();
332 
333       HDFSBlocksDistribution hdfsBlocksDistribution =
334           new HDFSBlocksDistribution();
335 
336       long tempNumStores = 0;
337       long tempNumStoreFiles = 0;
338       long tempMemstoreSize = 0;
339       long tempStoreFileSize = 0;
340       long tempReadRequestsCount = 0;
341       long tempWriteRequestsCount = 0;
342       long tempCheckAndMutateChecksFailed = 0;
343       long tempCheckAndMutateChecksPassed = 0;
344       long tempStorefileIndexSize = 0;
345       long tempTotalStaticIndexSize = 0;
346       long tempTotalStaticBloomSize = 0;
347       long tempNumMutationsWithoutWAL = 0;
348       long tempDataInMemoryWithoutWAL = 0;
349       int tempPercentFileLocal = 0;
350 
351 
352       for (HRegion r : regionServer.getOnlineRegionsLocalContext()) {
353         tempNumMutationsWithoutWAL += r.numMutationsWithoutWAL.get();
354         tempDataInMemoryWithoutWAL += r.dataInMemoryWithoutWAL.get();
355         tempReadRequestsCount += r.readRequestsCount.get();
356         tempWriteRequestsCount += r.writeRequestsCount.get();
357         tempCheckAndMutateChecksFailed += r.checkAndMutateChecksFailed.get();
358         tempCheckAndMutateChecksPassed += r.checkAndMutateChecksPassed.get();
359         tempNumStores += r.stores.size();
360         for (Store store : r.stores.values()) {
361           tempNumStoreFiles += store.getStorefilesCount();
362           tempMemstoreSize += store.getMemStoreSize();
363           tempStoreFileSize += store.getStorefilesSize();
364           tempStorefileIndexSize += store.getStorefilesIndexSize();
365           tempTotalStaticBloomSize += store.getTotalStaticBloomSize();
366           tempTotalStaticIndexSize += store.getTotalStaticIndexSize();
367         }
368 
369         hdfsBlocksDistribution.add(r.getHDFSBlocksDistribution());
370       }
371 
372       float localityIndex = hdfsBlocksDistribution.getBlockLocalityIndex(
373           regionServer.getServerName().getHostname());
374       tempPercentFileLocal = (int) (localityIndex * 100);
375 
376 
377       //Compute the number of requests per second
378       long currentTime = EnvironmentEdgeManager.currentTimeMillis();
379 
380       // assume that it took PERIOD seconds to start the executor.
381       // this is a guess but it's a pretty good one.
382       if (lastRan == 0) {
383         lastRan = currentTime - (PERIOD*1000);
384       }
385 
386 
387       //If we've time traveled keep the last requests per second.
388       if ((currentTime - lastRan) > 10) {
389         long currentRequestCount = getTotalRequestCount();
390         requestsPerSecond = (currentRequestCount - lastRequestCount) / ((currentTime - lastRan) / 1000.0);
391         lastRequestCount = currentRequestCount;
392       }
393       lastRan = currentTime;
394 
395       //Copy over computed values so that no thread sees half computed values.
396       numStores = tempNumStores;
397       numStoreFiles = tempNumStoreFiles;
398       memstoreSize = tempMemstoreSize;
399       storeFileSize = tempStoreFileSize;
400       readRequestsCount = tempReadRequestsCount;
401       writeRequestsCount = tempWriteRequestsCount;
402       checkAndMutateChecksFailed = tempCheckAndMutateChecksFailed;
403       checkAndMutateChecksPassed = tempCheckAndMutateChecksPassed;
404       storefileIndexSize = tempStorefileIndexSize;
405       totalStaticIndexSize = tempTotalStaticIndexSize;
406       totalStaticBloomSize = tempTotalStaticBloomSize;
407       numMutationsWithoutWAL = tempNumMutationsWithoutWAL;
408       dataInMemoryWithoutWAL = tempDataInMemoryWithoutWAL;
409       percentFileLocal = tempPercentFileLocal;
410     }
411   }
412 
413 }