View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional information regarding
4    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
8    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
9    * for the specific language governing permissions and limitations under the License.
10   */
11  
12  package org.apache.hadoop.hbase.coprocessor;
13  
14  import static org.junit.Assert.assertEquals;
15  import static org.junit.Assert.assertNotNull;
16  
17  import java.io.IOException;
18  import java.util.ArrayList;
19  import java.util.HashSet;
20  import java.util.Hashtable;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Random;
24  import java.util.Set;
25  
26  import javax.management.MBeanAttributeInfo;
27  import javax.management.MBeanInfo;
28  import javax.management.MBeanServerConnection;
29  import javax.management.ObjectInstance;
30  import javax.management.ObjectName;
31  import javax.management.remote.JMXConnector;
32  import javax.management.remote.JMXConnectorFactory;
33  
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.hbase.HBaseTestingUtility;
36  import org.apache.hadoop.hbase.JMXListener;
37  import org.apache.hadoop.hbase.TableName;
38  import org.apache.hadoop.hbase.client.Put;
39  import org.apache.hadoop.hbase.client.Table;
40  import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
41  import org.apache.hadoop.hbase.testclassification.MediumTests;
42  import org.apache.hadoop.hbase.util.Bytes;
43  import org.apache.hadoop.hbase.util.Threads;
44  import org.junit.AfterClass;
45  import org.junit.BeforeClass;
46  import org.junit.Test;
47  import org.junit.experimental.categories.Category;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  
52  @Category({ CoprocessorTests.class, MediumTests.class })
53  public class TestMetaTableMetrics {
54  
55    private static final Logger LOG = LoggerFactory.getLogger(TestMetaTableMetrics.class);
56  
57    private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
58    private static final TableName NAME1 = TableName.valueOf("TestExampleMetaTableMetricsOne");
59    private static final byte[] FAMILY = Bytes.toBytes("f");
60    private static final byte[] QUALIFIER = Bytes.toBytes("q");
61    private static final int NUM_ROWS = 5;
62    private static final String value = "foo";
63    private static Configuration conf = null;
64    private static int connectorPort = 61120;
65  
66    @BeforeClass
67    public static void setupBeforeClass() throws Exception {
68  
69      conf = UTIL.getConfiguration();
70      // Set system coprocessor so it can be applied to meta regions
71      UTIL.getConfiguration().set("hbase.coprocessor.region.classes",
72        MetaTableMetrics.class.getName());
73      conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, JMXListener.class.getName());
74      Random rand = new Random();
75      for (int i = 0; i < 10; i++) {
76        do {
77          int sign = i % 2 == 0 ? 1 : -1;
78          connectorPort += sign * rand.nextInt(100);
79        } while (!HBaseTestingUtility.available(connectorPort));
80        try {
81          conf.setInt("regionserver.rmi.registry.port", connectorPort);
82          UTIL.startMiniCluster(1);
83          UTIL.createTable(NAME1, new byte[][]{FAMILY});
84          LOG.error("util to string" + UTIL.toString());
85          break;
86        } catch (Exception e) {
87          LOG.debug("Encountered exception when starting cluster. Trying port " + connectorPort, e);
88          try {
89            // this is to avoid "IllegalStateException: A mini-cluster is already running"
90            UTIL.shutdownMiniCluster();
91          } catch (Exception ex) {
92            LOG.debug("Encountered exception shutting down cluster", ex);
93          }
94        }
95      }
96    }
97  
98    @AfterClass
99    public static void tearDown() throws Exception {
100     UTIL.shutdownMiniCluster();
101   }
102 
103   private void writeData(Table t) throws IOException {
104     List<Put> puts = new ArrayList<>(NUM_ROWS);
105     for (int i = 0; i < NUM_ROWS; i++) {
106       Put p = new Put(Bytes.toBytes(i + 1));
107       p.addColumn(FAMILY, QUALIFIER, Bytes.toBytes(value));
108       puts.add(p);
109     }
110     t.put(puts);
111   }
112 
113   private Set<String> readJmxMetricsWithRetry() throws IOException {
114     final int count = 0;
115     for (int i = 0; i < 10; i++) {
116       Set<String> metrics = readJmxMetrics();
117       if (metrics != null) {
118         return metrics;
119       }
120       LOG.warn("Failed to get jmxmetrics... sleeping, retrying; " + i + " of " + count + " times");
121       Threads.sleep(1000);
122     }
123     return null;
124   }
125 
126   /**
127    * Read the attributes from Hadoop->HBase->RegionServer->MetaTableMetrics in JMX
128    * @throws IOException when fails to retrieve jmx metrics.
129    */
130   // this method comes from this class: TestStochasticBalancerJmxMetrics with minor modifications.
131   private Set<String> readJmxMetrics() throws IOException {
132     JMXConnector connector = null;
133     ObjectName target = null;
134     MBeanServerConnection mb = null;
135     try {
136       connector =
137           JMXConnectorFactory.connect(JMXListener.buildJMXServiceURL(connectorPort, connectorPort));
138       mb = connector.getMBeanServerConnection();
139 
140       @SuppressWarnings("JdkObsolete")
141       Hashtable<String, String> pairs = new Hashtable<>();
142       pairs.put("service", "HBase");
143       pairs.put("name", "RegionServer");
144       pairs.put("sub",
145         "Coprocessor.Region.CP_org.apache.hadoop.hbase.coprocessor"
146             + ".MetaTableMetrics");
147       target = new ObjectName("Hadoop", pairs);
148       MBeanInfo beanInfo = mb.getMBeanInfo(target);
149 
150       Set<String> existingAttrs = new HashSet<>();
151       for (MBeanAttributeInfo attrInfo : beanInfo.getAttributes()) {
152         existingAttrs.add(attrInfo.getName());
153       }
154       return existingAttrs;
155     } catch (Exception e) {
156       LOG.warn("Failed to get bean." + target, e);
157       if (mb != null) {
158         Set<ObjectInstance> instances = mb.queryMBeans(null, null);
159         Iterator<ObjectInstance> iterator = instances.iterator();
160         LOG.warn("MBean Found:");
161         while (iterator.hasNext()) {
162           ObjectInstance instance = iterator.next();
163           LOG.warn("Class Name: " + instance.getClassName());
164           LOG.warn("Object Name: " + instance.getObjectName());
165         }
166       }
167     } finally {
168       if (connector != null) {
169         try {
170           connector.close();
171         } catch (Exception e) {
172           e.printStackTrace();
173         }
174       }
175     }
176     return null;
177   }
178 
179   // verifies meta table metrics exist from jmx
180   // for one table, there should be 5 MetaTable_table_<TableName> metrics.
181   // such as:
182   // [Time-limited test] example.TestMetaTableMetrics(204): ==
183   //    MetaTable_table_TestExampleMetaTableMetricsOne_request_count
184   // [Time-limited test] example.TestMetaTableMetrics(204): ==
185   //    MetaTable_table_TestExampleMetaTableMetricsOne_request_mean_rate
186   // [Time-limited test] example.TestMetaTableMetrics(204): ==
187   //    MetaTable_table_TestExampleMetaTableMetricsOne_request_1min_rate
188   // [Time-limited test] example.TestMetaTableMetrics(204): ==
189   //    MetaTable_table_TestExampleMetaTableMetricsOne_request_5min_rate
190   // [Time-limited test] example.TestMetaTableMetrics(204): ==
191   // MetaTable_table_TestExampleMetaTableMetricsOne_request_15min_rate
192   @Test
193   public void test() throws IOException, InterruptedException {
194     try (Table t = UTIL.getConnection().getTable(NAME1)) {
195       writeData(t);
196       // Flush the data
197       UTIL.flush(NAME1);
198       // Issue a compaction
199       UTIL.compact(NAME1, true);
200       Thread.sleep(2000);
201     }
202     Set<String> jmxMetrics = readJmxMetricsWithRetry();
203     assertNotNull(jmxMetrics);
204 
205     long name1TableMetricsCount = 0;
206     for(String metric : jmxMetrics) {
207       if (metric.contains("MetaTable_table_" + NAME1)){
208         name1TableMetricsCount++;
209       }
210     }
211     assertEquals(5L, name1TableMetricsCount);
212 
213     String putWithClientMetricNameRegex = "MetaTable_client_.+_put_request.*";
214     long putWithClientMetricsCount = 0;
215     for(String metric : jmxMetrics) {
216       if(metric.matches(putWithClientMetricNameRegex)) {
217         putWithClientMetricsCount++;
218       }
219     }
220     assertEquals(5L, putWithClientMetricsCount);
221   }
222 
223 }