-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-27466: Making metrics instance containing one or more connections. #4874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
9a525b7
7bbfc81
c39aec2
9a7d4fa
ed9b1e3
b51866c
3eb93dc
9bbfe2e
3abc7ab
e12e75e
77652cc
298ece2
b9234b3
80f135a
c28a248
be2d559
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,10 @@ | |
| import com.codahale.metrics.MetricRegistry; | ||
| import com.codahale.metrics.RatioGauge; | ||
| import com.codahale.metrics.Timer; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.ConcurrentMap; | ||
| import java.util.concurrent.ConcurrentSkipListMap; | ||
|
|
@@ -54,6 +58,38 @@ | |
| @InterfaceAudience.Private | ||
| public class MetricsConnection implements StatisticTrackable { | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
|
|
||
| static final Map<String, MetricsConnection> METRICS_INSTANCES = | ||
| new HashMap<String, MetricsConnection>(); | ||
|
|
||
| static MetricsConnection getMetricsConnection(final AsyncConnection conn, | ||
| Supplier<ThreadPoolExecutor> batchPool, Supplier<ThreadPoolExecutor> metaPool) { | ||
| String scope = getScope(conn); | ||
| MetricsConnection metrics; | ||
| synchronized (METRICS_INSTANCES) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider a synchronized or concurrent map type instead.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure if a synchronized or concurrent map can protect the entire block, I want this entire block to run in single thread mode. Especially in the deletion method below, the decrementing count, getting count, and remove it from the map have to be single threaded. @apurtell @d-c-manning
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The scope here should be unique per async connection object, is that correct?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the scope that you meant here is the scope of this code block, it is per async connection object, and the single metrics object which might be shared among multiple async connection objects. Please refer the comment in the deleteMetricsConnection() code block, too. |
||
| metrics = METRICS_INSTANCES.get(scope); | ||
| if (metrics == null) { | ||
| metrics = new MetricsConnection(scope, batchPool, metaPool); | ||
| METRICS_INSTANCES.put(scope, metrics); | ||
| } else { | ||
| metrics.addThreadPools(batchPool, metaPool); | ||
| } | ||
| metrics.incrConnectionCount(); | ||
| } | ||
| return metrics; | ||
| } | ||
|
|
||
| static void deleteMetricsConnection(final AsyncConnection conn) { | ||
| String scope = getScope(conn); | ||
| synchronized (METRICS_INSTANCES) { | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
| MetricsConnection metrics = METRICS_INSTANCES.get(scope); | ||
| metrics.decrConnectionCount(); | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
| if (metrics.getConnectionCount() == 0) { | ||
| METRICS_INSTANCES.remove(scope); | ||
| metrics.shutdown(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** Set this key to {@code true} to enable metrics collection of client requests. */ | ||
| public static final String CLIENT_SIDE_METRICS_ENABLED_KEY = "hbase.client.metrics.enable"; | ||
|
|
||
|
|
@@ -78,9 +114,15 @@ public class MetricsConnection implements StatisticTrackable { | |
| * @param connectionObj either a Connection or AsyncConnectionImpl, the instance creating this | ||
| * MetricsConnection. | ||
| */ | ||
| static String getScope(Configuration conf, String clusterId, Object connectionObj) { | ||
| return conf.get(METRICS_SCOPE_KEY, | ||
| clusterId + "@" + Integer.toHexString(connectionObj.hashCode())); | ||
| private static String getScope(final AsyncConnection conn) { | ||
| String identity = conn.getIdentity(); | ||
| if (identity != null) { | ||
| return identity; | ||
| } | ||
| Configuration conf = conn.getConfiguration(); | ||
| String clusterId = conn.getClusterId2(); | ||
| int connHashCode = conn.hashCode(); | ||
| return conf.get(METRICS_SCOPE_KEY, clusterId + "@" + Integer.toHexString(connHashCode)); | ||
| } | ||
|
|
||
| private static final String CNT_BASE = "rpcCount_"; | ||
|
|
@@ -295,8 +337,13 @@ public Counter newMetric(Class<?> clazz, String name, String scope) { | |
| } | ||
| }; | ||
|
|
||
| // List of thread pool per connection of the metrics. | ||
| private List batchPools = new ArrayList<Supplier>(); | ||
| private List metaPools = new ArrayList<Supplier>(); | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
|
|
||
| // static metrics | ||
|
|
||
| protected final Counter connectionCount; | ||
| protected final Counter metaCacheHits; | ||
| protected final Counter metaCacheMisses; | ||
| protected final CallTracker getTracker; | ||
|
|
@@ -334,27 +381,48 @@ public Counter newMetric(Class<?> clazz, String name, String scope) { | |
| MetricsConnection(String scope, Supplier<ThreadPoolExecutor> batchPool, | ||
| Supplier<ThreadPoolExecutor> metaPool) { | ||
| this.scope = scope; | ||
| this.batchPools.add(batchPool); | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
| this.metaPools.add(metaPool); | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
| this.registry = new MetricRegistry(); | ||
| this.registry.register(getExecutorPoolName(), new RatioGauge() { | ||
| @Override | ||
| protected Ratio getRatio() { | ||
| ThreadPoolExecutor pool = batchPool.get(); | ||
| if (pool == null) { | ||
| return Ratio.of(0, 0); | ||
| int numerator = 0; | ||
|
vli02 marked this conversation as resolved.
|
||
| int denominator = 0; | ||
| for (int i = 0; i < batchPools.size(); i++) { | ||
| ThreadPoolExecutor pool = (ThreadPoolExecutor) ((Supplier) batchPools.get(i)).get(); | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
| if (pool != null) { | ||
| int activeCount = pool.getActiveCount(); | ||
| int maxPoolSize = pool.getMaximumPoolSize(); | ||
| if (numerator == 0 || (numerator * maxPoolSize) < (activeCount * denominator)) { | ||
| numerator = activeCount; | ||
| denominator = maxPoolSize; | ||
| } | ||
|
vli02 marked this conversation as resolved.
|
||
| } | ||
| } | ||
| return Ratio.of(pool.getActiveCount(), pool.getMaximumPoolSize()); | ||
| return Ratio.of(numerator, denominator); | ||
| } | ||
| }); | ||
| this.registry.register(getMetaPoolName(), new RatioGauge() { | ||
| @Override | ||
| protected Ratio getRatio() { | ||
| ThreadPoolExecutor pool = metaPool.get(); | ||
| if (pool == null) { | ||
| return Ratio.of(0, 0); | ||
| int numerator = 0; | ||
| int denominator = 0; | ||
| for (int i = 0; i < metaPools.size(); i++) { | ||
| ThreadPoolExecutor pool = (ThreadPoolExecutor) ((Supplier) metaPools.get(i)).get(); | ||
| if (pool != null) { | ||
| int activeCount = pool.getActiveCount(); | ||
| int maxPoolSize = pool.getMaximumPoolSize(); | ||
| if (numerator == 0 || (numerator * maxPoolSize) < (activeCount * denominator)) { | ||
| numerator = activeCount; | ||
| denominator = maxPoolSize; | ||
| } | ||
| } | ||
| } | ||
| return Ratio.of(pool.getActiveCount(), pool.getMaximumPoolSize()); | ||
| return Ratio.of(numerator, denominator); | ||
| } | ||
| }); | ||
| this.connectionCount = registry.counter(name(this.getClass(), "connectionCount", scope)); | ||
| this.metaCacheHits = registry.counter(name(this.getClass(), "metaCacheHits", scope)); | ||
| this.metaCacheMisses = registry.counter(name(this.getClass(), "metaCacheMisses", scope)); | ||
| this.metaCacheNumClearServer = | ||
|
|
@@ -457,6 +525,27 @@ public void incrementServerOverloadedBackoffTime(long time, TimeUnit timeUnit) { | |
| overloadedBackoffTimer.update(time, timeUnit); | ||
| } | ||
|
|
||
| /** Return the connection count of the metrics within a scope */ | ||
| private long getConnectionCount() { | ||
| return connectionCount.getCount(); | ||
|
vli02 marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /** Increment the connection count of the metrics within a scope */ | ||
| private void incrConnectionCount() { | ||
| connectionCount.inc(); | ||
| } | ||
|
|
||
| /** Decrement the connection count of the metrics within a scope */ | ||
| private void decrConnectionCount() { | ||
| connectionCount.dec(); | ||
| } | ||
|
|
||
| /** Add thread pools of additional connections to the metrics */ | ||
| private void addThreadPools(Supplier batchPool, Supplier metaPool) { | ||
|
vli02 marked this conversation as resolved.
Outdated
|
||
| batchPools.add(batchPool); | ||
| metaPools.add(metaPool); | ||
| } | ||
|
|
||
| /** | ||
| * Get a metric for {@code key} from {@code map}, or create it with {@code factory}. | ||
| */ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.