Skip to content
Permalink
Browse files
Support metrics of backend store
Implement #136

Change-Id: I3524bd483f33e57a8b0c0a742861c829346f0ec6
  • Loading branch information
Linary authored and zhoney committed Nov 15, 2018
1 parent 684eabc commit 54ae2576dffdee0f30b090573c9d2e21c4836f77
Showing 17 changed files with 464 additions and 51 deletions.
@@ -30,18 +30,30 @@
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;

import org.slf4j.Logger;

import com.baidu.hugegraph.api.API;
import com.baidu.hugegraph.backend.store.BackendMetrics;
import com.baidu.hugegraph.backend.tx.GraphTransaction;
import com.baidu.hugegraph.core.GraphManager;
import com.baidu.hugegraph.exception.NotSupportException;
import com.baidu.hugegraph.metric.ServerReporter;
import com.baidu.hugegraph.metric.SystemMetrics;
import com.baidu.hugegraph.util.InsertionOrderUtil;
import com.baidu.hugegraph.util.JsonUtil;
import com.baidu.hugegraph.util.Log;
import com.codahale.metrics.Metric;
import com.codahale.metrics.annotation.Timed;
import com.codahale.metrics.json.MetricsModule;

@Singleton
@Path("metrics")
public class MetricsAPI extends API {

private static final Logger LOG = Log.logger(MetricsAPI.class);

private SystemMetrics systemMetrics;

static {
@@ -53,6 +65,7 @@ public MetricsAPI() {
}

@GET
@Timed
@Path("system")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
@@ -61,6 +74,29 @@ public String system() {
}

@GET
@Timed
@Path("backend")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
public String backend(@Context GraphManager manager) {
Map<String, Map<String, Object>> results = InsertionOrderUtil.newMap();
for (String graph : manager.graphs()) {
GraphTransaction tx = manager.graph(graph).graphTransaction();
Map<String, Object> metrics = InsertionOrderUtil.newMap();
metrics.put(BackendMetrics.BACKEND, tx.store().provider().type());
try {
metrics.putAll(tx.metadata(null, "metrics"));
} catch (NotSupportException e) {
metrics.put(BackendMetrics.EXCEPTION, e.toString());
LOG.debug("Failed to get backend metrics", e);
}
results.put(graph, metrics);
}
return JsonUtil.toJson(results);
}

@GET
@Timed
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
public String all() {
@@ -75,6 +111,7 @@ public String all() {
}

@GET
@Timed
@Path("gauges")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
@@ -84,6 +121,7 @@ public String gauges() {
}

@GET
@Timed
@Path("counters")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
@@ -93,6 +131,7 @@ public String counters() {
}

@GET
@Timed
@Path("histograms")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
@@ -102,6 +141,7 @@ public String histograms() {
}

@GET
@Timed
@Path("meters")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
@@ -111,10 +151,11 @@ public String meters() {
}

@GET
@Path("times")
@Timed
@Path("timers")
@Produces(APPLICATION_JSON_WITH_CHARSET)
@RolesAllowed("admin")
public String times() {
public String timers() {
ServerReporter reporter = ServerReporter.instance();
return JsonUtil.toJson(reporter.timers());
}
@@ -0,0 +1,73 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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 com.baidu.hugegraph.backend.store.cassandra;

import java.lang.management.MemoryUsage;
import java.util.Map;

import org.apache.cassandra.tools.NodeProbe;

import com.baidu.hugegraph.backend.store.BackendMetrics;
import com.baidu.hugegraph.config.HugeConfig;
import com.baidu.hugegraph.util.Bytes;
import com.baidu.hugegraph.util.InsertionOrderUtil;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Host;

public class CassandraMetrics implements BackendMetrics {

private final Cluster cluster;
private final int port;
private final String username;
private final String password;

public CassandraMetrics(Cluster cluster, HugeConfig conf) {
this.cluster = cluster;
this.port = conf.get(CassandraOptions.CASSANDRA_JMX_PORT);
this.username = conf.get(CassandraOptions.CASSANDRA_USERNAME);
this.password = conf.get(CassandraOptions.CASSANDRA_PASSWORD);
}

@Override
public Map<String, Object> getMetrics() {
Map<String, Object> results = InsertionOrderUtil.newMap();
for (Host host : this.cluster.getMetadata().getAllHosts()) {
String address = host.getAddress().getHostAddress();
results.put(address, this.getMetricsByHost(address));
}
return results;
}

private Map<String, Object> getMetricsByHost(String host) {
Map<String, Object> metrics = InsertionOrderUtil.newMap();
// JMX client operations for Cassandra.
try (NodeProbe probe = new NodeProbe(host, port, username, password)) {
MemoryUsage heapUsage = probe.getHeapMemoryUsage();
metrics.put(MEM_USED, heapUsage.getUsed() / Bytes.MB);
metrics.put(MEM_COMMITED, heapUsage.getCommitted() / Bytes.MB);
metrics.put(MEM_MAX, heapUsage.getMax() / Bytes.MB);
metrics.put(MEM_UNIT, "MB");
metrics.put(DATA_SIZE, probe.getLoadString());
} catch (Exception e) {
metrics.put(EXCEPTION, e.toString());
}
return metrics;
}
}
@@ -111,4 +111,12 @@ public static synchronized CassandraOptions instance() {
allowValues("none", "snappy", "lz4"),
"none"
);

public static final ConfigOption<Integer> CASSANDRA_JMX_PORT =
new ConfigOption<>(
"cassandra.jmx_port",
"The port of JMX API service for cassandra",
rangeInt(1, 65535),
7199
);
}
@@ -29,11 +29,11 @@
import com.baidu.hugegraph.backend.BackendException;
import com.baidu.hugegraph.backend.id.Id;
import com.baidu.hugegraph.backend.query.Query;
import com.baidu.hugegraph.backend.store.AbstractBackendStore;
import com.baidu.hugegraph.backend.store.BackendAction;
import com.baidu.hugegraph.backend.store.BackendEntry;
import com.baidu.hugegraph.backend.store.BackendFeatures;
import com.baidu.hugegraph.backend.store.BackendMutation;
import com.baidu.hugegraph.backend.store.BackendStore;
import com.baidu.hugegraph.backend.store.BackendStoreProvider;
import com.baidu.hugegraph.config.HugeConfig;
import com.baidu.hugegraph.type.HugeType;
@@ -46,7 +46,7 @@
import com.datastax.driver.core.exceptions.InvalidQueryException;
import com.datastax.driver.core.schemabuilder.SchemaBuilder;

public abstract class CassandraStore implements BackendStore {
public abstract class CassandraStore extends AbstractBackendStore {

private static final Logger LOG = Log.logger(CassandraStore.class);

@@ -58,6 +58,7 @@ public abstract class CassandraStore implements BackendStore {
private final BackendStoreProvider provider;

private final CassandraSessionPool sessions;
// TODO: move to parent class
private final Map<HugeType, CassandraTable> tables;

private HugeConfig conf;
@@ -77,9 +78,17 @@ public CassandraStore(final BackendStoreProvider provider,

this.conf = null;

this.registerMetaHandlers();
LOG.debug("Store loaded: {}", store);
}

private void registerMetaHandlers() {
this.registerMetaHandler("metrics", (session, meta, args) -> {
CassandraMetrics metrics = new CassandraMetrics(cluster(), conf);
return metrics.getMetrics();
});
}

protected void registerTableManager(HugeType type, CassandraTable table) {
this.tables.put(type, table);
}
@@ -226,14 +235,6 @@ public Iterator<BackendEntry> query(Query query) {
return table.query(this.sessions.session(), query);
}

@Override
public <R> R metadata(HugeType type, String meta, Object[] args) {
this.checkSessionConnected();

CassandraTable table = this.table(type);
return table.metadata(this.sessions.session(), meta, args);
}

@Override
public BackendFeatures features() {
return FEATURES;
@@ -406,6 +407,7 @@ protected void clearTables() {
}
}

@Override
protected final CassandraTable table(HugeType type) {
assert type != null;
CassandraTable table = this.tables.get(type);
@@ -415,6 +417,12 @@ protected final CassandraTable table(HugeType type) {
return table;
}

@Override
protected CassandraSessionPool.Session session(HugeType type) {
this.checkSessionConnected();
return this.sessions.session();
}

protected final void checkClusterConnected() {
E.checkState(this.sessions != null,
"Cassandra store has not been initialized");
@@ -0,0 +1,58 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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 com.baidu.hugegraph.backend.store;

import com.baidu.hugegraph.type.HugeType;

public abstract class AbstractBackendStore implements BackendStore {

private final MetaDispatcher dispatcher;

public AbstractBackendStore() {
this.dispatcher = new MetaDispatcher();
}

protected MetaDispatcher metaDispatcher() {
return this.dispatcher;
}

public <Session extends BackendSession>
void registerMetaHandler(String name, MetaHandler<Session> handler) {
this.dispatcher.registerMetaHandler(name, handler);
}

// Get metadata by key
public <R> R metadata(HugeType type, String meta, Object[] args) {
BackendSession session = this.session(type);
MetaDispatcher dispatcher = null;
if (type == null) {
dispatcher = this.metaDispatcher();
} else {
BackendTable table = this.table(type);
dispatcher = table.metaDispatcher();
}
return dispatcher.dispatchMetaHandler(session, meta, args);
}

protected abstract BackendTable table(HugeType type);

// NOTE: Need to support passing null
protected abstract BackendSession session(HugeType type);
}
@@ -0,0 +1,40 @@
/*
* Copyright 2017 HugeGraph Authors
*
* 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 com.baidu.hugegraph.backend.store;

import java.util.Map;

public interface BackendMetrics {

public String BACKEND = "backend";

// Memory related metrics
public String MEM_USED = "mem_used";
public String MEM_COMMITED = "mem_commited";
public String MEM_MAX = "mem_max";
public String MEM_UNIT = "mem_unit";

// Data load related metrics
public String DATA_SIZE = "data_size";

public String EXCEPTION = "exception";

public Map<String, Object> getMetrics();
}

0 comments on commit 54ae257

Please sign in to comment.