HADOOP-14944. Add JvmMetrics to KMS.

(cherry picked from commit 86ee0c5e4e)
This commit is contained in:
Xiao Chen 2017-10-17 15:55:30 -07:00
parent 5897095d53
commit 12d19d3978
4 changed files with 84 additions and 0 deletions

View File

@ -58,6 +58,11 @@ public class JvmMetrics implements MetricsSource {
} }
return impl; return impl;
} }
synchronized void shutdown() {
DefaultMetricsSystem.instance().unregisterSource(JvmMetrics.name());
impl = null;
}
} }
@VisibleForTesting @VisibleForTesting
@ -81,6 +86,7 @@ public class JvmMetrics implements MetricsSource {
final ConcurrentHashMap<String, MetricsInfo[]> gcInfoCache = final ConcurrentHashMap<String, MetricsInfo[]> gcInfoCache =
new ConcurrentHashMap<String, MetricsInfo[]>(); new ConcurrentHashMap<String, MetricsInfo[]>();
@VisibleForTesting
JvmMetrics(String processName, String sessionId) { JvmMetrics(String processName, String sessionId) {
this.processName = processName; this.processName = processName;
this.sessionId = sessionId; this.sessionId = sessionId;
@ -104,6 +110,16 @@ public class JvmMetrics implements MetricsSource {
return Singleton.INSTANCE.init(processName, sessionId); return Singleton.INSTANCE.init(processName, sessionId);
} }
/**
* Shutdown the JvmMetrics singleton. This is not necessary if the JVM itself
* is shutdown, but may be necessary for scenarios where JvmMetrics instance
* needs to be re-created while the JVM is still around. One such scenario
* is unit-testing.
*/
public static void shutdownSingleton() {
Singleton.INSTANCE.shutdown();
}
@Override @Override
public void getMetrics(MetricsCollector collector, boolean all) { public void getMetrics(MetricsCollector collector, boolean all) {
MetricsRecordBuilder rb = collector.addRecord(JvmMetrics) MetricsRecordBuilder rb = collector.addRecord(JvmMetrics)

View File

@ -76,6 +76,15 @@ public class KMSConfiguration {
public static final String KMS_AUDIT_AGGREGATION_WINDOW = CONFIG_PREFIX + public static final String KMS_AUDIT_AGGREGATION_WINDOW = CONFIG_PREFIX +
"audit.aggregation.window.ms"; "audit.aggregation.window.ms";
// Process name shown in metrics
public static final String METRICS_PROCESS_NAME_KEY =
CONFIG_PREFIX + "metrics.process.name";
public static final String METRICS_PROCESS_NAME_DEFAULT = "KMS";
// Session id for metrics
public static final String METRICS_SESSION_ID_KEY =
CONFIG_PREFIX + "metrics.session.id";
// KMS Audit logger classes to use // KMS Audit logger classes to use
public static final String KMS_AUDIT_LOGGER_KEY = CONFIG_PREFIX + public static final String KMS_AUDIT_LOGGER_KEY = CONFIG_PREFIX +
"audit.logger"; "audit.logger";

View File

@ -27,12 +27,19 @@ import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.ConfigurationWithLogging; import org.apache.hadoop.conf.ConfigurationWithLogging;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.http.HttpServer2; import org.apache.hadoop.http.HttpServer2;
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
import org.apache.hadoop.metrics2.source.JvmMetrics;
import org.apache.hadoop.security.authorize.AccessControlList; import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.security.ssl.SSLFactory; import org.apache.hadoop.security.ssl.SSLFactory;
import org.apache.hadoop.util.JvmPauseMonitor;
import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.util.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static org.apache.hadoop.crypto.key.kms.server.KMSConfiguration.METRICS_PROCESS_NAME_DEFAULT;
import static org.apache.hadoop.crypto.key.kms.server.KMSConfiguration.METRICS_PROCESS_NAME_KEY;
import static org.apache.hadoop.crypto.key.kms.server.KMSConfiguration.METRICS_SESSION_ID_KEY;
/** /**
* The KMS web server. * The KMS web server.
*/ */
@ -46,6 +53,9 @@ public class KMSWebServer {
private final HttpServer2 httpServer; private final HttpServer2 httpServer;
private final String scheme; private final String scheme;
private final String processName;
private final String sessionId;
private final JvmPauseMonitor pauseMonitor;
KMSWebServer(Configuration conf, Configuration sslConf) throws Exception { KMSWebServer(Configuration conf, Configuration sslConf) throws Exception {
// Override configuration with deprecated environment variables. // Override configuration with deprecated environment variables.
@ -73,6 +83,11 @@ public class KMSWebServer {
boolean sslEnabled = conf.getBoolean(KMSConfiguration.SSL_ENABLED_KEY, boolean sslEnabled = conf.getBoolean(KMSConfiguration.SSL_ENABLED_KEY,
KMSConfiguration.SSL_ENABLED_DEFAULT); KMSConfiguration.SSL_ENABLED_DEFAULT);
scheme = sslEnabled ? HttpServer2.HTTPS_SCHEME : HttpServer2.HTTP_SCHEME; scheme = sslEnabled ? HttpServer2.HTTPS_SCHEME : HttpServer2.HTTP_SCHEME;
processName =
conf.get(METRICS_PROCESS_NAME_KEY, METRICS_PROCESS_NAME_DEFAULT);
sessionId = conf.get(METRICS_SESSION_ID_KEY);
pauseMonitor = new JvmPauseMonitor();
pauseMonitor.init(conf);
String host = conf.get(KMSConfiguration.HTTP_HOST_KEY, String host = conf.get(KMSConfiguration.HTTP_HOST_KEY,
KMSConfiguration.HTTP_HOST_DEFAULT); KMSConfiguration.HTTP_HOST_DEFAULT);
@ -113,6 +128,11 @@ public class KMSWebServer {
public void start() throws IOException { public void start() throws IOException {
httpServer.start(); httpServer.start();
DefaultMetricsSystem.initialize(processName);
final JvmMetrics jm = JvmMetrics.initSingleton(processName, sessionId);
jm.setPauseMonitor(pauseMonitor);
pauseMonitor.start();
} }
public boolean isRunning() { public boolean isRunning() {
@ -125,6 +145,10 @@ public class KMSWebServer {
public void stop() throws Exception { public void stop() throws Exception {
httpServer.stop(); httpServer.stop();
pauseMonitor.stop();
JvmMetrics.shutdownSingleton();
DefaultMetricsSystem.shutdown();
} }
public URL getKMSUrl() { public URL getKMSUrl() {

View File

@ -98,6 +98,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -2693,4 +2694,38 @@ public class TestKMS {
}); });
} }
/*
* Test the jmx page can return, and contains the basic JvmMetrics. Only
* testing in simple mode since the page content is the same, kerberized
* or not.
*/
@Test
public void testKMSJMX() throws Exception {
Configuration conf = new Configuration();
final File confDir = getTestDir();
conf = createBaseKMSConf(confDir, conf);
final String processName = "testkmsjmx";
conf.set(KMSConfiguration.METRICS_PROCESS_NAME_KEY, processName);
writeConf(confDir, conf);
runServer(null, null, confDir, new KMSCallable<Void>() {
@Override
public Void call() throws Exception {
final URL jmxUrl = new URL(
getKMSUrl() + "/jmx?user.name=whatever&qry=Hadoop:service="
+ processName + ",name=JvmMetrics");
LOG.info("Requesting jmx from " + jmxUrl);
final StringBuilder sb = new StringBuilder();
final InputStream in = jmxUrl.openConnection().getInputStream();
final byte[] buffer = new byte[64 * 1024];
int len;
while ((len = in.read(buffer)) > 0) {
sb.append(new String(buffer, 0, len));
}
LOG.info("jmx returned: " + sb.toString());
assertTrue(sb.toString().contains("JvmMetrics"));
return null;
}
});
}
} }