From 1428c8bf111ffcccd3d2102597b68b3d161a6ee6 Mon Sep 17 00:00:00 2001 From: zhoney Date: Tue, 4 Feb 2020 21:03:44 +0800 Subject: [PATCH] add "nodes" metadata for backends (#821) implemented: #816 Change-Id: Ica7be59f1af1f290342b010c0c018cc541a1122b --- .../store/cassandra/CassandraMetrics.java | 12 +- .../store/cassandra/CassandraSessionPool.java | 2 +- .../store/cassandra/CassandraStore.java | 3 +- .../java/com/baidu/hugegraph/HugeFactory.java | 2 +- .../backend/store/BackendMetrics.java | 2 + .../backend/store/memory/InMemoryDBStore.java | 10 ++ .../backend/store/memory/InMemoryMetrics.java | 33 ++++++ .../backend/store/hbase/HbaseMetrics.java | 111 ++++++++++++++++++ .../backend/store/hbase/HbaseSessions.java | 5 + .../backend/store/hbase/HbaseStore.java | 11 ++ .../backend/store/mysql/MysqlMetrics.java | 33 ++++++ .../backend/store/mysql/MysqlStore.java | 8 ++ .../backend/store/rocksdb/RocksDBMetrics.java | 1 + .../baidu/hugegraph/api/MetricsApiTest.java | 35 +++++- 14 files changed, 257 insertions(+), 11 deletions(-) create mode 100644 hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryMetrics.java create mode 100644 hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseMetrics.java create mode 100644 hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlMetrics.java diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraMetrics.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraMetrics.java index 2f6370bb17..d05ebd3852 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraMetrics.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraMetrics.java @@ -22,12 +22,14 @@ import java.io.IOException; import java.lang.management.MemoryUsage; import java.util.Map; +import java.util.Set; 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.E; import com.baidu.hugegraph.util.InsertionOrderUtil; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Host; @@ -39,8 +41,10 @@ public class CassandraMetrics implements BackendMetrics { private final String username; private final String password; - public CassandraMetrics(Cluster cluster, HugeConfig conf) { - this.cluster = cluster; + public CassandraMetrics(CassandraSessionPool sessions, HugeConfig conf) { + E.checkArgumentNotNull(sessions, + "Cassandra sessions have not been initialized"); + this.cluster = sessions.cluster(); this.port = conf.get(CassandraOptions.CASSANDRA_JMX_PORT); this.username = conf.get(CassandraOptions.CASSANDRA_USERNAME); this.password = conf.get(CassandraOptions.CASSANDRA_PASSWORD); @@ -50,7 +54,9 @@ public CassandraMetrics(Cluster cluster, HugeConfig conf) { @Override public Map getMetrics() { Map results = InsertionOrderUtil.newMap(); - for (Host host : this.cluster.getMetadata().getAllHosts()) { + Set hosts = this.cluster.getMetadata().getAllHosts(); + results.put(NODES, hosts.size()); + for (Host host : hosts) { String address = host.getAddress().getHostAddress(); results.put(address, this.getMetricsByHost(address)); } diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSessionPool.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSessionPool.java index 328bc4ab7c..6dace5abc7 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSessionPool.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraSessionPool.java @@ -99,7 +99,7 @@ public final synchronized boolean opened() { return (this.cluster != null && !this.cluster.isClosed()); } - public final synchronized Cluster cluster() { + protected final synchronized Cluster cluster() { E.checkState(this.cluster != null, "Cassandra cluster has not been initialized"); return this.cluster; diff --git a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStore.java b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStore.java index 86dfb59295..b1d73b03bb 100644 --- a/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStore.java +++ b/hugegraph-cassandra/src/main/java/com/baidu/hugegraph/backend/store/cassandra/CassandraStore.java @@ -89,7 +89,8 @@ public CassandraStore(final BackendStoreProvider provider, private void registerMetaHandlers() { this.registerMetaHandler("metrics", (session, meta, args) -> { - CassandraMetrics metrics = new CassandraMetrics(cluster(), this.conf); + CassandraMetrics metrics = new CassandraMetrics(this.sessions, + this.conf); return metrics.getMetrics(); }); } diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/HugeFactory.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/HugeFactory.java index 31732a546f..f35e6a4ae4 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/HugeFactory.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/HugeFactory.java @@ -45,7 +45,7 @@ public static synchronized HugeGraph open(Configuration config) { "Invalid graph name '%s', valid graph name is up to " + "48 alpha-numeric characters and underscores " + "and only letters are supported as first letter. " + - "Note: letter is case insensitive"); + "Note: letter is case insensitive", name); name = name.toLowerCase(); HugeGraph graph = graphs.get(name); if (graph == null || graph.closed()) { diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/BackendMetrics.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/BackendMetrics.java index 1f8c14dbd8..a5ee6825dd 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/BackendMetrics.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/BackendMetrics.java @@ -25,6 +25,8 @@ public interface BackendMetrics { public String BACKEND = "backend"; + public String NODES = "nodes"; + // Memory related metrics public String MEM_USED = "mem_used"; public String MEM_COMMITED = "mem_commited"; diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryDBStore.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryDBStore.java index d95a7c607f..625b8e5af1 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryDBStore.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryDBStore.java @@ -73,6 +73,16 @@ public InMemoryDBStore(final BackendStoreProvider provider, this.database = database; this.store = store; this.tables = new HashMap<>(); + + this.registerMetaHandlers(); + LOG.debug("Store loaded: {}", store); + } + + private void registerMetaHandlers() { + this.registerMetaHandler("metrics", (session, meta, args) -> { + InMemoryMetrics metrics = new InMemoryMetrics(); + return metrics.getMetrics(); + }); } protected void registerTableManager(HugeType type, InMemoryDBTable table) { diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryMetrics.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryMetrics.java new file mode 100644 index 0000000000..aca750a38b --- /dev/null +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/backend/store/memory/InMemoryMetrics.java @@ -0,0 +1,33 @@ +/* + * 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.memory; + +import java.util.Map; + +import com.baidu.hugegraph.backend.store.BackendMetrics; +import com.google.common.collect.ImmutableMap; + +public class InMemoryMetrics implements BackendMetrics { + + @Override + public Map getMetrics() { + return ImmutableMap.of(NODES, 1); + } +} diff --git a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseMetrics.java b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseMetrics.java new file mode 100644 index 0000000000..133e34d3a6 --- /dev/null +++ b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseMetrics.java @@ -0,0 +1,111 @@ +/* + * 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.hbase; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.hadoop.hbase.ClusterMetrics; +import org.apache.hadoop.hbase.RegionMetrics; +import org.apache.hadoop.hbase.ServerMetrics; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.Size; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Connection; + +import com.baidu.hugegraph.backend.store.BackendMetrics; +import com.baidu.hugegraph.util.E; +import com.baidu.hugegraph.util.InsertionOrderUtil; + +public class HbaseMetrics implements BackendMetrics { + + private final Connection hbase; + + public HbaseMetrics(HbaseSessions hbase) { + E.checkArgumentNotNull(hbase, "HBase connection is not opened"); + this.hbase = hbase.hbase(); + } + + @Override + public Map getMetrics() { + Map results = InsertionOrderUtil.newMap(); + try (Admin admin = this.hbase.getAdmin()) { + // Cluster info + ClusterMetrics clusterMetrics = admin.getClusterMetrics(); + results.put("cluster_id", clusterMetrics.getClusterId()); + results.put("average_load", clusterMetrics.getAverageLoad()); + results.put("hbase_version", clusterMetrics.getHBaseVersion()); + results.put("region_count", clusterMetrics.getRegionCount()); + // Region servers info + Collection servers = admin.getRegionServers(); + results.put(NODES, servers.size()); + Map metrics = + clusterMetrics.getLiveServerMetrics(); + Map regionServers = InsertionOrderUtil.newMap(); + for (Map.Entry e : metrics.entrySet()) { + ServerName server = e.getKey(); + ServerMetrics serverMetrics = e.getValue(); + List regions = admin.getRegionMetrics(server); + regionServers.put(server.getAddress().toString(), + formatMetrics(serverMetrics, regions)); + } + results.put("region_servers", regionServers); + } catch (Throwable e) { + results.put(EXCEPTION, e.getMessage()); + } + return results; + } + + private static Map formatMetrics( + ServerMetrics serverMetrics, + List regions) { + Map metrics = InsertionOrderUtil.newMap(); + metrics.put("max_heap_size", + serverMetrics.getMaxHeapSize().get(Size.Unit.MEGABYTE)); + metrics.put("used_heap_size", + serverMetrics.getUsedHeapSize().get(Size.Unit.MEGABYTE)); + metrics.put("heap_size_unit", "MB"); + metrics.put("request_count", serverMetrics.getRequestCount()); + metrics.put("request_count_per_second", + serverMetrics.getRequestCountPerSecond()); + metrics.put("regions", formatMetrics(regions)); + return metrics; + } + + private static Map formatMetrics( + List regions) { + Map metrics = InsertionOrderUtil.newMap(); + for (RegionMetrics region : regions) { + metrics.put(region.getNameAsString(), formatMetrics(region)); + } + return metrics; + } + + private static Map formatMetrics(RegionMetrics region) { + Map metrics = InsertionOrderUtil.newMap(); + metrics.put("mem_store_size", + region.getMemStoreSize().get(Size.Unit.MEGABYTE)); + metrics.put("file_store_size", + region.getStoreFileSize().get(Size.Unit.MEGABYTE)); + metrics.put("store_size_unit", "MB"); + return metrics; + } +} diff --git a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseSessions.java b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseSessions.java index f9170fabf5..21be222322 100644 --- a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseSessions.java +++ b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseSessions.java @@ -85,6 +85,11 @@ public HbaseSessions(HugeConfig config, String namespace, String store) { this.namespace = namespace; } + protected Connection hbase() { + E.checkState(this.hbase != null, "HBase connection is not opened"); + return this.hbase; + } + private Table table(String table) throws IOException { E.checkState(this.hbase != null, "HBase connection is not opened"); TableName tableName = TableName.valueOf(this.namespace, table); diff --git a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStore.java b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStore.java index 19af25e279..64ce63daca 100644 --- a/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStore.java +++ b/hugegraph-hbase/src/main/java/com/baidu/hugegraph/backend/store/hbase/HbaseStore.java @@ -33,6 +33,7 @@ import org.apache.hadoop.hbase.NamespaceExistException; import org.apache.hadoop.hbase.TableExistsException; import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.client.Connection; import org.slf4j.Logger; import com.baidu.hugegraph.backend.BackendException; @@ -73,6 +74,16 @@ public HbaseStore(final BackendStoreProvider provider, this.namespace = namespace; this.store = store; this.sessions = null; + + this.registerMetaHandlers(); + LOG.debug("Store loaded: {}", store); + } + + private void registerMetaHandlers() { + this.registerMetaHandler("metrics", (session, meta, args) -> { + HbaseMetrics metrics = new HbaseMetrics(this.sessions); + return metrics.getMetrics(); + }); } protected void registerTableManager(HugeType type, HbaseTable table) { diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlMetrics.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlMetrics.java new file mode 100644 index 0000000000..eb58b21809 --- /dev/null +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlMetrics.java @@ -0,0 +1,33 @@ +/* + * 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.mysql; + +import java.util.Map; + +import com.baidu.hugegraph.backend.store.BackendMetrics; +import com.google.common.collect.ImmutableMap; + +public class MysqlMetrics implements BackendMetrics { + + @Override + public Map getMetrics() { + return ImmutableMap.of(NODES, 1); + } +} diff --git a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStore.java b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStore.java index a687664589..b9b1484e84 100644 --- a/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStore.java +++ b/hugegraph-mysql/src/main/java/com/baidu/hugegraph/backend/store/mysql/MysqlStore.java @@ -71,9 +71,17 @@ public MysqlStore(final BackendStoreProvider provider, this.sessions = null; this.tables = new ConcurrentHashMap<>(); + this.registerMetaHandlers(); LOG.debug("Store loaded: {}", store); } + private void registerMetaHandlers() { + this.registerMetaHandler("metrics", (session, meta, args) -> { + MysqlMetrics metrics = new MysqlMetrics(); + return metrics.getMetrics(); + }); + } + protected void registerTableManager(HugeType type, MysqlTable table) { this.tables.put(type, table); } diff --git a/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBMetrics.java b/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBMetrics.java index 8371a58252..bb5ec00a43 100644 --- a/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBMetrics.java +++ b/hugegraph-rocksdb/src/main/java/com/baidu/hugegraph/backend/store/rocksdb/RocksDBMetrics.java @@ -49,6 +49,7 @@ public RocksDBMetrics(List dbs, @Override public Map getMetrics() { Map metrics = InsertionOrderUtil.newMap(); + metrics.put(NODES, 1); // NOTE: the unit of rocksdb mem property is bytes metrics.put(MEM_USED, this.getMemUsed() / Bytes.MB); metrics.put(MEM_UNIT, "MB"); diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/MetricsApiTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/MetricsApiTest.java index f92fd95319..6aca2444b7 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/api/MetricsApiTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/api/MetricsApiTest.java @@ -62,17 +62,18 @@ public void testMetricsBackend() { Assert.assertTrue(value instanceof Map); Map graph = (Map) value; + assertMapContains(graph, "backend"); + assertMapContains(graph, "nodes"); String backend = (String) graph.get("backend"); - String notSupport = "Not support metadata 'metrics'"; + int nodes = (Integer) graph.get("nodes"); switch (backend) { case "memory": case "mysql": - case "hbase": case "postgresql": - String except = (String) assertMapContains(graph, "exception"); - Assert.assertTrue(except, except.contains(notSupport)); + Assert.assertEquals(1, nodes); break; case "rocksdb": + Assert.assertEquals(1, nodes); assertMapContains(graph, "mem_used"); assertMapContains(graph, "mem_unit"); assertMapContains(graph, "data_size"); @@ -82,7 +83,7 @@ public void testMetricsBackend() { for (Map.Entry e : graph.entrySet()) { String key = (String) e.getKey(); value = e.getValue(); - if ("backend".equals(key)) { + if ("backend".equals(key) || "nodes".equals(key)) { continue; } Assert.assertTrue(String.format( @@ -97,6 +98,30 @@ public void testMetricsBackend() { assertMapContains(host, "data_size"); } break; + case "hbase": + assertMapContains(graph, "cluster_id"); + assertMapContains(graph, "average_load"); + assertMapContains(graph, "hbase_version"); + assertMapContains(graph, "region_count"); + assertMapContains(graph, "region_servers"); + Map servers = (Map) graph.get("region_servers"); + for (Map.Entry e : servers.entrySet()) { + String key = (String) e.getKey(); + value = e.getValue(); + Assert.assertTrue(String.format( + "Expect map value for key %s but got %s", + key, value), + value instanceof Map); + Map regionServer = (Map) value; + assertMapContains(regionServer, "max_heap_size"); + assertMapContains(regionServer, "used_heap_size"); + assertMapContains(regionServer, "heap_size_unit"); + assertMapContains(regionServer, "request_count"); + assertMapContains(regionServer, + "request_count_per_second"); + assertMapContains(regionServer, "regions"); + } + break; default: Assert.assertTrue("Unexpected backend " + backend, false); break;