diff --git src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 6e509f1..9667968 100644 --- src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -2977,6 +2977,10 @@ public class AssignmentManager extends ZooKeeperListener { return region; } + public ServerName getServerName() { + return serverName; + } + public boolean isClosing() { return state == State.CLOSING; } diff --git src/main/java/org/apache/hadoop/hbase/master/HMaster.java src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 9d21903..034a4cc 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.metrics.util.MBeanUtil; 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. */ @@ -1558,6 +1569,7 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { return rsFatals; } + @SuppressWarnings("deprecation") @Override public void shutdown() { if (cpHost != null) { @@ -1567,6 +1579,10 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { LOG.error("Error call master coprocessor preShutdown()", ioe); } } + if (mxBean != null) { + MBeanUtil.unregisterMBean(mxBean); + mxBean = null; + } if (this.assignmentManager != null) this.assignmentManager.shutdown(); if (this.serverManager != null) this.serverManager.shutdownCluster(); try { @@ -1769,4 +1785,14 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { VersionInfo.logVersion(); new HMasterCommandLine(HMaster.class).doMain(args); } + + /** + * Register bean with platform management server + */ + @SuppressWarnings("deprecation") + void registerMBean() { + MXBeanImpl mxBeanInfo = MXBeanImpl.init(this); + MBeanUtil.registerMBean("org.apache.hbase", "Master", mxBeanInfo); + LOG.info("Registered HMaster MXBean"); + } } diff --git src/main/java/org/apache/hadoop/hbase/master/MXBean.java src/main/java/org/apache/hadoop/hbase/master/MXBean.java new file mode 100644 index 0000000..7f44dc2 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/master/MXBean.java @@ -0,0 +1,118 @@ +/** + * 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.Map; + +import org.apache.hadoop.classification.InterfaceStability.Evolving; +import org.apache.hadoop.hbase.HServerLoad; + +/** + * This is the JMX management interface for Hbase master information + */ +@Evolving +public interface MXBean { + + /** + * Required for MXBean implementation + */ + public static interface RegionsInTransitionInfo { + /** + * Name of region in transition + */ + public String getRegionName(); + /** + * Current transition state + */ + public String getRegionState(); + /** + * Get Region Server name + */ + public String getRegionServerName(); + /** + * Get last update time + */ + public long getLastUpdateTime(); + } + + /** + * Get ServerName + */ + public String getServerName(); + + /** + * 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(); + + /** + * Whether this master is the active master + * @return True if this is the active master + */ + public boolean getIsActiveMaster(); + + /** + * Get the live region servers + * @return Live region servers + */ + public Map 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/master/MXBeanImpl.java src/main/java/org/apache/hadoop/hbase/master/MXBeanImpl.java new file mode 100644 index 0000000..45b8fe7 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/master/MXBeanImpl.java @@ -0,0 +1,150 @@ +/** + * 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.HashMap; +import java.util.List; +import java.util.Map; +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; + +/** + * Impl for exposing HMaster Information through JMX + */ +public class MXBeanImpl implements MXBean { + + private final HMaster master; + + private static MXBeanImpl instance = null; + public synchronized static MXBeanImpl init(final HMaster master) { + if (instance == null) { + instance = new MXBeanImpl(master); + } + return instance; + } + + protected MXBeanImpl(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 Map getRegionServers() { + Map data = new HashMap(); + for (final Entry entry : + master.getServerManager().getOnlineServers().entrySet()) { + data.put(entry.getKey().getServerName(), + entry.getValue()); + } + 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(); + } + + @Override + public String getRegionServerName() { + ServerName serverName = entry.getValue().getServerName(); + if (serverName != null) { + return serverName.getServerName(); + } + else { + return ""; + } + } + }; + info.add(innerinfo); + } + RegionsInTransitionInfo[] data = + new RegionsInTransitionInfo[info.size()]; + info.toArray(data); + return data; + } + + @Override + public String getServerName() { + return master.getServerName().getServerName(); + } + + @Override + public boolean getIsActiveMaster() { + return master.isActiveMaster(); + } +} diff --git src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 2afe159..8410092 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.metrics.util.MBeanUtil; 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 @@ -647,6 +655,7 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, /** * The HRegionServer sticks in this loop until closed. */ + @SuppressWarnings("deprecation") public void run() { try { // Do pre-registration initializations; zookeeper, lease threads, etc. @@ -668,6 +677,7 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, break; } } + registerMBean(); // We registered with the Master. Go into run mode. long lastMsg = 0; @@ -714,6 +724,10 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, } } // Run shutdown. + if (mxBean != null) { + MBeanUtil.unregisterMBean(mxBean); + mxBean = null; + } if (this.thriftServer != null) this.thriftServer.shutdown(); this.leases.closeAfterLeasesExpire(); this.rpcServer.stop(); @@ -3669,4 +3683,16 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, HServerLoad hsl = buildServerLoad(); return hsl == null? null: hsl.getCoprocessors(); } + + /** + * Register bean with platform management server + */ + @SuppressWarnings("deprecation") + void registerMBean() { + MXBeanImpl mxBeanInfo = MXBeanImpl.init(this); + mxBean = MBeanUtil.registerMBean("org.apache.hbase", "RegionServer", + mxBeanInfo); + LOG.info("Registered RegionServer MXBean"); + } + } diff --git src/main/java/org/apache/hadoop/hbase/regionserver/MXBean.java src/main/java/org/apache/hadoop/hbase/regionserver/MXBean.java new file mode 100644 index 0000000..b0a92c5 --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/regionserver/MXBean.java @@ -0,0 +1,46 @@ +/** + * 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.classification.InterfaceStability.Evolving; + +/** + * This is the JMX management interface for HBase Region Server information + */ +@Evolving +public interface MXBean { + + /** + * Return RegionServer's ServerName + * @return ServerName + */ + public String getServerName(); + + /** + * Get loaded co-processors + * @return Loaded Co-processors + */ + public String[] getCoprocessors(); + + /** + * Get Zookeeper Quorum + * @return Comma-separated list of Zookeeper Quorum servers + */ + public String getZookeeperQuorum(); +} diff --git src/main/java/org/apache/hadoop/hbase/regionserver/MXBeanImpl.java src/main/java/org/apache/hadoop/hbase/regionserver/MXBeanImpl.java new file mode 100644 index 0000000..78f3b6f --- /dev/null +++ src/main/java/org/apache/hadoop/hbase/regionserver/MXBeanImpl.java @@ -0,0 +1,54 @@ +/** + * 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; + +/** + * Impl for exposing Region Server Information through JMX + */ +public class MXBeanImpl implements MXBean { + + private final HRegionServer regionServer; + + private static MXBeanImpl instance = null; + public synchronized static MXBeanImpl init(final HRegionServer rs){ + if (instance == null) { + instance = new MXBeanImpl(rs); + } + return instance; + } + + protected MXBeanImpl(final HRegionServer rs) { + this.regionServer = rs; + } + + @Override + public String[] getCoprocessors() { + return regionServer.getCoprocessors(); + } + + @Override + public String getZookeeperQuorum() { + return regionServer.getZooKeeper().getQuorum(); + } + + @Override + public String getServerName() { + return regionServer.getServerName().getServerName(); + } + +} diff --git src/test/java/org/apache/hadoop/hbase/master/TestMXBean.java src/test/java/org/apache/hadoop/hbase/master/TestMXBean.java new file mode 100644 index 0000000..379f70c --- /dev/null +++ src/test/java/org/apache/hadoop/hbase/master/TestMXBean.java @@ -0,0 +1,95 @@ +/** + * 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.HashSet; +import java.util.Map; +import java.util.Set; + +import junit.framework.Assert; + +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HServerLoad; +import org.apache.hadoop.hbase.regionserver.HRegionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestMXBean { + + 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(Map regions) { + Set expected = new HashSet(); + for (int i = 0; i < 4; ++i) { + HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(i); + expected.add(rs.getServerName().getServerName()); + } + + int found = 0; + for (java.util.Map.Entry entry : regions.entrySet()) { + if (expected.contains(entry.getKey())) { + ++found; + } + } + Assert.assertEquals(4, found); + } + + @Test + public void testInfo() { + HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); + MXBeanImpl info = MXBeanImpl.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().size()); + Assert.assertEquals(master.getAssignmentManager().isRegionsInTransition(), + info.getRegionsInTransition().length > 0); + Assert.assertTrue(info.getRegionServers().size() == 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().size() == 3); + Assert.assertTrue(info.getDeadRegionServers().length == 1); + + } + +} diff --git src/test/java/org/apache/hadoop/hbase/regionserver/TestMXBean.java src/test/java/org/apache/hadoop/hbase/regionserver/TestMXBean.java new file mode 100644 index 0000000..83e02c7 --- /dev/null +++ src/test/java/org/apache/hadoop/hbase/regionserver/TestMXBean.java @@ -0,0 +1,58 @@ +/** + * 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 TestMXBean { + + 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(); + MXBeanImpl info = MXBeanImpl.init(rs); + + Assert.assertEquals(rs.getServerName().getServerName(), + info.getServerName()); + Assert.assertEquals(rs.getCoprocessors().length, + info.getCoprocessors().length); + rs.getConfiguration().setInt("hbase.master.info.port", + master.getServerName().getPort()); + Assert.assertEquals(rs.getZooKeeperWatcher().getQuorum(), + info.getZookeeperQuorum()); + } +}