use of io.confluent.ksql.rest.util.ConcurrencyLimiter.Decrementer in project ksql by confluentinc.
the class QueryMetricsUtil method initializePullStreamMetricsCallback.
public static MetricsCallback initializePullStreamMetricsCallback(final Optional<PullQueryExecutorMetrics> pullQueryMetrics, final SlidingWindowRateLimiter pullBandRateLimiter, final ImmutableAnalysis analysis, final AtomicReference<StreamPullQueryMetadata> resultForMetrics, final AtomicReference<Decrementer> refDecrementer) {
final MetricsCallback metricsCallback = (statusCode, requestBytes, responseBytes, startTimeNanos) -> pullQueryMetrics.ifPresent(metrics -> {
metrics.recordStatusCode(statusCode);
metrics.recordRequestSize(requestBytes);
final StreamPullQueryMetadata m = resultForMetrics.get();
final KafkaStreams.State state = m == null ? null : m.getTransientQueryMetadata().getKafkaStreams().state();
if (m == null || state == null || state.equals(State.ERROR) || state.equals(State.PENDING_ERROR)) {
recordErrorMetrics(pullQueryMetrics, responseBytes, startTimeNanos);
} else {
final boolean isWindowed = analysis.getFrom().getDataSource().getKsqlTopic().getKeyFormat().isWindowed();
final QuerySourceType sourceType = isWindowed ? QuerySourceType.WINDOWED_STREAM : QuerySourceType.NON_WINDOWED_STREAM;
// There is no WHERE clause constraint information in the persistent logical plan
final PullPhysicalPlanType planType = PullPhysicalPlanType.UNKNOWN;
final RoutingNodeType routingNodeType = RoutingNodeType.SOURCE_NODE;
metrics.recordResponseSize(responseBytes, sourceType, planType, routingNodeType);
metrics.recordLatency(startTimeNanos, sourceType, planType, routingNodeType);
final TransientQueryQueue rowQueue = (TransientQueryQueue) m.getTransientQueryMetadata().getRowQueue();
// The rows read from the underlying data source equal the rows read by the user
// since the WHERE condition is pushed to the data source
metrics.recordRowsReturned(rowQueue.getTotalRowsQueued(), sourceType, planType, routingNodeType);
metrics.recordRowsProcessed(rowQueue.getTotalRowsQueued(), sourceType, planType, routingNodeType);
}
pullBandRateLimiter.add(responseBytes);
// Decrement on happy or exception path
final Decrementer decrementer = refDecrementer.get();
if (decrementer != null) {
decrementer.decrementAtMostOnce();
}
});
return metricsCallback;
}
use of io.confluent.ksql.rest.util.ConcurrencyLimiter.Decrementer in project ksql by confluentinc.
the class ConcurrencyLimiterTest method shouldSucceedUnderLimit.
@Test
public void shouldSucceedUnderLimit() {
final Metrics metrics = new Metrics();
final Map<String, String> tags = Collections.emptyMap();
ConcurrencyLimiter limiter = new ConcurrencyLimiter(1, "pull", metrics, tags);
assertThat(getReject(metrics, tags), is(0.0));
assertThat(getRemaining(metrics, tags), is(1.0));
Decrementer decrementer = limiter.increment();
assertThat(limiter.getCount(), is(1));
assertThat(getReject(metrics, tags), is(0.0));
assertThat(getRemaining(metrics, tags), is(0.0));
decrementer.decrementAtMostOnce();
decrementer.decrementAtMostOnce();
assertThat(limiter.getCount(), is(0));
assertThat(getReject(metrics, tags), is(0.0));
assertThat(getRemaining(metrics, tags), is(1.0));
}
use of io.confluent.ksql.rest.util.ConcurrencyLimiter.Decrementer in project ksql by confluentinc.
the class ConcurrencyLimiterTest method shouldError_atLimit.
@Test
public void shouldError_atLimit() {
final Metrics metrics = new Metrics();
final Map<String, String> tags = Collections.emptyMap();
ConcurrencyLimiter limiter = new ConcurrencyLimiter(1, "pull", metrics, tags);
assertThat(getReject(metrics, tags), is(0.0));
assertThat(getRemaining(metrics, tags), is(1.0));
Decrementer decrementer = limiter.increment();
assertThat(getReject(metrics, tags), is(0.0));
assertThat(getRemaining(metrics, tags), is(0.0));
final Exception e = assertThrows(KsqlException.class, limiter::increment);
assertThat(e.getMessage(), containsString("Host is at concurrency limit for pull queries."));
assertThat(limiter.getCount(), is(1));
assertThat(getReject(metrics, tags), is(1.0));
assertThat(getRemaining(metrics, tags), is(0.0));
decrementer.decrementAtMostOnce();
assertThat(limiter.getCount(), is(0));
assertThat(getReject(metrics, tags), is(1.0));
assertThat(getRemaining(metrics, tags), is(1.0));
}
use of io.confluent.ksql.rest.util.ConcurrencyLimiter.Decrementer in project ksql by confluentinc.
the class QueryExecutor method handleTablePullQuery.
private QueryMetadataHolder handleTablePullQuery(final ImmutableAnalysis analysis, final ServiceContext serviceContext, final ConfiguredStatement<Query> configured, final Map<String, Object> requestProperties, final Optional<Boolean> isInternalRequest, final SlidingWindowRateLimiter pullBandRateLimiter, final AtomicReference<PullQueryResult> resultForMetrics, final Optional<ConsistencyOffsetVector> consistencyOffsetVector) {
final RoutingOptions routingOptions = new PullQueryConfigRoutingOptions(configured.getSessionConfig().getConfig(false), configured.getSessionConfig().getOverrides(), requestProperties);
final PullQueryConfigPlannerOptions plannerOptions = new PullQueryConfigPlannerOptions(configured.getSessionConfig().getConfig(false), configured.getSessionConfig().getOverrides());
// A request is considered forwarded if the request has the forwarded flag or if the request
// is from an internal listener.
final boolean isAlreadyForwarded = routingOptions.getIsSkipForwardRequest() && // Trust the forward request option if isInternalRequest isn't available.
isInternalRequest.orElse(true);
// Only check the rate limit at the forwarding host
Decrementer decrementer = null;
try {
if (!isAlreadyForwarded) {
rateLimiter.checkLimit();
decrementer = concurrencyLimiter.increment();
}
pullBandRateLimiter.allow(KsqlQueryType.PULL);
final Optional<Decrementer> optionalDecrementer = Optional.ofNullable(decrementer);
final PullQueryResult result = ksqlEngine.executeTablePullQuery(analysis, serviceContext, configured, routing, routingOptions, plannerOptions, pullQueryMetrics, false, consistencyOffsetVector);
resultForMetrics.set(result);
result.onCompletionOrException((v, t) -> optionalDecrementer.ifPresent(Decrementer::decrementAtMostOnce));
return QueryMetadataHolder.of(result);
} catch (final Throwable t) {
if (decrementer != null) {
decrementer.decrementAtMostOnce();
}
throw t;
}
}
Aggregations