Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/HRegionServerMetrics.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/HRegionServerMetrics.java (revision ) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/metrics/HRegionServerMetrics.java (revision ) @@ -0,0 +1,84 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.regionserver.metrics; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.metrics2.MetricsBuilder; +import org.apache.hadoop.metrics2.MetricsSource; +import org.apache.hadoop.metrics2.MetricsSystem; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.hadoop.metrics2.lib.MetricMutableGaugeInt; +import org.apache.hadoop.metrics2.lib.MetricsRegistry; +import org.apache.hadoop.metrics2.source.JvmMetricsSource; + +/** + * + * This class is for maintaining the various HRegionServer statistics + * and publishing them through the metrics interfaces. + * This also registers the JMX MBean for RPC. + *

+ * This class has a number of metrics variables that are publicly accessible; + * these variables (objects) have methods to update their values; + * for example: + *

{@link #regions#incr()} + * + */ +public class HRegionServerMetrics implements MetricsSource { + final String name; + final MetricsRegistry registry = new MetricsRegistry("hregionserver"); + + final MetricMutableGaugeInt regions = + registry.newGauge("regions", "", 0); + + public HRegionServerMetrics(final String name, final String sessionId) { + this.name = name; + JvmMetricsSource.create("HRegionServer", sessionId); + registry.setContext(name).tag("sessionId", "", sessionId); + } + + @Override + public void getMetrics(MetricsBuilder builder, boolean all) { + registry.snapshot(builder.addRecord(registry.name()), all); + } + + public static HRegionServerMetrics create(Configuration conf, + String rsName) { + return create(conf, rsName, DefaultMetricsSystem.INSTANCE); + } + + public static HRegionServerMetrics create(Configuration conf, + String rsName, + MetricsSystem ms) { + String name = "hregionserver-" + rsName; + String sessionId = conf.get("session.id"); + return ms.register("HRegionSever", "HRegionServer metrics", + new HRegionServerMetrics(name, sessionId)); + } + + public String getName() { + return name; + } + + public void setRegions(int val) { + regions.set(val); + } + + public MetricMutableGaugeInt getRegions() { + return regions; + } +} Index: hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionServerMetrics.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionServerMetrics.java (revision ) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegionServerMetrics.java (revision ) @@ -0,0 +1,107 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.regionserver; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.MediumTests; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Threads; +import org.apache.hadoop.metrics2.MetricsRecordBuilder; +import org.apache.hadoop.metrics2.lib.MetricMutableGaugeInt; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import static org.apache.hadoop.test.MetricsAsserts.assertGauge; + +@Category(MediumTests.class) +public class TestHRegionServerMetrics { + private static final Log LOG = LogFactory.getLog(TestHRegionServerMetrics.class); + + static { + Logger.getLogger("org.apache.hadoop.hbase").setLevel(Level.DEBUG); + } + + private MiniHBaseCluster cluster; + private HRegionServer rs; + private Configuration conf; + private HBaseTestingUtility TEST_UTIL; + + private void startCluster() throws Exception{ + LOG.info("Starting cluster"); + conf = HBaseConfiguration.create(); + conf.getLong("hbase.splitlog.max.resubmit", 0); + // Make the failure test faster + conf.setInt("zookeeper.recovery.retry", 0); + conf.setInt(HConstants.REGIONSERVER_INFO_PORT, -1); + conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, (float) 100.0); // no load balancing + conf.setBoolean(HConstants.DISTRIBUTED_LOG_SPLITTING_KEY, true); + TEST_UTIL = new HBaseTestingUtility(conf); + TEST_UTIL.startMiniCluster(1, 1); + cluster = TEST_UTIL.getHBaseCluster(); + LOG.info("Waiting for active/ready master"); + cluster.waitForActiveAndReadyMaster(); + + while (cluster.getLiveRegionServerThreads().size() < 1) { + Threads.sleep(1); + } + + rs = cluster.getRegionServer(0); + } + + @After + public void after() throws Exception { + if (TEST_UTIL != null) { + TEST_UTIL.shutdownMiniCluster(); + } + } + + @Test(timeout=300000) + public void testClusterRequests() throws Exception { + startCluster(); + + int regions = getValue(rs.getHRegionServerMetrics().getRegions()); + TEST_UTIL.createTable(Bytes.toBytes("table"), Bytes.toBytes("cf")); + assertGauge("regions", regions + 1, rs.getHRegionServerMetrics()); + } + + private int getValue(MetricMutableGaugeInt metric) { + final int[] value = new int[1]; + MetricsRecordBuilder mrb = Mockito.mock(MetricsRecordBuilder.class, new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + value[0] = (Integer) args[2]; // args are: name, description, value + return invocation.getMock(); + } + }); + metric.snapshot(mrb); + return value[0]; + } +} Index: conf/hadoop-metrics2.properties =================================================================== --- conf/hadoop-metrics2.properties (revision ) +++ conf/hadoop-metrics2.properties (revision ) @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# syntax: [prefix].[source|sink].[instance].[options] +# See javadoc of package-info.java for org.apache.hadoop.metrics2 for details + +# Example sink configuration: +# *.sink.file.class=org.apache.hadoop.metrics2.sink.FileSink +# default sampling period +# *.period=10 Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/HMasterMetrics.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/HMasterMetrics.java (revision ) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/metrics/HMasterMetrics.java (revision ) @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.master.metrics; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.metrics2.MetricsBuilder; +import org.apache.hadoop.metrics2.MetricsSource; +import org.apache.hadoop.metrics2.MetricsSystem; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.hadoop.metrics2.lib.MetricMutableCounterInt; +import org.apache.hadoop.metrics2.lib.MetricsRegistry; +import org.apache.hadoop.metrics2.source.JvmMetricsSource; + +/** + * + * This class is for maintaining the various HMaster statistics + * and publishing them through the metrics interfaces. + * This also registers the JMX MBean for RPC. + *

+ * This class has a number of metrics variables that are publicly accessible; + * these variables (objects) have methods to update their values; + * for example: + *

{@link #clusterRequests#incr()} + * + */ +public class HMasterMetrics implements MetricsSource { + final String name; + final MetricsRegistry registry = new MetricsRegistry("hmaster"); + + final MetricMutableCounterInt clusterRequests = + registry.newCounter("cluster_requests", "", 0); + + public HMasterMetrics(final String name, final String sessionId) { + this.name = name; + JvmMetricsSource.create("HMaster", sessionId); + registry.setContext(name).tag("sessionId", "", sessionId); + } + + @Override + public void getMetrics(MetricsBuilder builder, boolean all) { + registry.snapshot(builder.addRecord(registry.name()), all); + } + + public static HMasterMetrics create(Configuration conf, + String masterName) { + return create(conf, masterName, DefaultMetricsSystem.INSTANCE); + } + + public static HMasterMetrics create(Configuration conf, + String masterName, + MetricsSystem ms) { + String name = "hmaster-" + masterName; + String sessionId = conf.get("session.id"); + return ms.register("HMaster", "HMaster metrics", + new HMasterMetrics(name, sessionId)); + } + + public String getName() { + return name; + } + + public void incrClusterRequests() { + clusterRequests.incr(); + } + + public void incrClusterRequests(int delta) { + clusterRequests.incr(delta); + } + + public MetricMutableCounterInt getClusterRequests() { + return clusterRequests; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (revision 1358294) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java (revision ) @@ -79,6 +79,7 @@ import org.apache.hadoop.hbase.MasterMonitorProtocol; import org.apache.hadoop.hbase.MasterAdminProtocol; import org.apache.hadoop.hbase.RegionServerStatusProtocol; +import org.apache.hadoop.hbase.master.metrics.HMasterMetrics; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.RequestConverter; import org.apache.hadoop.hbase.ipc.ProtocolSignature; @@ -116,6 +117,7 @@ import org.apache.hadoop.hbase.zookeeper.ZKUtil; import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; import org.apache.hadoop.metrics.util.MBeanUtil; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.net.DNS; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.Watcher; @@ -228,6 +230,10 @@ // Metrics for the HMaster private final MasterMetrics metrics; + + // Metrics for the HMaster, using Hadoop's Metrics Framework v2 + private final HMasterMetrics myMetrics; + // file system manager for the master FS operations private MasterFileSystem fileSystemManager; @@ -350,6 +356,11 @@ this.zooKeeper = new ZooKeeperWatcher(conf, MASTER + ":" + isa.getPort(), this, true); this.rpcServer.startThreads(); this.metrics = new MasterMetrics(getServerName().toString()); + + DefaultMetricsSystem.initialize("HMaster"); + // TODO: move to where HMaster starts? + this.myMetrics = HMasterMetrics.create(conf, getServerName().toString()); + // metrics interval: using the same property as region server. this.msgInterval = conf.getInt("hbase.regionserver.msginterval", 3 * 1000); } @@ -957,6 +968,10 @@ return this.zooKeeper; } + HMasterMetrics getMetrics() { + return myMetrics; + } + /* * Start up all services. If any of these threads gets an unhandled exception * then they just die with a logged message. This should be fine because @@ -965,7 +980,7 @@ * need to install an unexpected exception handler. */ void startServiceThreads() throws IOException{ - + // Start the executor service pools this.executorService.startExecutorService(ExecutorType.MASTER_OPEN_REGION, conf.getInt("hbase.master.executor.openregion.threads", 5)); @@ -1119,6 +1134,10 @@ if (sl != null && this.metrics != null) { // Up our metrics. this.metrics.incrementRequests(sl.getTotalNumberOfRequests()); + } + if (sl != null && this.myMetrics != null) { + // Up our metrics. + this.myMetrics.incrClusterRequests(sl.getTotalNumberOfRequests()); } } catch (IOException ioe) { throw new ServiceException(ioe); Index: hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestHMasterMetrics.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestHMasterMetrics.java (revision ) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestHMasterMetrics.java (revision ) @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.master; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.MediumTests; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; +import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos; +import org.apache.hadoop.hbase.regionserver.HRegionServer; +import org.apache.hadoop.hbase.util.Threads; +import org.apache.hadoop.metrics2.MetricsRecordBuilder; +import org.apache.hadoop.metrics2.lib.MetricMutableCounterInt; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import static org.apache.hadoop.test.MetricsAsserts.assertCounter; + +@Category(MediumTests.class) +public class TestHMasterMetrics { + private static final Log LOG = LogFactory.getLog(TestHMasterMetrics.class); + + static { + Logger.getLogger("org.apache.hadoop.hbase").setLevel(Level.DEBUG); + } + + private MiniHBaseCluster cluster; + private HMaster master; + private Configuration conf; + private HBaseTestingUtility TEST_UTIL; + + private void startCluster() throws Exception{ + LOG.info("Starting cluster"); + conf = HBaseConfiguration.create(); + conf.getLong("hbase.splitlog.max.resubmit", 0); + // Make the failure test faster + conf.setInt("zookeeper.recovery.retry", 0); + conf.setInt(HConstants.REGIONSERVER_INFO_PORT, -1); + conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, (float) 100.0); // no load balancing + conf.setBoolean(HConstants.DISTRIBUTED_LOG_SPLITTING_KEY, true); + TEST_UTIL = new HBaseTestingUtility(conf); + TEST_UTIL.startMiniCluster(1, 1); + cluster = TEST_UTIL.getHBaseCluster(); + LOG.info("Waiting for active/ready master"); + cluster.waitForActiveAndReadyMaster(); + master = cluster.getMaster(); + + while (cluster.getLiveRegionServerThreads().size() < 1) { + Threads.sleep(1); + } + } + + @After + public void after() throws Exception { + if (TEST_UTIL != null) { + TEST_UTIL.shutdownMiniCluster(); + } + } + + @Test(timeout=300000) + public void testClusterRequests() throws Exception { + startCluster(); + + MetricMutableCounterInt metric = master.getMetrics().getClusterRequests(); + int val = getValue(metric); + + // sending fake request to master to see how metric value has changed + RegionServerStatusProtos.RegionServerReportRequest.Builder request = + RegionServerStatusProtos.RegionServerReportRequest.newBuilder(); + HRegionServer rs = cluster.getRegionServer(0); + request.setServer(ProtobufUtil.toServerName(rs.getServerName())); + + HBaseProtos.ServerLoad sl = HBaseProtos.ServerLoad.newBuilder() + .setTotalNumberOfRequests(10) + .build(); + request.setLoad(sl); + master.regionServerReport(null, request.build()); + + assertCounter("cluster_requests", val + 10, master.getMetrics()); + master.stopMaster(); + } + + private int getValue(MetricMutableCounterInt metric) { + final int[] value = new int[1]; + MetricsRecordBuilder mrb = Mockito.mock(MetricsRecordBuilder.class, new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + value[0] = (Integer) args[2]; // args are: name, description, value + return invocation.getMock(); + } + }); + metric.snapshot(mrb); + return value[0]; + } +} Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 1358294) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision ) @@ -177,6 +177,7 @@ import org.apache.hadoop.hbase.regionserver.handler.OpenMetaHandler; import org.apache.hadoop.hbase.regionserver.handler.OpenRegionHandler; import org.apache.hadoop.hbase.regionserver.handler.OpenRootHandler; +import org.apache.hadoop.hbase.regionserver.metrics.HRegionServerMetrics; import org.apache.hadoop.hbase.regionserver.metrics.RegionMetricsStorage; import org.apache.hadoop.hbase.regionserver.metrics.RegionServerDynamicMetrics; import org.apache.hadoop.hbase.regionserver.metrics.RegionServerMetrics; @@ -205,6 +206,7 @@ import org.apache.hadoop.io.Writable; import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.metrics.util.MBeanUtil; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.net.DNS; import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.StringUtils; @@ -360,6 +362,9 @@ private RegionServerMetrics metrics; + // Metrics for the HRegionServer, using Hadoop's Metrics Framework v2 + private HRegionServerMetrics myMetrics; + private RegionServerDynamicMetrics dynamicMetrics; /* @@ -1086,6 +1091,11 @@ // Init in here rather than in constructor after thread name has been set this.metrics = new RegionServerMetrics(); this.dynamicMetrics = RegionServerDynamicMetrics.newInstance(); + + DefaultMetricsSystem.initialize("HRegionServer"); + String threadName = Thread.currentThread().getName(); + this.myMetrics = HRegionServerMetrics.create(conf, threadName); + startServiceThreads(); LOG.info("Serving as " + this.serverNameFromMasterPOV + ", RPC listening on " + this.isa + @@ -1329,6 +1339,7 @@ protected void metrics() { this.metrics.regions.set(this.onlineRegions.size()); + this.myMetrics.setRegions(this.onlineRegions.size()); this.metrics.incrementRequests(this.requestCount.get()); this.metrics.requests.intervalHeartBeat(); // Is this too expensive every three seconds getting a lock on onlineRegions @@ -1476,6 +1487,15 @@ */ public RegionServerMetrics getMetrics() { return this.metrics; + } + + /** + * Metrics for the HMaster, using Hadoop's Metrics Framework v2 + * TODO: Rename method after removing old metrics + * @return Region server metrics instance. + */ + public HRegionServerMetrics getHRegionServerMetrics() { + return this.myMetrics; } /**