com.netflix.hystrix.HystrixThreadPoolMetrics Maven / Gradle / Ivy
Show all versions of hystrix-core Show documentation
/**
* Copyright 2012 Netflix, Inc.
*
* Licensed 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.netflix.hystrix;
import com.netflix.hystrix.metric.HystrixCommandCompletion;
import com.netflix.hystrix.metric.consumer.CumulativeThreadPoolEventCounterStream;
import com.netflix.hystrix.metric.consumer.RollingThreadPoolMaxConcurrencyStream;
import com.netflix.hystrix.metric.consumer.RollingThreadPoolEventCounterStream;
import com.netflix.hystrix.util.HystrixRollingNumberEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.functions.Func0;
import rx.functions.Func2;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Used by {@link HystrixThreadPool} to record metrics.
*/
public class HystrixThreadPoolMetrics extends HystrixMetrics {
private static final HystrixEventType[] ALL_COMMAND_EVENT_TYPES = HystrixEventType.values();
private static final HystrixEventType.ThreadPool[] ALL_THREADPOOL_EVENT_TYPES = HystrixEventType.ThreadPool.values();
private static final int NUMBER_THREADPOOL_EVENT_TYPES = ALL_THREADPOOL_EVENT_TYPES.length;
// String is HystrixThreadPoolKey.name() (we can't use HystrixThreadPoolKey directly as we can't guarantee it implements hashcode/equals correctly)
private static final ConcurrentHashMap metrics = new ConcurrentHashMap();
/**
* Get or create the {@link HystrixThreadPoolMetrics} instance for a given {@link HystrixThreadPoolKey}.
*
* This is thread-safe and ensures only 1 {@link HystrixThreadPoolMetrics} per {@link HystrixThreadPoolKey}.
*
* @param key
* {@link HystrixThreadPoolKey} of {@link HystrixThreadPool} instance requesting the {@link HystrixThreadPoolMetrics}
* @param threadPool
* Pass-thru of ThreadPoolExecutor to {@link HystrixThreadPoolMetrics} instance on first time when constructed
* @param properties
* Pass-thru to {@link HystrixThreadPoolMetrics} instance on first time when constructed
* @return {@link HystrixThreadPoolMetrics}
*/
public static HystrixThreadPoolMetrics getInstance(HystrixThreadPoolKey key, ThreadPoolExecutor threadPool, HystrixThreadPoolProperties properties) {
// attempt to retrieve from cache first
HystrixThreadPoolMetrics threadPoolMetrics = metrics.get(key.name());
if (threadPoolMetrics != null) {
return threadPoolMetrics;
} else {
synchronized (HystrixThreadPoolMetrics.class) {
HystrixThreadPoolMetrics existingMetrics = metrics.get(key.name());
if (existingMetrics != null) {
return existingMetrics;
} else {
HystrixThreadPoolMetrics newThreadPoolMetrics = new HystrixThreadPoolMetrics(key, threadPool, properties);
metrics.putIfAbsent(key.name(), newThreadPoolMetrics);
return newThreadPoolMetrics;
}
}
}
}
/**
* Get the {@link HystrixThreadPoolMetrics} instance for a given {@link HystrixThreadPoolKey} or null if one does not exist.
*
* @param key
* {@link HystrixThreadPoolKey} of {@link HystrixThreadPool} instance requesting the {@link HystrixThreadPoolMetrics}
* @return {@link HystrixThreadPoolMetrics}
*/
public static HystrixThreadPoolMetrics getInstance(HystrixThreadPoolKey key) {
return metrics.get(key.name());
}
/**
* All registered instances of {@link HystrixThreadPoolMetrics}
*
* @return {@code Collection}
*/
public static Collection getInstances() {
List threadPoolMetrics = new ArrayList();
for (HystrixThreadPoolMetrics tpm: metrics.values()) {
if (hasExecutedCommandsOnThread(tpm)) {
threadPoolMetrics.add(tpm);
}
}
return Collections.unmodifiableCollection(threadPoolMetrics);
}
private static boolean hasExecutedCommandsOnThread(HystrixThreadPoolMetrics threadPoolMetrics) {
return threadPoolMetrics.getCurrentCompletedTaskCount().intValue() > 0;
}
public static final Func2 appendEventToBucket
= new Func2() {
@Override
public long[] call(long[] initialCountArray, HystrixCommandCompletion execution) {
ExecutionResult.EventCounts eventCounts = execution.getEventCounts();
for (HystrixEventType eventType: ALL_COMMAND_EVENT_TYPES) {
long eventCount = eventCounts.getCount(eventType);
HystrixEventType.ThreadPool threadPoolEventType = HystrixEventType.ThreadPool.from(eventType);
if (threadPoolEventType != null) {
initialCountArray[threadPoolEventType.ordinal()] += eventCount;
}
}
return initialCountArray;
}
};
public static final Func2 counterAggregator = new Func2() {
@Override
public long[] call(long[] cumulativeEvents, long[] bucketEventCounts) {
for (int i = 0; i < NUMBER_THREADPOOL_EVENT_TYPES; i++) {
cumulativeEvents[i] += bucketEventCounts[i];
}
return cumulativeEvents;
}
};
/**
* Clears all state from metrics. If new requests come in instances will be recreated and metrics started from scratch.
*
*/
/* package */ static void reset() {
metrics.clear();
}
private final HystrixThreadPoolKey threadPoolKey;
private final ThreadPoolExecutor threadPool;
private final HystrixThreadPoolProperties properties;
private final AtomicInteger concurrentExecutionCount = new AtomicInteger();
private final RollingThreadPoolEventCounterStream rollingCounterStream;
private final CumulativeThreadPoolEventCounterStream cumulativeCounterStream;
private final RollingThreadPoolMaxConcurrencyStream rollingThreadPoolMaxConcurrencyStream;
private HystrixThreadPoolMetrics(HystrixThreadPoolKey threadPoolKey, ThreadPoolExecutor threadPool, HystrixThreadPoolProperties properties) {
super(null);
this.threadPoolKey = threadPoolKey;
this.threadPool = threadPool;
this.properties = properties;
rollingCounterStream = RollingThreadPoolEventCounterStream.getInstance(threadPoolKey, properties);
cumulativeCounterStream = CumulativeThreadPoolEventCounterStream.getInstance(threadPoolKey, properties);
rollingThreadPoolMaxConcurrencyStream = RollingThreadPoolMaxConcurrencyStream.getInstance(threadPoolKey, properties);
}
/**
* {@link ThreadPoolExecutor} this executor represents.
*
* @return ThreadPoolExecutor
*/
public ThreadPoolExecutor getThreadPool() {
return threadPool;
}
/**
* {@link HystrixThreadPoolKey} these metrics represent.
*
* @return HystrixThreadPoolKey
*/
public HystrixThreadPoolKey getThreadPoolKey() {
return threadPoolKey;
}
/**
* {@link HystrixThreadPoolProperties} of the {@link HystrixThreadPool} these metrics represent.
*
* @return HystrixThreadPoolProperties
*/
public HystrixThreadPoolProperties getProperties() {
return properties;
}
/**
* Value from {@link ThreadPoolExecutor#getActiveCount()}
*
* @return Number
*/
public Number getCurrentActiveCount() {
return threadPool.getActiveCount();
}
/**
* Value from {@link ThreadPoolExecutor#getCompletedTaskCount()}
*
* @return Number
*/
public Number getCurrentCompletedTaskCount() {
return threadPool.getCompletedTaskCount();
}
/**
* Value from {@link ThreadPoolExecutor#getCorePoolSize()}
*
* @return Number
*/
public Number getCurrentCorePoolSize() {
return threadPool.getCorePoolSize();
}
/**
* Value from {@link ThreadPoolExecutor#getLargestPoolSize()}
*
* @return Number
*/
public Number getCurrentLargestPoolSize() {
return threadPool.getLargestPoolSize();
}
/**
* Value from {@link ThreadPoolExecutor#getMaximumPoolSize()}
*
* @return Number
*/
public Number getCurrentMaximumPoolSize() {
return threadPool.getMaximumPoolSize();
}
/**
* Value from {@link ThreadPoolExecutor#getPoolSize()}
*
* @return Number
*/
public Number getCurrentPoolSize() {
return threadPool.getPoolSize();
}
/**
* Value from {@link ThreadPoolExecutor#getTaskCount()}
*
* @return Number
*/
public Number getCurrentTaskCount() {
return threadPool.getTaskCount();
}
/**
* Current size of {@link BlockingQueue} used by the thread-pool
*
* @return Number
*/
public Number getCurrentQueueSize() {
return threadPool.getQueue().size();
}
/**
* Invoked each time a thread is executed.
*/
public void markThreadExecution() {
concurrentExecutionCount.incrementAndGet();
}
/**
* Rolling count of number of threads executed during rolling statistical window.
*
* The rolling window is defined by {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}.
*
* @return rolling count of threads executed
*/
public long getRollingCountThreadsExecuted() {
return rollingCounterStream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED);
}
/**
* Cumulative count of number of threads executed since the start of the application.
*
* @return cumulative count of threads executed
*/
public long getCumulativeCountThreadsExecuted() {
return cumulativeCounterStream.getLatestCount(HystrixEventType.ThreadPool.EXECUTED);
}
/**
* Rolling count of number of threads rejected during rolling statistical window.
*
* The rolling window is defined by {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}.
*
* @return rolling count of threads rejected
*/
public long getRollingCountThreadsRejected() {
return rollingCounterStream.getLatestCount(HystrixEventType.ThreadPool.REJECTED);
}
/**
* Cumulative count of number of threads rejected since the start of the application.
*
* @return cumulative count of threads rejected
*/
public long getCumulativeCountThreadsRejected() {
return cumulativeCounterStream.getLatestCount(HystrixEventType.ThreadPool.REJECTED);
}
public long getRollingCount(HystrixEventType.ThreadPool event) {
return rollingCounterStream.getLatestCount(event);
}
public long getCumulativeCount(HystrixEventType.ThreadPool event) {
return cumulativeCounterStream.getLatestCount(event);
}
@Override
public long getCumulativeCount(HystrixRollingNumberEvent event) {
return cumulativeCounterStream.getLatestCount(HystrixEventType.ThreadPool.from(event));
}
@Override
public long getRollingCount(HystrixRollingNumberEvent event) {
return rollingCounterStream.getLatestCount(HystrixEventType.ThreadPool.from(event));
}
/**
* Invoked each time a thread completes.
*/
public void markThreadCompletion() {
concurrentExecutionCount.decrementAndGet();
}
/**
* Rolling max number of active threads during rolling statistical window.
*
* The rolling window is defined by {@link HystrixThreadPoolProperties#metricsRollingStatisticalWindowInMilliseconds()}.
*
* @return rolling max active threads
*/
public long getRollingMaxActiveThreads() {
return rollingThreadPoolMaxConcurrencyStream.getLatestRollingMax();
}
/**
* Invoked each time a command is rejected from the thread-pool
*/
public void markThreadRejection() {
concurrentExecutionCount.decrementAndGet();
}
public static Func0 getCurrentConcurrencyThunk(final HystrixThreadPoolKey threadPoolKey) {
return new Func0() {
@Override
public Integer call() {
return HystrixThreadPoolMetrics.getInstance(threadPoolKey).concurrentExecutionCount.get();
}
};
}
}