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   public final MetricsIntValue activeRpcCount =
104       new MetricsIntValue("activeRpcCount", registry);
105 
106   private void initMethods(Class<? extends VersionedProtocol> protocol) {
107     for (Method m : protocol.getDeclaredMethods()) {
108       if (get(m.getName()) == null)
109         create(m.getName());
110     }
111   }
112 
113   private MetricsTimeVaryingRate get(String key) {
114     return (MetricsTimeVaryingRate) registry.get(key);
115   }
116   private MetricsTimeVaryingRate create(String key) {
117     return new MetricsTimeVaryingRate(key, this.registry);
118   }
119 
120   public void inc(String name, int amt) {
121     MetricsTimeVaryingRate m = get(name);
122     if (m == null) {
123       LOG.warn("Got inc() request for method that doesnt exist: " +
124       name);
125       return; // ignore methods that dont exist.
126     }
127     m.inc(amt);
128   }
129 
130   /**
131    * Generate metrics entries for all the methods defined in the list of
132    * interfaces.  A {@link MetricsTimeVaryingRate} counter will be created for
133    * each {@code Class.getMethods().getName()} entry.
134    * @param ifaces Define metrics for all methods in the given classes
135    */
136   public void createMetrics(Class<?>[] ifaces) {
137     createMetrics(ifaces, false);
138   }
139 
140   /**
141    * Generate metrics entries for all the methods defined in the list of
142    * interfaces.  A {@link MetricsTimeVaryingRate} counter will be created for
143    * each {@code Class.getMethods().getName()} entry.
144    *
145    * <p>
146    * If {@code prefixWithClass} is {@code true}, each metric will be named as
147    * {@code [Class.getSimpleName()].[Method.getName()]}.  Otherwise each metric
148    * will just be named according to the method -- {@code Method.getName()}.
149    * </p>
150    * @param ifaces Define metrics for all methods in the given classes
151    * @param prefixWithClass If {@code true}, each metric will be named as
152    *     "classname.method"
153    */
154   public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass) {
155     createMetrics(ifaces, prefixWithClass, null);
156   }
157 
158   /**
159   * Generate metrics entries for all the methods defined in the list of
160   * interfaces. A {@link MetricsTimeVaryingRate} counter will be created for
161   * each {@code Class.getMethods().getName()} entry.
162   *
163   * <p>
164   * If {@code prefixWithClass} is {@code true}, each metric will be named as
165   * {@code [Class.getSimpleName()].[Method.getName()]}. Otherwise each metric
166   * will just be named according to the method -- {@code Method.getName()}.
167   * </p>
168   *
169   * <p>
170   * Additionally, if {@code suffixes} is defined, additional metrics will be
171   * created for each method named as the original metric concatenated with
172   * the suffix.
173   * </p>
174   * @param ifaces Define metrics for all methods in the given classes
175   * @param prefixWithClass If {@code true}, each metric will be named as
176   * "classname.method"
177   * @param suffixes If not null, each method will get additional metrics ending
178   * in each of the suffixes.
179   */
180   public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass,
181       String [] suffixes) {
182     for (Class<?> iface : ifaces) {
183       Method[] methods = iface.getMethods();
184       for (Method method : methods) {
185         String attrName = prefixWithClass ?
186         getMetricName(iface, method.getName()) : method.getName();
187         if (get(attrName) == null)
188           create(attrName);
189         if (suffixes != null) {
190           // create metrics for each requested suffix
191           for (String s : suffixes) {
192             String metricName = attrName + s;
193             if (get(metricName) == null)
194               create(metricName);
195           }
196         }
197       }
198     }
199   }
200 
201   public static String getMetricName(Class<?> c, String method) {
202     return c.getSimpleName() + NAME_DELIM + method;
203   }
204 
205   /**
206    * Push the metrics to the monitoring subsystem on doUpdate() call.
207    */
208   public void doUpdates(final MetricsContext context) {
209     // Both getMetricsList() and pushMetric() are thread-safe
210     for (MetricsBase m : registry.getMetricsList()) {
211       m.pushMetric(metricsRecord);
212     }
213     metricsRecord.update();
214   }
215 
216   public void shutdown() {
217     if (rpcStatistics != null)
218       rpcStatistics.shutdown();
219   }
220 }