View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.ipc;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.hbase.ipc.VersionedProtocol;
26  import org.apache.hadoop.metrics.MetricsContext;
27  import org.apache.hadoop.metrics.MetricsRecord;
28  import org.apache.hadoop.metrics.MetricsUtil;
29  import org.apache.hadoop.metrics.Updater;
30  import org.apache.hadoop.metrics.util.*;
31  
32  import java.lang.reflect.Method;
33  
34  /**
35   *
36   * This class is for maintaining  the various RPC statistics
37   * and publishing them through the metrics interfaces.
38   * This also registers the JMX MBean for RPC.
39   * <p>
40   * This class has a number of metrics variables that are publicly accessible;
41   * these variables (objects) have methods to update their values;
42   * for example:
43   *  <p> {@link #rpcQueueTime}.inc(time)
44   *
45   */
46  public class HBaseRpcMetrics implements Updater {
47    public static final String NAME_DELIM = "$";
48    private final MetricsRegistry registry = new MetricsRegistry();
49    private final MetricsRecord metricsRecord;
50    private static Log LOG = LogFactory.getLog(HBaseRpcMetrics.class);
51    private final HBaseRPCStatistics rpcStatistics;
52  
53    public HBaseRpcMetrics(String hostName, String port) {
54      MetricsContext context = MetricsUtil.getContext("rpc");
55      metricsRecord = MetricsUtil.createRecord(context, "metrics");
56  
57      metricsRecord.setTag("port", port);
58  
59      LOG.info("Initializing RPC Metrics with hostName="
60          + hostName + ", port=" + port);
61  
62      context.registerUpdater(this);
63  
64      initMethods(HMasterInterface.class);
65      initMethods(HMasterRegionInterface.class);
66      initMethods(HRegionInterface.class);
67      rpcStatistics = new HBaseRPCStatistics(this.registry, hostName, port);
68    }
69  
70  
71    /**
72     * The metrics variables are public:
73     *  - they can be set directly by calling their set/inc methods
74     *  -they can also be read directly - e.g. JMX does this.
75     */
76  
77    public final MetricsTimeVaryingLong receivedBytes =
78           new MetricsTimeVaryingLong("ReceivedBytes", registry);
79    public final MetricsTimeVaryingLong sentBytes =
80           new MetricsTimeVaryingLong("SentBytes", registry);
81    public final MetricsTimeVaryingRate rpcQueueTime =
82            new MetricsTimeVaryingRate("RpcQueueTime", registry);
83    public MetricsTimeVaryingRate rpcProcessingTime =
84            new MetricsTimeVaryingRate("RpcProcessingTime", registry);
85    public final MetricsIntValue numOpenConnections =
86            new MetricsIntValue("NumOpenConnections", registry);
87    public final MetricsIntValue callQueueLen =
88            new MetricsIntValue("callQueueLen", registry);
89    public final MetricsIntValue priorityCallQueueLen =
90            new MetricsIntValue("priorityCallQueueLen", registry);
91    public final MetricsTimeVaryingInt authenticationFailures = 
92            new MetricsTimeVaryingInt("rpcAuthenticationFailures", registry);
93    public final MetricsTimeVaryingInt authenticationSuccesses =
94            new MetricsTimeVaryingInt("rpcAuthenticationSuccesses", registry);
95    public final MetricsTimeVaryingInt authorizationFailures =
96            new MetricsTimeVaryingInt("rpcAuthorizationFailures", registry);
97    public final MetricsTimeVaryingInt authorizationSuccesses =
98           new MetricsTimeVaryingInt("rpcAuthorizationSuccesses", registry);
99    public MetricsTimeVaryingRate rpcSlowResponseTime =
100       new MetricsTimeVaryingRate("RpcSlowResponse", registry);
101   public final MetricsIntValue replicationCallQueueLen =
102     new MetricsIntValue("replicationCallQueueLen", registry);
103 
104   private void initMethods(Class<? extends VersionedProtocol> protocol) {
105     for (Method m : protocol.getDeclaredMethods()) {
106       if (get(m.getName()) == null)
107         create(m.getName());
108     }
109   }
110 
111   private MetricsTimeVaryingRate get(String key) {
112     return (MetricsTimeVaryingRate) registry.get(key);
113   }
114   private MetricsTimeVaryingRate create(String key) {
115     return new MetricsTimeVaryingRate(key, this.registry);
116   }
117 
118   public void inc(String name, int amt) {
119     MetricsTimeVaryingRate m = get(name);
120     if (m == null) {
121       LOG.warn("Got inc() request for method that doesnt exist: " +
122       name);
123       return; // ignore methods that dont exist.
124     }
125     m.inc(amt);
126   }
127 
128   /**
129    * Generate metrics entries for all the methods defined in the list of
130    * interfaces.  A {@link MetricsTimeVaryingRate} counter will be created for
131    * each {@code Class.getMethods().getName()} entry.
132    * @param ifaces Define metrics for all methods in the given classes
133    */
134   public void createMetrics(Class<?>[] ifaces) {
135     createMetrics(ifaces, false);
136   }
137 
138   /**
139    * Generate metrics entries for all the methods defined in the list of
140    * interfaces.  A {@link MetricsTimeVaryingRate} counter will be created for
141    * each {@code Class.getMethods().getName()} entry.
142    *
143    * <p>
144    * If {@code prefixWithClass} is {@code true}, each metric will be named as
145    * {@code [Class.getSimpleName()].[Method.getName()]}.  Otherwise each metric
146    * will just be named according to the method -- {@code Method.getName()}.
147    * </p>
148    * @param ifaces Define metrics for all methods in the given classes
149    * @param prefixWithClass If {@code true}, each metric will be named as
150    *     "classname.method"
151    */
152   public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass) {
153     createMetrics(ifaces, prefixWithClass, null);
154   }
155 
156   /**
157   * Generate metrics entries for all the methods defined in the list of
158   * interfaces. A {@link MetricsTimeVaryingRate} counter will be created for
159   * each {@code Class.getMethods().getName()} entry.
160   *
161   * <p>
162   * If {@code prefixWithClass} is {@code true}, each metric will be named as
163   * {@code [Class.getSimpleName()].[Method.getName()]}. Otherwise each metric
164   * will just be named according to the method -- {@code Method.getName()}.
165   * </p>
166   *
167   * <p>
168   * Additionally, if {@code suffixes} is defined, additional metrics will be
169   * created for each method named as the original metric concatenated with
170   * the suffix.
171   * </p>
172   * @param ifaces Define metrics for all methods in the given classes
173   * @param prefixWithClass If {@code true}, each metric will be named as
174   * "classname.method"
175   * @param suffixes If not null, each method will get additional metrics ending
176   * in each of the suffixes.
177   */
178   public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass,
179       String [] suffixes) {
180     for (Class<?> iface : ifaces) {
181       Method[] methods = iface.getMethods();
182       for (Method method : methods) {
183         String attrName = prefixWithClass ?
184         getMetricName(iface, method.getName()) : method.getName();
185         if (get(attrName) == null)
186           create(attrName);
187         if (suffixes != null) {
188           // create metrics for each requested suffix
189           for (String s : suffixes) {
190             String metricName = attrName + s;
191             if (get(metricName) == null)
192               create(metricName);
193           }
194         }
195       }
196     }
197   }
198 
199   public static String getMetricName(Class<?> c, String method) {
200     return c.getSimpleName() + NAME_DELIM + method;
201   }
202 
203   /**
204    * Push the metrics to the monitoring subsystem on doUpdate() call.
205    */
206   public void doUpdates(final MetricsContext context) {
207     // Both getMetricsList() and pushMetric() are thread-safe
208     for (MetricsBase m : registry.getMetricsList()) {
209       m.pushMetric(metricsRecord);
210     }
211     metricsRecord.update();
212   }
213 
214   public void shutdown() {
215     if (rpcStatistics != null)
216       rpcStatistics.shutdown();
217   }
218 }