hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From apurt...@apache.org
Subject git commit: HBASE-10289 Avoid random port usage by default JMX Server. Create Custom JMX server (Qiang Tian)
Date Fri, 20 Jun 2014 00:23:50 GMT
Repository: hbase
Updated Branches:
  refs/heads/0.98 0cce7d16a -> 8ac95e73a


HBASE-10289 Avoid random port usage by default JMX Server. Create Custom JMX server (Qiang
Tian)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/8ac95e73
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/8ac95e73
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/8ac95e73

Branch: refs/heads/0.98
Commit: 8ac95e73aeb76bf6bc0679122c772ce093be2955
Parents: 0cce7d1
Author: Andrew Purtell <apurtell@apache.org>
Authored: Thu Jun 19 17:21:06 2014 -0700
Committer: Andrew Purtell <apurtell@apache.org>
Committed: Thu Jun 19 17:21:06 2014 -0700

----------------------------------------------------------------------
 conf/hbase-env.sh                               |   4 +-
 .../org/apache/hadoop/hbase/JMXListener.java    | 190 +++++++++++++++++++
 .../apache/hadoop/hbase/TestJMXListener.java    |  95 ++++++++++
 3 files changed, 288 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/8ac95e73/conf/hbase-env.sh
----------------------------------------------------------------------
diff --git a/conf/hbase-env.sh b/conf/hbase-env.sh
index 91aca76..1885fa9 100644
--- a/conf/hbase-env.sh
+++ b/conf/hbase-env.sh
@@ -74,7 +74,9 @@ export HBASE_OPTS="-XX:+UseConcMarkSweepGC"
 # Uncomment and adjust to enable JMX exporting
 # See jmxremote.password and jmxremote.access in $JRE_HOME/lib/management to configure remote
password access.
 # More details at: http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html
-#
+# NOTE: HBase provides an alternative JMX implementation to fix the random ports issue, please
see JMX
+# section in HBase Reference Guide for instructions.
+
 # export HBASE_JMX_BASE="-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
 # export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS $HBASE_JMX_BASE -Dcom.sun.management.jmxremote.port=10101"
 # export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS $HBASE_JMX_BASE -Dcom.sun.management.jmxremote.port=10102"

