diff --git src/main/java/org/apache/hadoop/hbase/master/HBaseMasterInfo.java src/main/java/org/apache/hadoop/hbase/master/HBaseMasterInfo.java new file mode 100644 index 0000000..dd778af --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/master/HBaseMasterInfo.java @@ -0,0 +1,161 @@ +/** + * Copyright 2012 The Apache Software Foundation + * + * 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 java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import org.apache.hadoop.hbase.HServerLoad; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.master.AssignmentManager.RegionState; +import org.apache.hadoop.hbase.metrics.HBaseMasterMXBean; + +public class HBaseMasterInfo implements HBaseMasterMXBean { + + private final HMaster master; + + private static HBaseMasterInfo theInstance = null; + public synchronized static HBaseMasterInfo init(final HMaster master) { + if (theInstance == null) { + theInstance = new HBaseMasterInfo(master); + } + return theInstance; + } + + protected HBaseMasterInfo(final HMaster master) { + this.master = master; + } + + @Override + public double getAverageLoad() { + return master.getAverageLoad(); + } + + @Override + public String getClusterId() { + return master.getClusterId(); + } + + @Override + public String getZookeeperQuorum() { + return master.getZooKeeperWatcher().getQuorum(); + } + + @Override + public String[] getCoprocessors() { + return master.getCoprocessors(); + } + + @Override + public long getMasterStartTime() { + return master.getMasterStartTime(); + } + + @Override + public long getMasterActiveTime() { + return master.getMasterActiveTime(); + } + + @Override + public RegionServerInfo[] getRegionServers() { + int regionCnt = master.getServerManager().getOnlineServers().size(); + List info = new ArrayList(regionCnt); + for (final Entry entry : + master.getServerManager().getOnlineServers().entrySet()) { + RegionServerInfo innerinfo = new RegionServerInfo() { + + @Override + public String getRegionServer() { + return entry.getKey().getHostAndPort(); + } + + @Override + public long getStartCode() { + return entry.getKey().getStartcode(); + } + + @Override + public int getRequestsPerSecond() { + return entry.getValue().getNumberOfRequests(); + } + + @Override + public int getNumberOfOnlineRegions() { + return entry.getValue().getNumberOfRegions(); + } + + @Override + public int getMaxHeapMB() { + return entry.getValue().getMaxHeapMB(); + } + + @Override + public int getUsedHeapMB() { + return entry.getValue().getUsedHeapMB(); + } + }; + info.add(innerinfo); + } + RegionServerInfo[] data = new RegionServerInfo[info.size()]; + info.toArray(data); + return data; + } + + @Override + public String[] getDeadRegionServers() { + List deadServers = new ArrayList(); + for (ServerName name : master.getServerManager().getDeadServers()) { + deadServers.add(name.getHostAndPort()); + } + return deadServers.toArray(new String[0]); + } + + @Override + public RegionsInTransitionInfo[] getRegionsInTransition() { + List info = + new ArrayList(); + for (final Entry entry : + master.getAssignmentManager().getRegionsInTransition().entrySet()) { + RegionsInTransitionInfo innerinfo = new RegionsInTransitionInfo() { + + @Override + public String getRegionState() { + return entry.getValue().getState().toString(); + } + + @Override + public String getRegionName() { + return entry.getKey(); + } + + @Override + public long getLastUpdateTime() { + return entry.getValue().getStamp(); + } + }; + info.add(innerinfo); + } + RegionsInTransitionInfo[] data = + new RegionsInTransitionInfo[info.size()]; + info.toArray(data); + return data; + } +} diff --git src/main/java/org/apache/hadoop/hbase/master/HMaster.java src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 9d21903..4ac5d51 100644 --- src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -36,6 +36,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import javax.management.ObjectName; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -69,7 +71,6 @@ import org.apache.hadoop.hbase.ipc.HMasterInterface; import org.apache.hadoop.hbase.ipc.HMasterRegionInterface; import org.apache.hadoop.hbase.ipc.ProtocolSignature; import org.apache.hadoop.hbase.ipc.RpcServer; -import org.apache.hadoop.hbase.master.CatalogJanitor.SplitParentFirstComparator; import org.apache.hadoop.hbase.master.handler.CreateTableHandler; import org.apache.hadoop.hbase.master.handler.DeleteTableHandler; import org.apache.hadoop.hbase.master.handler.DisableTableHandler; @@ -101,6 +102,7 @@ import org.apache.hadoop.hbase.zookeeper.RegionServerTracker; import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; import org.apache.hadoop.io.MapWritable; import org.apache.hadoop.io.Text; +import org.apache.hadoop.metrics2.util.MBeans; import org.apache.hadoop.net.DNS; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.Watcher; @@ -123,7 +125,8 @@ import org.apache.zookeeper.Watcher; * @see Watcher */ public class HMaster extends HasThread -implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { +implements HMasterInterface, HMasterRegionInterface, MasterServices, +Server { private static final Log LOG = LogFactory.getLog(HMaster.class.getName()); // MASTER is name of the webapp and the attribute name used stuffing this @@ -212,6 +215,11 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { private long masterActiveTime; /** + * MX Bean for MasterInfo + */ + private ObjectName mxBean = null; + + /** * Initializes the HMaster. The steps are as follows: *

*

    @@ -545,6 +553,8 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { // Schema janitor chore. this.schemaJanitorChore = getAndStartSchemaJanitorChore(this); + registerMBean(); + status.markComplete("Initialization successful"); LOG.info("Master has completed initialization"); initialized = true; @@ -1375,6 +1385,7 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { this.assignmentManager.clearRegionFromTransition(hri); } } + /** * @return cluster status */ @@ -1415,7 +1426,7 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { public long getMasterActiveTime() { return masterActiveTime; } - + /** * @return array of coprocessor SimpleNames. */ @@ -1567,6 +1578,10 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { LOG.error("Error call master coprocessor preShutdown()", ioe); } } + if (mxBean != null) { + MBeans.unregister(mxBean); + mxBean = null; + } if (this.assignmentManager != null) this.assignmentManager.shutdown(); if (this.serverManager != null) this.serverManager.shutdownCluster(); try { @@ -1769,4 +1784,14 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { VersionInfo.logVersion(); new HMasterCommandLine(HMaster.class).doMain(args); } + + /** + * Register bean with platform management server + */ + void registerMBean() { + HBaseMasterInfo mxBeanInfo = HBaseMasterInfo.init(this); + mxBean = MBeans.register("HBase", "MasterInfo", + mxBeanInfo); + LOG.info("Registered HBaseMasterMXBean"); + } } diff --git src/main/java/org/apache/hadoop/hbase/metrics/HBaseMasterMXBean.java src/main/java/org/apache/hadoop/hbase/metrics/HBaseMasterMXBean.java new file mode 100644 index 0000000..ff13bf5 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/metrics/HBaseMasterMXBean.java @@ -0,0 +1,105 @@ +/** + * Copyright 2012 The Apache Software Foundation + * + * 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.metrics; + +import org.apache.hadoop.classification.InterfaceStability.Evolving; + +/** + * This is the JMX management interface for Hbase master information + */ +@Evolving +public interface HBaseMasterMXBean { + + /** + * Required for MXBean implementation + */ + public static interface RegionServerInfo { + public String getRegionServer(); + public long getStartCode(); + public int getRequestsPerSecond(); + public int getNumberOfOnlineRegions(); + public int getMaxHeapMB(); + public int getUsedHeapMB(); + } + + /** + * Required for MXBean implementation + */ + public static interface RegionsInTransitionInfo { + public String getRegionName(); + public String getRegionState(); + public long getLastUpdateTime(); + } + + /** + * Get Average Load + * @return Average Load + */ + public double getAverageLoad(); + + /** + * Get the Cluster ID + * @return Cluster ID + */ + public String getClusterId(); + + /** + * Get the Zookeeper Quorum Info + * @return Zookeeper Quorum Info + */ + public String getZookeeperQuorum(); + + /** + * Get the co-processors + * @return Co-processors + */ + public String[] getCoprocessors(); + + /** + * Get hbase master start time + * @return Start time of master in milliseconds + */ + public long getMasterStartTime(); + + /** + * Get the hbase master active time + * @return Time in milliseconds when master became active + */ + public long getMasterActiveTime(); + + /** + * Get the live region servers + * @return Live region servers + */ + public RegionServerInfo[] getRegionServers(); + + /** + * Get the dead region servers + * @return Dead region Servers + */ + public String[] getDeadRegionServers(); + + /** + * Get information on regions in transition + * @return Regions in transition + */ + public RegionsInTransitionInfo[] getRegionsInTransition(); + +} diff --git src/main/java/org/apache/hadoop/hbase/metrics/HbaseRegionServerMXBean.java src/main/java/org/apache/hadoop/hbase/metrics/HbaseRegionServerMXBean.java new file mode 100644 index 0000000..9be0f29 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/metrics/HbaseRegionServerMXBean.java @@ -0,0 +1,34 @@ +package org.apache.hadoop.hbase.metrics; + +import org.apache.hadoop.classification.InterfaceStability.Evolving; + +/** + * This is the JMX management interface for HBase Region Server information + */ +@Evolving +public interface HbaseRegionServerMXBean { + + /** + * Return host:port information of hbase master + * @return HBase Master address + */ + public String getHBaseMaster(); + + /** + * Get loaded co-processors + * @return Loaded Co-processors + */ + public String[] getCoprocessors(); + + /** + * Get Zookeeper Quorum Info + * @return Zookeeper Quorum Info + */ + public String getZookeeperQuorum(); + + /** + * Get Region Server Start Time + * @return Start time of Region Server in milliseconds + */ + public long getStartCode(); +} diff --git src/main/java/org/apache/hadoop/hbase/regionserver/HBaseRegionServerInfo.java src/main/java/org/apache/hadoop/hbase/regionserver/HBaseRegionServerInfo.java new file mode 100644 index 0000000..8309a87 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/regionserver/HBaseRegionServerInfo.java @@ -0,0 +1,66 @@ +/** + * Copyright 2012 The Apache Software Foundation + * + * 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.hadoop.hbase.metrics.HbaseRegionServerMXBean; + +public class HBaseRegionServerInfo implements HbaseRegionServerMXBean { + + private final HRegionServer regionServer; + + private static HBaseRegionServerInfo theInstance = null; + public synchronized static HBaseRegionServerInfo init(final HRegionServer rs) { + if (theInstance == null) { + theInstance = new HBaseRegionServerInfo(rs); + } + return theInstance; + } + + protected HBaseRegionServerInfo(final HRegionServer rs) { + this.regionServer = rs; + } + + @Override + public String getHBaseMaster() { + int masterInfoPort = + regionServer.getConfiguration().getInt("hbase.master.info.port", 60010); + if (masterInfoPort < 0) { + return "Invalid"; + } + return regionServer.getMasterAddressManager() + .getMasterAddress().getHostname() + ":" + masterInfoPort; + } + + @Override + public String[] getCoprocessors() { + return regionServer.getCoprocessors(); + } + + @Override + public String getZookeeperQuorum() { + return regionServer.getZooKeeperWatcher().getQuorum(); + } + + @Override + public long getStartCode() { + return regionServer.getStartcode(); + } + +} diff --git src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 5cb606f..dc1a32d 100644 --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -49,6 +49,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantReadWriteLock; +import javax.management.ObjectName; + import org.apache.commons.lang.mutable.MutableDouble; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -150,6 +152,7 @@ import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; import org.apache.hadoop.io.MapWritable; import org.apache.hadoop.io.Writable; import org.apache.hadoop.ipc.RemoteException; +import org.apache.hadoop.metrics2.util.MBeans; import org.apache.hadoop.net.DNS; import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.StringUtils; @@ -342,6 +345,11 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, private static final String CLOSE = "CLOSE"; /** + * MX Bean for RegionServerInfo + */ + private ObjectName mxBean = null; + + /** * Starts a HRegionServer at the default location * * @param conf @@ -668,6 +676,7 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, break; } } + registerMBean(); // We registered with the Master. Go into run mode. long lastMsg = 0; @@ -714,6 +723,10 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, } } // Run shutdown. + if (mxBean != null) { + MBeans.unregister(mxBean); + mxBean = null; + } if (this.thriftServer != null) this.thriftServer.shutdown(); this.leases.closeAfterLeasesExpire(); this.rpcServer.stop(); @@ -3666,4 +3679,15 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, HServerLoad hsl = buildServerLoad(); return hsl == null? null: hsl.getCoprocessors(); } + + /** + * Register bean with platform management server + */ + void registerMBean() { + HBaseRegionServerInfo mxBeanInfo = HBaseRegionServerInfo.init(this); + mxBean = MBeans.register("HBase", "RegionServerInfo", + mxBeanInfo); + LOG.info("Registered HBaseRegionServerMXBean"); + } + } diff --git src/test/java/org/apache/hadoop/hbase/master/TestHBaseMasterInfo.java src/test/java/org/apache/hadoop/hbase/master/TestHBaseMasterInfo.java new file mode 100644 index 0000000..d4386d0 --- /dev/null +++ src/test/java/org/apache/hadoop/hbase/master/TestHBaseMasterInfo.java @@ -0,0 +1,98 @@ +/** + * Copyright 2012 The Apache Software Foundation + * + * 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 java.util.HashMap; +import java.util.Map; + +import junit.framework.Assert; + +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.metrics.HBaseMasterMXBean.RegionServerInfo; +import org.apache.hadoop.hbase.regionserver.HRegionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestHBaseMasterInfo { + + private static final HBaseTestingUtility TEST_UTIL = + new HBaseTestingUtility(); + + @BeforeClass + public static void setup() throws Exception { + TEST_UTIL.startMiniCluster(1, 4); + } + + @AfterClass + public static void teardown() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + private void verifyRegionServers(RegionServerInfo[] regionServers) { + Map expected = new HashMap(); + for (int i = 0; i < 4; ++i) { + HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i); + expected.put(rs.getServerName().getHostAndPort(), + rs.getStartcode()); + } + + int found = 0; + for (RegionServerInfo rs : regionServers) { + if (expected.containsKey(rs.getRegionServer()) + && expected.get(rs.getRegionServer()) == rs.getStartCode()) { + ++found; + } + } + Assert.assertEquals(4, found); + } + + @Test + public void testInfo() { + HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); + HBaseMasterInfo info = HBaseMasterInfo.init(master); + Assert.assertEquals(master.getAverageLoad(), info.getAverageLoad()); + Assert.assertEquals(master.getClusterId(), info.getClusterId()); + Assert.assertEquals(master.getMasterActiveTime(), + info.getMasterActiveTime()); + Assert.assertEquals(master.getMasterStartTime(), + info.getMasterStartTime()); + Assert.assertEquals(master.getCoprocessors().length, + info.getCoprocessors().length); + Assert.assertEquals(master.getServerManager().getOnlineServersList().size(), + info.getRegionServers().length); + Assert.assertEquals(master.getAssignmentManager().isRegionsInTransition(), + info.getRegionsInTransition().length > 0); + Assert.assertTrue(info.getRegionServers().length == 4); + + String zkServers = info.getZookeeperQuorum(); + Assert.assertEquals(zkServers.split(",").length, + TEST_UTIL.getZkCluster().getZooKeeperServerNum()); + + verifyRegionServers(info.getRegionServers()); + + TEST_UTIL.getMiniHBaseCluster().stopRegionServer(3, false); + TEST_UTIL.getMiniHBaseCluster().waitOnRegionServer(3); + Assert.assertTrue(info.getRegionServers().length == 3); + Assert.assertTrue(info.getDeadRegionServers().length == 1); + + } + +} diff --git src/test/java/org/apache/hadoop/hbase/regionserver/TestHBaseRegionServerInfo.java src/test/java/org/apache/hadoop/hbase/regionserver/TestHBaseRegionServerInfo.java new file mode 100644 index 0000000..b2b5974 --- /dev/null +++ src/test/java/org/apache/hadoop/hbase/regionserver/TestHBaseRegionServerInfo.java @@ -0,0 +1,64 @@ +/** + * Copyright 2012 The Apache Software Foundation + * + * 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 junit.framework.Assert; + +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.master.HMaster; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestHBaseRegionServerInfo { + + private static final HBaseTestingUtility TEST_UTIL = + new HBaseTestingUtility(); + + @BeforeClass + public static void setup() throws Exception { + TEST_UTIL.startMiniCluster(1, 1); + } + + @AfterClass + public static void teardown() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testInfo() { + HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0); + HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); + HBaseRegionServerInfo info = HBaseRegionServerInfo.init(rs); + + Assert.assertEquals(rs.getStartcode(), info.getStartCode()); + Assert.assertEquals(rs.getCoprocessors().length, + info.getCoprocessors().length); + rs.getConfiguration().setInt("hbase.master.info.port", + master.getServerName().getPort()); + Assert.assertEquals(master.getServerName().getHostAndPort(), + info.getHBaseMaster()); + + String zkServers = info.getZookeeperQuorum(); + Assert.assertEquals(zkServers.split(",").length, + TEST_UTIL.getZkCluster().getZooKeeperServerNum()); + } + +}