View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  
21  package org.apache.hadoop.hbase.coprocessor.example;
22  
23  import java.io.IOException;
24  import java.util.List;
25  import java.util.concurrent.ThreadLocalRandom;
26  
27  import org.apache.hadoop.hbase.Cell;
28  import org.apache.hadoop.hbase.CoprocessorEnvironment;
29  import org.apache.hadoop.hbase.client.Get;
30  import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
31  import org.apache.hadoop.hbase.coprocessor.ObserverContext;
32  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
33  import org.apache.hadoop.hbase.metrics.Counter;
34  import org.apache.hadoop.hbase.metrics.MetricRegistry;
35  import org.apache.hadoop.hbase.metrics.Timer;
36  
37  /**
38   * An example coprocessor that collects some metrics to demonstrate the usage of exporting custom
39   * metrics from the coprocessor.
40   * <p>
41   * These metrics will be available through the regular Hadoop metrics2 sinks (ganglia, opentsdb,
42   * etc) as well as JMX output. You can view a snapshot of the metrics by going to the http web UI
43   * of the regionserver page, something like http://myregionserverhost:16030/jmx
44   * </p>
45   *
46   * @see ExampleMasterObserverWithMetrics
47   */
48  public class ExampleRegionObserverWithMetrics extends BaseRegionObserver {
49  
50    private Counter preGetCounter;
51    private Timer costlyOperationTimer;
52  
53    @Override
54    public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results)
55        throws IOException {
56      super.preGetOp(e, get, results);
57  
58      // Increment the Counter whenever the coprocessor is called
59      preGetCounter.increment();
60    }
61  
62    @Override
63    public void postGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get,
64                          List<Cell> results) throws IOException {
65      super.postGetOp(e, get, results);
66  
67      // do a costly (high latency) operation which we want to measure how long it takes by
68      // using a Timer (which is a Meter and a Histogram).
69      long start = System.nanoTime();
70      try {
71        performCostlyOperation();
72      } finally {
73        costlyOperationTimer.updateNanos(System.nanoTime() - start);
74      }
75    }
76  
77    private void performCostlyOperation() {
78      try {
79        // simulate the operation by sleeping.
80        Thread.sleep(ThreadLocalRandom.current().nextLong(100));
81      } catch (InterruptedException ignore) {}
82    }
83  
84    @Override
85    public void start(CoprocessorEnvironment env) throws IOException {
86      super.start(env);
87  
88      // start for the RegionServerObserver will be called only once in the lifetime of the
89      // server. We will construct and register all metrics that we will track across method
90      // invocations.
91  
92      if (env instanceof RegionCoprocessorEnvironment) {
93        // Obtain the MetricRegistry for the RegionServer. Metrics from this registry will be reported
94        // at the region server level per-regionserver.
95        MetricRegistry registry =
96            ((RegionCoprocessorEnvironment) env).getMetricRegistryForRegionServer();
97  
98        if (preGetCounter == null) {
99          // Create a new Counter, or get the already registered counter.
100         // It is much better to only call this once and save the Counter as a class field instead
101         // of creating the counter every time a coprocessor method is invoked. This will negate
102         // any performance bottleneck coming from map lookups tracking metrics in the registry.
103         // Returned counter instance is shared by all coprocessors of the same class in the same
104         // region server.
105         preGetCounter = registry.counter("preGetRequests");
106       }
107 
108       if (costlyOperationTimer == null) {
109         // Create a Timer to track execution times for the costly operation.
110         costlyOperationTimer = registry.timer("costlyOperation");
111       }
112     }
113   }
114 
115   @Override
116   public void stop(CoprocessorEnvironment e) throws IOException {
117     // we should NOT remove / deregister the metrics in stop(). The whole registry will be
118     // removed when the last region of the table is closed.
119     super.stop(e);
120   }
121 }