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 final RpcServer myServer;
51    private static Log LOG = LogFactory.getLog(HBaseRpcMetrics.class);
52    private final HBaseRPCStatistics rpcStatistics;
53  
54    public HBaseRpcMetrics(String hostName, String port,
55        final RpcServer server) {
56      myServer = server;
57      MetricsContext context = MetricsUtil.getContext("rpc");
58      metricsRecord = MetricsUtil.createRecord(context, "metrics");
59  
60      metricsRecord.setTag("port", port);
61  
62      LOG.info("Initializing RPC Metrics with hostName="
63          + hostName + ", port=" + port);
64  
65      context.registerUpdater(this);
66  
67      initMethods(HMasterInterface.class);
68      initMethods(HMasterRegionInterface.class);
69      initMethods(HRegionInterface.class);
70      rpcStatistics = new HBaseRPCStatistics(this.registry, hostName, port);
71    }
72  
73  
74    /**
75     * The metrics variables are public:
76     *  - they can be set directly by calling their set/inc methods
77     *  -they can also be read directly - e.g. JMX does this.
78     */
79  
80    public final MetricsTimeVaryingLong receivedBytes =
81           new MetricsTimeVaryingLong("ReceivedBytes", registry);
82    public final MetricsTimeVaryingLong sentBytes =
83           new MetricsTimeVaryingLong("SentBytes", registry);
84    public final MetricsTimeVaryingRate rpcQueueTime =
85            new MetricsTimeVaryingRate("RpcQueueTime", registry);
86    public MetricsTimeVaryingRate rpcProcessingTime =
87            new MetricsTimeVaryingRate("RpcProcessingTime", registry);
88    public final MetricsIntValue numOpenConnections =
89            new MetricsIntValue("NumOpenConnections", registry);
90    public final MetricsIntValue callQueueLen =
91            new MetricsIntValue("callQueueLen", registry);
92    public final MetricsTimeVaryingInt authenticationFailures = 
93            new MetricsTimeVaryingInt("rpcAuthenticationFailures", registry);
94    public final MetricsTimeVaryingInt authenticationSuccesses =
95            new MetricsTimeVaryingInt("rpcAuthenticationSuccesses", registry);
96    public final MetricsTimeVaryingInt authorizationFailures =
97            new MetricsTimeVaryingInt("rpcAuthorizationFailures", registry);
98    public final MetricsTimeVaryingInt authorizationSuccesses =
99           new MetricsTimeVaryingInt("rpcAuthorizationSuccesses", registry);
100   public MetricsTimeVaryingRate rpcSlowResponseTime =
101       new MetricsTimeVaryingRate("RpcSlowResponse", registry);
102 
103   private void initMethods(Class<? extends VersionedProtocol> protocol) {
104     for (Method m : protocol.getDeclaredMethods()) {
105       if (get(m.getName()) == null)
106         create(m.getName());
107     }
108   }
109 
110   private MetricsTimeVaryingRate get(String key) {
111     return (MetricsTimeVaryingRate) registry.get(key);
112   }
113   private MetricsTimeVaryingRate create(String key) {
114     return new MetricsTimeVaryingRate(key, this.registry);
115   }
116 
117   public void inc(String name, int amt) {
118     MetricsTimeVaryingRate m = get(name);
119     if (m == null) {
120       LOG.warn("Got inc() request for method that doesnt exist: " +
121       name);
122       return; // ignore methods that dont exist.
123     }
124     m.inc(amt);
125   }
126 
127   /**
128    * Generate metrics entries for all the methods defined in the list of
129    * interfaces.  A {@link MetricsTimeVaryingRate} counter will be created for
130    * each {@code Class.getMethods().getName()} entry.
131    * @param ifaces Define metrics for all methods in the given classes
132    */
133   public void createMetrics(Class<?>[] ifaces) {
134     createMetrics(ifaces, false);
135   }
136 
137   /**
138    * Generate metrics entries for all the methods defined in the list of
139    * interfaces.  A {@link MetricsTimeVaryingRate} counter will be created for
140    * each {@code Class.getMethods().getName()} entry.
141    *
142    * <p>
143    * If {@code prefixWithClass} is {@code true}, each metric will be named as
144    * {@code [Class.getSimpleName()].[Method.getName()]}.  Otherwise each metric
145    * will just be named according to the method -- {@code Method.getName()}.
146    * </p>
147    * @param ifaces Define metrics for all methods in the given classes
148    * @param prefixWithClass If {@code true}, each metric will be named as
149    *     "classname.method"
150    */
151   public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass) {
152     createMetrics(ifaces, prefixWithClass, null);
153   }
154 
155   /**
156   * Generate metrics entries for all the methods defined in the list of
157   * interfaces. A {@link MetricsTimeVaryingRate} counter will be created for
158   * each {@code Class.getMethods().getName()} entry.
159   *
160   * <p>
161   * If {@code prefixWithClass} is {@code true}, each metric will be named as
162   * {@code [Class.getSimpleName()].[Method.getName()]}. Otherwise each metric
163   * will just be named according to the method -- {@code Method.getName()}.
164   * </p>
165   *
166   * <p>
167   * Additionally, if {@code suffixes} is defined, additional metrics will be
168   * created for each method named as the original metric concatenated with
169   * the suffix.
170   * </p>
171   * @param ifaces Define metrics for all methods in the given classes
172   * @param prefixWithClass If {@code true}, each metric will be named as
173   * "classname.method"
174   * @param suffixes If not null, each method will get additional metrics ending
175   * in each of the suffixes.
176   */
177   public void createMetrics(Class<?>[] ifaces, boolean prefixWithClass,
178       String [] suffixes) {
179     for (Class<?> iface : ifaces) {
180       Method[] methods = iface.getMethods();
181       for (Method method : methods) {
182         String attrName = prefixWithClass ?
183         getMetricName(iface, method.getName()) : method.getName();
184         if (get(attrName) == null)
185           create(attrName);
186         if (suffixes != null) {
187           // create metrics for each requested suffix
188           for (String s : suffixes) {
189             String metricName = attrName + s;
190             if (get(metricName) == null)
191               create(metricName);
192           }
193         }
194       }
195     }
196   }
197 
198   public static String getMetricName(Class<?> c, String method) {
199     return c.getSimpleName() + NAME_DELIM + method;
200   }
201 
202   /**
203    * Push the metrics to the monitoring subsystem on doUpdate() call.
204    */
205   public void doUpdates(final MetricsContext context) {
206     synchronized (this) {
207       // ToFix - fix server to use the following two metrics directly so
208       // the metrics do not have be copied here.
209       numOpenConnections.set(myServer.getNumOpenConnections());
210       callQueueLen.set(myServer.getCallQueueLen());
211       for (MetricsBase m : registry.getMetricsList()) {
212         m.pushMetric(metricsRecord);
213       }
214     }
215     metricsRecord.update();
216   }
217 
218   public void shutdown() {
219     if (rpcStatistics != null)
220       rpcStatistics.shutdown();
221   }
222 }