http://git-wip-us.apache.org/repos/asf/hbase/blob/8ac95e73/hbase-server/src/main/java/org/apache/hadoop/hbase/JMXListener.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/JMXListener.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/JMXListener.java
new file mode 100644
index 0000000..f292d4c
--- /dev/null
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/JMXListener.java
@@ -0,0 +1,190 @@
+/**
+ *
+ * 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;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.CoprocessorEnvironment;
+import org.apache.hadoop.hbase.coprocessor.*;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.util.HashMap;
+
+import javax.management.MBeanServer;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+/**
+ * Pluggable JMX Agent for HBase(to fix the 2 random TCP ports issue
+ * of the out-of-the-box JMX Agent):
+ * 1)connector port can share with the registry port if SSL is OFF
+ * 2)support password authentication
+ * 3)support subset of SSL (with default configuration)
+ */
+public class JMXListener implements Coprocessor {
+
+  public static final Log LOG = LogFactory.getLog(JMXListener.class);
+  public static final String RMI_REGISTRY_PORT_CONF_KEY = ".rmi.registry.port";
+  public static final String RMI_CONNECTOR_PORT_CONF_KEY = ".rmi.connector.port";
+  public static int defMasterRMIRegistryPort = 10101;
+  public static int defRegionserverRMIRegistryPort = 10102;
+
+  private JMXConnectorServer jmxCS = null;
+
+  public static JMXServiceURL buildJMXServiceURL(int rmiRegistryPort,
+      int rmiConnectorPort) throws IOException {
+    // Build jmxURL
+    StringBuilder url = new StringBuilder();
+    url.append("service:jmx:rmi://localhost:");
+    url.append(rmiConnectorPort);
+    url.append("/jndi/rmi://localhost:");
+    url.append(rmiRegistryPort);
+    url.append("/jmxrmi");
+
+    return new JMXServiceURL(url.toString());
+
+  }
+
+  public void startConnectorServer(int rmiRegistryPort, int rmiConnectorPort)
+              throws IOException {
+    boolean rmiSSL = false;
+    boolean authenticate = true;
+    String passwordFile = null;
+    String accessFile = null;
+
+    System.setProperty("java.rmi.server.randomIDs", "true");
+
+    String rmiSSLValue = System.getProperty("com.sun.management.jmxremote.ssl",
+                                            "false");
+    rmiSSL = Boolean.parseBoolean(rmiSSLValue);
+
+    String authenticateValue =
+        System.getProperty("com.sun.management.jmxremote.authenticate", "false");
+    authenticate = Boolean.parseBoolean(authenticateValue);
+
+    passwordFile = System.getProperty("com.sun.management.jmxremote.password.file");
+    accessFile = System.getProperty("com.sun.management.jmxremote.access.file");
+
+    LOG.info("rmiSSL:" + rmiSSLValue + ",authenticate:" + authenticateValue
+              + ",passwordFile:" + passwordFile + ",accessFile:" + accessFile);
+
+    // Environment map
+    HashMap<String, Object> jmxEnv = new HashMap<String, Object>();
+
+    RMIClientSocketFactory csf = null;
+    RMIServerSocketFactory ssf = null;
+
+    if (rmiSSL) {
+      if (rmiRegistryPort == rmiConnectorPort) {
+        throw new IOException("SSL is enabled. " +
+            "rmiConnectorPort cannot share with the rmiRegistryPort!");
+      }
+      csf = new SslRMIClientSocketFactory();
+      ssf = new SslRMIServerSocketFactory();
+    }
+
+    if (csf != null) {
+      jmxEnv.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
+    }
+    if (ssf != null) {
+      jmxEnv.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf);
+    }
+
+    // Configure authentication
+    if (authenticate) {
+      jmxEnv.put("jmx.remote.x.password.file", passwordFile);
+      jmxEnv.put("jmx.remote.x.access.file", accessFile);
+    }
+
+    // Create the RMI registry
+    LocateRegistry.createRegistry(rmiRegistryPort);
+    // Retrieve the PlatformMBeanServer.
+    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+    // Build jmxURL
+    JMXServiceURL serviceUrl = buildJMXServiceURL(rmiRegistryPort, rmiConnectorPort);
+
+    try {
+      // Start the JMXListener with the connection string
+      jmxCS = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, jmxEnv, mbs);
+      jmxCS.start();
+      LOG.info("ConnectorServer started!");
+    } catch (IOException e) {
+      LOG.error("fail to start connector server!", e);
+    }
+
+  }
+
+  public void stopConnectorServer() throws IOException {
+    if (jmxCS != null) {
+      jmxCS.stop();
+      LOG.info("ConnectorServer stopped!");
+      jmxCS = null;
+    }
+  }
+
+
+  @Override
+  public void start(CoprocessorEnvironment env) throws IOException {
+    int rmiRegistryPort = -1;
+    int rmiConnectorPort = -1;
+    Configuration conf = env.getConfiguration();
+
+    if (env instanceof MasterCoprocessorEnvironment) {
+      // running on Master
+      rmiRegistryPort =
+        conf.getInt("master" + RMI_REGISTRY_PORT_CONF_KEY,
+        defMasterRMIRegistryPort);
+      rmiConnectorPort =
+        conf.getInt("master" + RMI_CONNECTOR_PORT_CONF_KEY, rmiRegistryPort);
+      LOG.info("Master rmiRegistryPort:" + rmiRegistryPort
+        + ",Master rmiConnectorPort:" + rmiConnectorPort);
+
+    } else if (env instanceof RegionServerCoprocessorEnvironment) {
+      // running on RegionServer
+      rmiRegistryPort =
+        conf.getInt("regionserver" + RMI_REGISTRY_PORT_CONF_KEY,
+        defRegionserverRMIRegistryPort);
+      rmiConnectorPort =
+        conf.getInt("regionserver" + RMI_CONNECTOR_PORT_CONF_KEY, rmiRegistryPort);
+      LOG.info("RegionServer rmiRegistryPort:" + rmiRegistryPort
+        + ",RegionServer rmiConnectorPort:" + rmiConnectorPort);
+
+    } else if (env instanceof RegionCoprocessorEnvironment) {
+      LOG.error("JMXListener should not be loaded in Region Environment!");
+    }
+
+    startConnectorServer(rmiRegistryPort, rmiConnectorPort);
+  }
+
+  @Override
+  public void stop(CoprocessorEnvironment env) throws IOException {
+    stopConnectorServer();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/8ac95e73/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXListener.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXListener.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXListener.java
new file mode 100644
index 0000000..719e04f
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXListener.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;
+
+import java.io.IOException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+
+
+
+@Category(MediumTests.class)
+public class TestJMXListener {
+  private static final Log LOG = LogFactory.getLog(TestJMXListener.class);
+  private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
+  private static int connectorPort = 61120;
+
+  @BeforeClass
+  public static void setupBeforeClass() throws Exception {
+    Configuration conf = UTIL.getConfiguration();
+
+    conf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY,
+      JMXListener.class.getName());
+    conf.setInt("regionserver.rmi.registry.port", connectorPort);
+
+    UTIL.startMiniCluster();
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    UTIL.shutdownMiniCluster();
+  }
+
+  @Test
+  public void testStart() throws Exception {
+    JMXConnector connector = JMXConnectorFactory.connect(
+      JMXListener.buildJMXServiceURL(connectorPort,connectorPort));
+
+    MBeanServerConnection mb = connector.getMBeanServerConnection();
+    String domain = mb.getDefaultDomain();
+    Assert.assertTrue("default domain is not correct",
+      !domain.isEmpty());
+    connector.close();
+
+  }
+
+  //shutdown hbase only. then try connect, IOException expected
+  @Rule
+  public ExpectedException expectedEx = ExpectedException.none();
+  @Test
+  public void testStop() throws Exception {
+    MiniHBaseCluster cluster = UTIL.getHBaseCluster();
+    LOG.info("shutdown hbase cluster...");
+    cluster.shutdown();
+    LOG.info("wait for the hbase cluster shutdown...");
+    cluster.waitUntilShutDown();
+
+    JMXConnector connector = JMXConnectorFactory.newJMXConnector(
+      JMXListener.buildJMXServiceURL(connectorPort,connectorPort), null);
+    expectedEx.expect(IOException.class);
+    connector.connect();
+
+  }
+
+
+}
\ No newline at end of file


Mime
View raw message