-
Notifications
You must be signed in to change notification settings - Fork 3.8k
minor: Add logs and metrics observability to the segment upgrade path that fires while using concurrent locking #19651
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
base: master
Are you sure you want to change the base?
Changes from all commits
58381a5
d82041f
1999407
b2c75e2
dbe7b65
1a83b18
03c48a2
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 |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /* | ||
| * 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 org.apache.druid.indexing.common; | ||
|
|
||
| import org.apache.druid.java.util.emitter.service.ServiceMetricEvent; | ||
| import org.apache.druid.metadata.PendingSegmentRecord; | ||
| import org.apache.druid.query.DruidMetrics; | ||
| import org.apache.druid.segment.realtime.appenderator.SegmentIdWithShardSpec; | ||
|
|
||
| /** | ||
| * Metric names and dimension values for the re-announcement of pending segments upgraded by a concurrent REPLACE. | ||
| * <ul> | ||
| * <li>the task action emits {@link #COUNT} (how many upgrades a commit produced),</li> | ||
| * <li>the supervisor emits {@link #NOTIFIED}, {@link #UNMATCHED} and {@link #SEND_FAILED} as it fans requests out,</li> | ||
| * <li>the streaming task emits {@link #ANNOUNCED} and {@link #SKIPPED} (with a {@code reason}) as it applies them.</li> | ||
| * </ul> | ||
| * Two reconciliations bound the visibility gap: | ||
| * <ul> | ||
| * <li>per segment, {@link #UNMATCHED} counts upgrades that reached no running task (delayed until handoff);</li> | ||
| * <li>per task, {@link #NOTIFIED} should equal {@link #ANNOUNCED} + {@link #SKIPPED} + {@link #SEND_FAILED}, | ||
| * since every notified task either announces, skips, or fails to receive the request. A shortfall means a | ||
| * notification was silently dropped.</li> | ||
| * </ul> | ||
| */ | ||
| public class SegmentUpgradeMetrics | ||
| { | ||
| /** Number of upgraded pending segments a REPLACE commit created and handed to the supervisor. Task-action dims. */ | ||
| public static final String COUNT = "ingest/realtime/segmentUpgrade/count"; | ||
|
|
||
| /** A notification was sent to a running task (once per task). Supervisor dims plus {@code taskId}. */ | ||
| public static final String NOTIFIED = "ingest/realtime/segmentUpgrade/notified"; | ||
|
|
||
| /** A record matched no running task and will not be re-announced until handoff. Supervisor dims. */ | ||
| public static final String UNMATCHED = "ingest/realtime/segmentUpgrade/unmatched"; | ||
|
|
||
| /** An upgrade request failed to reach a task over the wire. Supervisor dims plus {@code taskId}. */ | ||
| public static final String SEND_FAILED = "ingest/realtime/segmentUpgrade/sendFailed"; | ||
|
|
||
| /** A task announced an upgraded segment under the new version. Task dims. */ | ||
| public static final String ANNOUNCED = "ingest/realtime/segmentUpgrade/announced"; | ||
|
|
||
| /** | ||
| * A task received an upgrade request but did not announce it. The {@code reason} dimension carries | ||
| * {@link org.apache.druid.segment.realtime.appenderator.StreamAppenderator.PendingSegmentUpgradeResult#getReason()}. | ||
| * Task dims. | ||
| */ | ||
| public static final String SKIPPED = "ingest/realtime/segmentUpgrade/skipped"; | ||
|
|
||
| /** | ||
| * Adds the upgraded pending segment's {@code interval} and {@code version} to a metric builder so that every | ||
| * segment-upgrade metric can be sliced by the specific segment being re-announced. Mirrors | ||
| * {@code IndexTaskUtils.setSegmentDimensions}, which serves the same purpose for {@code DataSegment}s. | ||
| */ | ||
| public static ServiceMetricEvent.Builder setSegmentDimensions( | ||
|
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. Nit: Maybe move this method to |
||
| ServiceMetricEvent.Builder metricBuilder, | ||
| PendingSegmentRecord pendingSegmentRecord | ||
| ) | ||
| { | ||
| final SegmentIdWithShardSpec id = pendingSegmentRecord.getId(); | ||
| return metricBuilder | ||
| .setDimension(DruidMetrics.INTERVAL, id.getInterval().toString()) | ||
| .setDimension(DruidMetrics.VERSION, id.getVersion()); | ||
| } | ||
|
|
||
| private SegmentUpgradeMetrics() | ||
| { | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,20 +24,24 @@ | |||||||||||||||||||||||||||
| import com.fasterxml.jackson.core.type.TypeReference; | ||||||||||||||||||||||||||||
| import com.google.common.base.Optional; | ||||||||||||||||||||||||||||
| import com.google.common.collect.ImmutableSet; | ||||||||||||||||||||||||||||
| import org.apache.druid.indexing.common.SegmentUpgradeMetrics; | ||||||||||||||||||||||||||||
| import org.apache.druid.indexing.common.task.IndexTaskUtils; | ||||||||||||||||||||||||||||
| import org.apache.druid.indexing.common.task.Task; | ||||||||||||||||||||||||||||
| import org.apache.druid.indexing.overlord.CriticalAction; | ||||||||||||||||||||||||||||
| import org.apache.druid.indexing.overlord.SegmentPublishResult; | ||||||||||||||||||||||||||||
| import org.apache.druid.indexing.overlord.supervisor.SupervisorManager; | ||||||||||||||||||||||||||||
| import org.apache.druid.java.util.common.logger.Logger; | ||||||||||||||||||||||||||||
| import org.apache.druid.java.util.emitter.service.ServiceMetricEvent; | ||||||||||||||||||||||||||||
| import org.apache.druid.metadata.PendingSegmentRecord; | ||||||||||||||||||||||||||||
| import org.apache.druid.metadata.ReplaceTaskLock; | ||||||||||||||||||||||||||||
| import org.apache.druid.segment.SegmentSchemaMapping; | ||||||||||||||||||||||||||||
| import org.apache.druid.segment.SegmentUtils; | ||||||||||||||||||||||||||||
| import org.apache.druid.timeline.DataSegment; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| import javax.annotation.Nullable; | ||||||||||||||||||||||||||||
| import java.util.LinkedHashMap; | ||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||||||||
| import java.util.Set; | ||||||||||||||||||||||||||||
| import java.util.stream.Collectors; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
@@ -169,19 +173,45 @@ private void registerUpgradedPendingSegmentsOnSupervisor( | |||||||||||||||||||||||||||
| List<PendingSegmentRecord> upgradedPendingSegments | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||
| // Emit one count per upgraded segment (rather than a single aggregate) regardless of whether a supervisor exists | ||||||||||||||||||||||||||||
| // to receive them, so the total can be compared against the count actually announced by tasks and so each event | ||||||||||||||||||||||||||||
| // carries the segment's interval and version. | ||||||||||||||||||||||||||||
| for (PendingSegmentRecord upgradedPendingSegment : upgradedPendingSegments) { | ||||||||||||||||||||||||||||
| final ServiceMetricEvent.Builder metricBuilder = new ServiceMetricEvent.Builder(); | ||||||||||||||||||||||||||||
| IndexTaskUtils.setTaskDimensions(metricBuilder, task); | ||||||||||||||||||||||||||||
| SegmentUpgradeMetrics.setSegmentDimensions(metricBuilder, upgradedPendingSegment); | ||||||||||||||||||||||||||||
| toolbox.getEmitter().emit(metricBuilder.setMetric(SegmentUpgradeMetrics.COUNT, 1)); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| final SupervisorManager supervisorManager = toolbox.getSupervisorManager(); | ||||||||||||||||||||||||||||
| final Optional<String> activeSupervisorIdWithAppendLock = | ||||||||||||||||||||||||||||
| supervisorManager.getActiveSupervisorIdForDatasourceWithAppendLock(task.getDataSource()); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (!activeSupervisorIdWithAppendLock.isPresent()) { | ||||||||||||||||||||||||||||
| log.info("No active streaming supervisor for datasource[%s]; the [%d] upgraded pending segment(s) from task[%s]" | ||||||||||||||||||||||||||||
| + " will become queryable when their tasks hand off.", | ||||||||||||||||||||||||||||
| task.getDataSource(), | ||||||||||||||||||||||||||||
| upgradedPendingSegments.size(), | ||||||||||||||||||||||||||||
| task.getId() | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
|
Comment on lines
+191
to
+196
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. minor rephrase
Suggested change
|
||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| upgradedPendingSegments.forEach( | ||||||||||||||||||||||||||||
| upgradedPendingSegment -> supervisorManager.registerUpgradedPendingSegmentOnSupervisor( | ||||||||||||||||||||||||||||
| activeSupervisorIdWithAppendLock.get(), | ||||||||||||||||||||||||||||
| upgradedPendingSegment | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| // Register each upgraded pending segment on the supervisor and summarize the whole batch in one log line, | ||||||||||||||||||||||||||||
| // mapping each segment to the number of running tasks the supervisor notified. | ||||||||||||||||||||||||||||
| final Map<String, Integer> notifiedTasksBySegment = new LinkedHashMap<>(); | ||||||||||||||||||||||||||||
| for (PendingSegmentRecord upgradedPendingSegment : upgradedPendingSegments) { | ||||||||||||||||||||||||||||
| supervisorManager | ||||||||||||||||||||||||||||
| .registerUpgradedPendingSegmentOnSupervisor(activeSupervisorIdWithAppendLock.get(), upgradedPendingSegment) | ||||||||||||||||||||||||||||
| .ifPresent(notified -> notifiedTasksBySegment.put(upgradedPendingSegment.getId().toString(), notified)); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| log.info( | ||||||||||||||||||||||||||||
| "Registered [%d] upgraded pending segment(s) created by task[%s] on supervisor[%s]; tasks notified per" | ||||||||||||||||||||||||||||
| + " segment[%s].", | ||||||||||||||||||||||||||||
| notifiedTasksBySegment.size(), | ||||||||||||||||||||||||||||
| task.getId(), | ||||||||||||||||||||||||||||
| activeSupervisorIdWithAppendLock.get(), | ||||||||||||||||||||||||||||
| notifiedTasksBySegment | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably rename this metric from
counttopersistedto signify that this is the count that was actually persisted to the metadata store.Also, rephrased the text a bit.