com.wavefront.agent.queueing.TaskSizeEstimator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proxy Show documentation
Show all versions of proxy Show documentation
Service for batching and relaying metric traffic to Wavefront
package com.wavefront.agent.queueing;
import com.google.common.util.concurrent.RateLimiter;
import com.wavefront.agent.SharedMetricsRegistry;
import com.wavefront.agent.data.DataSubmissionTask;
import com.wavefront.common.NamedThreadFactory;
import com.wavefront.common.TaggedMetricName;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Gauge;
import com.yammer.metrics.core.Histogram;
import com.yammer.metrics.core.Meter;
import com.yammer.metrics.core.MetricsRegistry;
import java.io.ByteArrayOutputStream;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
/**
* Calculates approximate task sizes to estimate how quickly we would run out of disk space if we
* are no longer able to send data to the server endpoint (i.e. network outage).
*
* @author [email protected].
*/
public class TaskSizeEstimator {
private static final MetricsRegistry REGISTRY = SharedMetricsRegistry.getInstance();
/**
* Biases result sizes to the last 5 minutes heavily. This histogram does not see all result
* sizes. The executor only ever processes one posting at any given time and drops the rest.
* {@link #resultPostingMeter} records the actual rate (i.e. sees all posting calls).
*/
private final Histogram resultPostingSizes;
private final Meter resultPostingMeter;
/** A single threaded bounded work queue to update result posting sizes. */
private final ExecutorService resultPostingSizerExecutorService;
@SuppressWarnings("rawtypes")
private final TaskConverter taskConverter;
/** Only size postings once every 5 seconds. */
@SuppressWarnings("UnstableApiUsage")
private final RateLimiter resultSizingRateLimier = RateLimiter.create(0.2);
/** @param handle metric pipeline handle (usually port number). */
public TaskSizeEstimator(String handle) {
this.resultPostingSizes =
REGISTRY.newHistogram(
new TaggedMetricName("post-result", "result-size", "port", handle), true);
this.resultPostingMeter =
REGISTRY.newMeter(
new TaggedMetricName("post-result", "results", "port", handle),
"results",
TimeUnit.MINUTES);
this.resultPostingSizerExecutorService =
new ThreadPoolExecutor(
1,
1,
60L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1),
new NamedThreadFactory("result-posting-sizer-" + handle));
// for now, we can just use a generic task converter with default lz4 compression method
this.taskConverter = new RetryTaskConverter<>(handle, TaskConverter.CompressionType.LZ4);
Metrics.newGauge(
new TaggedMetricName("buffer", "fill-rate", "port", handle),
new Gauge() {
@Override
public Long value() {
return getBytesPerMinute();
}
});
}
/**
* Submit a candidate task to be sized. The task may or may not be accepted, depending on the rate
* limiter
*
* @param task task to be sized.
*/
public > void scheduleTaskForSizing(T task) {
resultPostingMeter.mark();
try {
//noinspection UnstableApiUsage
if (resultSizingRateLimier.tryAcquire()) {
resultPostingSizerExecutorService.submit(getPostingSizerTask(task));
}
} catch (Exception ex) {
// ignored.
}
}
/**
* Calculates the bytes per minute buffer usage rate. Needs at
*
* @return bytes per minute for requests submissions. Null if no data is available yet (needs at
* least
*/
@Nullable
public Long getBytesPerMinute() {
if (resultPostingSizes.count() < 50) return null;
if (resultPostingMeter.fifteenMinuteRate() == 0 || resultPostingSizes.mean() == 0) return null;
return (long) (resultPostingSizes.mean() * resultPostingMeter.fifteenMinuteRate());
}
public void shutdown() {
resultPostingSizerExecutorService.shutdown();
}
private > Runnable getPostingSizerTask(final T task) {
return () -> {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
taskConverter.serializeToStream(task, outputStream);
resultPostingSizes.update(outputStream.size());
} catch (Throwable t) {
// ignored. this is a stats task.
}
};
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy