KAFKA-9840: Skip End Offset validation when the leader epoch is not reliable#8486
Conversation
0910d36 to
22d7e20
Compare
There was a problem hiding this comment.
Move the function closer to its caller.
There was a problem hiding this comment.
Change one: immediately complete the validation when the leader epoch is not reliable.
There was a problem hiding this comment.
Could you not move the function while changing it so that the diff is easier to check -- e.g. here I'd have to blindly trust you that there are only changes of this func :)
There was a problem hiding this comment.
Change two: do not complete the validation as the returned epoch or offset is invalid.
There was a problem hiding this comment.
Change the function signature to be able to pass in response version.
There was a problem hiding this comment.
Added test coverage L203 and L214, other changes are just side cleanups and signature refactoring in this file.
guozhangwang
left a comment
There was a problem hiding this comment.
Made a pass over non-testing part. I'd suggest we revert the function movement so that it helps with more clear reviews.
There was a problem hiding this comment.
Could you not move the function while changing it so that the diff is easier to check -- e.g. here I'd have to blindly trust you that there are only changes of this func :)
| offsetsResult.endOffsets().forEach((respTopicPartition, respEndOffset) -> { | ||
| if (respEndOffset.hasUndefinedEpochOrOffset()) { | ||
| // Should attempt to find the new leader in the next try. | ||
| log.debug("Requesting metadata update for partition {} due to undefined epoch or offset {}", |
There was a problem hiding this comment.
nit: ... or offset {} from OffsetsForLeaderEpoch response
| } | ||
|
|
||
| public boolean hasUndefinedEpochOrOffset() { | ||
| return this.endOffset == UNDEFINED_EPOCH_OFFSET || |
There was a problem hiding this comment.
For my own understanding: if endOffset is UNDEFINED the epoch should always be UNDEFINED too? If that's the case we can just rely on leaderEpoch alone?
There was a problem hiding this comment.
I just feel this check is stronger if later we change the behavior on broker.
There was a problem hiding this comment.
Older versions did not return the epoch, so it was possible to see an offset defined without an epoch. However, the version that the consumer relies on should always have both or neither. Anyway, I think it is reasonable to be a little stricter here.
18d2e3a to
cf73388
Compare
guozhangwang
left a comment
There was a problem hiding this comment.
I think @hachikuji can take another look at this.
|
Where are with this? |
|
@ijuma will ping Jason for another review |
|
I was waiting for #8376 to get merged. I will review this shortly. |
hachikuji
left a comment
There was a problem hiding this comment.
@abbccdda Sorry for the delay. I think what we decided is that if the current leader epoch is not known, then we would not attempt to send OffsetsForLeaderEpoch because we cannot trust the result. What I had in mind was a little bit simpler, but I could be missing something. Inside SubscriptionState.TopicPartitionState.maybeValidatePosition, we have the following check:
if (!currentLeaderAndEpoch.leader.isPresent() && !currentLeaderAndEpoch.epoch.isPresent()) {
return false;
}What I was thinking is that we could do something like the following:
if (!currentLeaderAndEpoch.leader.isPresent()) {
return false;
}
if (!currentLeaderAndEpoch.epoch.isPresent()) {
completeValidation();
return false;
}That is, if we know the leader, but we don't have an epoch, then we must either have an older api or we must have discarded the value. Either way, we skip validation and begin fetching. Would that not work?
8b5d33a to
1d08929
Compare
…eck epoch/offset in response
| } | ||
|
|
||
| public boolean hasUndefinedEpochOrOffset() { | ||
| return this.endOffset == UNDEFINED_EPOCH_OFFSET || |
There was a problem hiding this comment.
Older versions did not return the epoch, so it was possible to see an offset defined without an epoch. However, the version that the consumer relies on should always have both or neither. Anyway, I think it is reasonable to be a little stricter here.
|
retest this please |
2 similar comments
|
retest this please |
|
retest this please |
|
retest this please |
1 similar comment
|
retest this please |
|
|
||
| if (respEndOffset.hasUndefinedEpochOrOffset()) { | ||
| handleOffsetOutOfRange(requestPosition.offset, respTopicPartition, | ||
| handleOffsetOutOfRange(requestPosition, respTopicPartition, |
There was a problem hiding this comment.
Didn't notice this before, but this is handled inside a loop. If one partition hits an error, then the raised exception will prevent us from completing the validation for other partitions.
| "Failed leader offset epoch validation for " + requestPosition | ||
| + " since no end offset larger than current fetch epoch was reported"); | ||
| } catch (OffsetOutOfRangeException e) { | ||
| // Swallow the OffsetOutOfRangeException to finish all partitions validation. |
There was a problem hiding this comment.
I don't feel great about having this in the code, even if it's supposed to be temporary. I think we should just fix the exception propagation bug in this patch. It seems like it would be straightforward to do something similar to what is done in the onFailure path.
if (!(e instanceof RetriableException) && !cachedOffsetForLeaderException.compareAndSet(null, e)) {
log.error("Discarding error in OffsetsForLeaderEpoch because another error is pending", e);
}Above may not be ideal, but at least it provides a way to propagate individual errors.
|
ok to test |
hachikuji
left a comment
There was a problem hiding this comment.
LGTM. Thanks for the patch!
|
|
||
| private void initMetadata(MockClient mockClient, Map<String, Integer> partitionCounts) { | ||
| MetadataResponse initialMetadata = TestUtils.metadataUpdateWith(1, partitionCounts); | ||
| int leaderEpoch = 1; |
There was a problem hiding this comment.
This is the actual fix, the other parts are mostly cleanup
|
ok to test |
|
ok to test |
|
retest please |
|
retest this please |
2 similar comments
|
retest this please |
|
retest this please |
…eliable (#8486) This PR provides two fixes: 1. Skip offset validation if the current leader epoch cannot be reliably determined. 2. Raise an out of range error if the leader returns an undefined offset in response to the OffsetsForLeaderEpoch request. Reviewers: Guozhang Wang <wangguoz@gmail.com>, Jason Gustafson <jason@confluent.io>
* 'trunk' of github.com:apache/kafka: (46 commits) MINOR: improve code encapsulation between StreamThread and TaskManager (apache#8819) Fixing KAFKA-10094 (apache#8797) KAFKA-9851: Revoking Connect tasks due to connectivity issues should also clear the running assignment (apache#8804) KAFKA-9840; Skip End Offset validation when the leader epoch is not reliable (apache#8486) HOT_FIX: Update javadoc since imports added (apache#8817) KAFKA-8011: Fix flaky RegexSourceIntegrationTest (apache#8799) KAFKA-9570: Define SSL configs in all worker config classes, not just distributed (apache#8135) KAFKA-10111: Make SinkTaskContext.errantRecordReporter() a default method (apache#8814) KAFKA-10110: Corrected potential NPE when null label value added to KafkaMetricsContext (apache#8811) MINOR: Change the order that Connect calls `config()` and `validate()` to avoid validating if the required ConfigDef is null (apache#8810) MINOR: fix backwards incompatibility in JmxReporter introduced by KIP-606 MINOR: Fix javadoc warnings (apache#8809) KAFKA-9441: Improve Kafka Streams task management (apache#8776) fix the broken links of streams javadoc (apache#8789) KAFKA-10040; Make computing the PreferredReplicaImbalanceCount metric more efficient (apache#8724) KAFKA-10066: TestOutputTopic should pass record headers into deserializers (apache#8759) MINOR: Add explanation for disabling forwarding from value transformers (apache#8771) KAFKA-10033: Throw UnknownTopicOrPartitionException if altering configs of non-existing topic KAFKA-9434: automated protocol for alterReplicaLogDirs (apache#8311) KAFKA-9313: Set `use_all_dns_ips` as the new default for `client.dns.lookup` (KIP-602) (apache#8644) ...
Conflicts: * build.gradle: take upstream changes regarding heap memory configuration for the build. * apache-github/trunk: (33 commits) MINOR: fix HTML markup (apache#8823) KAFKA-10012; Reduce overhead of strings in SelectorMetrics (apache#8684) KAFKA-9216: Enforce internal config topic settings for Connect workers during startup (apache#8270) KAFKA-10097: Internalize checkpoint data (apache#8820) KAFKA-10033: Throw UnknownTopicOrPartitionException when modifying a non-existent topic's config MINOR: improve code encapsulation between StreamThread and TaskManager (apache#8819) Fixing KAFKA-10094 (apache#8797) KAFKA-9851: Revoking Connect tasks due to connectivity issues should also clear the running assignment (apache#8804) KAFKA-9840; Skip End Offset validation when the leader epoch is not reliable (apache#8486) HOT_FIX: Update javadoc since imports added (apache#8817) KAFKA-8011: Fix flaky RegexSourceIntegrationTest (apache#8799) KAFKA-9570: Define SSL configs in all worker config classes, not just distributed (apache#8135) KAFKA-10111: Make SinkTaskContext.errantRecordReporter() a default method (apache#8814) KAFKA-10110: Corrected potential NPE when null label value added to KafkaMetricsContext (apache#8811) MINOR: Change the order that Connect calls `config()` and `validate()` to avoid validating if the required ConfigDef is null (apache#8810) MINOR: fix backwards incompatibility in JmxReporter introduced by KIP-606 MINOR: Fix javadoc warnings (apache#8809) KAFKA-9441: Improve Kafka Streams task management (apache#8776) fix the broken links of streams javadoc (apache#8789) KAFKA-10040; Make computing the PreferredReplicaImbalanceCount metric more efficient (apache#8724) ...
This PR provides two fixes:
Committer Checklist (excluded from commit message)