Skip to content

KAFKA-16154: Broker returns offset for LATEST_TIERED_TIMESTAMP#16783

Merged
showuon merged 14 commits into
apache:trunkfrom
brandboat:KAFKA-16154
Aug 5, 2024
Merged

KAFKA-16154: Broker returns offset for LATEST_TIERED_TIMESTAMP#16783
showuon merged 14 commits into
apache:trunkfrom
brandboat:KAFKA-16154

Conversation

@brandboat

@brandboat brandboat commented Aug 2, 2024

Copy link
Copy Markdown
Member

This pr support EarliestLocalSpec LatestTierSpec in GetOffsetShell, and add integration tests.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

@showuon showuon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. Left some comments.

Comment on lines +76 to +79
* Used to retrieve the offset with the local log start offset,
* log start offset is the offset of a log above which reads are guaranteed to be served
* from the disk of the leader broker, when Tiered Storage is not enabled, it behaves the same
* as the earliest timestamp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Used to retrieve the offset with the local log start offset[.]
[Local] log start offset is the offset of a log above which reads are guaranteed to be served from the disk of the leader broker.

Note: When tiered storage is not enabled, it behaves the same as retrieving the earliest timestamp offset.

Comment on lines +86 to +87
* Used to retrieve the offset with the highest offset of data stored in remote storage,
* and when Tiered Storage is not enabled, we won't return any offset (i.e. Unknown offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Used to retrieve the offset with the highest offset of data stored in remote storage[.]

Note: When tiered storage is not enabled, we won't return any offset (i.e. [will return] unknown offset.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comments, already fixed them in the latest commit.

@showuon showuon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM! We need integration tests for it. We should add some test like DeleteTopicTest using ExpectListOffsetsAction. I expected it should work like this (I didn't try):

// send records to partition 0
                .expectSegmentToBeOffloaded(broker0, topicA, p0, 0, new KeyValueSpec("k0", "v0"))
                .expectSegmentToBeOffloaded(broker0, topicA, p0, 1, new KeyValueSpec("k1", "v1"))
                .expectEarliestLocalOffsetInLogDirectory(topicA, p0, 2L)
                .produce(topicA, p0, new KeyValueSpec("k0", "v0"), new KeyValueSpec("k1", "v1"),
                        new KeyValueSpec("k2", "v2"))
                // new verification:
                 .expectListOffsets(topicA, 0, LatestTierSpec, 0(?)) <-- should create an expected `EpochEntry` instance

Let me know if you have any problem.

@showuon

showuon commented Aug 3, 2024

Copy link
Copy Markdown
Member

I mean, we can create a test called listOffsetTest under org.apache.kafka.tiered.storage.integration to test it.

@brandboat

Copy link
Copy Markdown
Member Author

Overall LGTM! We need integration tests for it. We should add some test like DeleteTopicTest using ExpectListOffsetsAction. I expected it should work like this (I didn't try):

Thanks @showuon , I enabled remote storage in GetOffsetShellTest, do we still need the test you mentioned above ?

Comment thread tools/src/test/java/org/apache/kafka/tools/GetOffsetShellTest.java Outdated

private static List<ClusterConfig> withRemoteStorage() {
Map<String, String> serverProperties = new HashMap<>();
serverProperties.put(RemoteLogManagerConfig.DEFAULT_REMOTE_LOG_METADATA_MANAGER_CONFIG_PREFIX + TopicBasedRemoteLogMetadataManagerConfig.REMOTE_LOG_METADATA_TOPIC_REPLICATION_FACTOR_PROP, "1");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we set remote.log.metadata.topic.num.partitions to 1 (default is 50) to speed up the test?

@showuon showuon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM! Left some comments. Thanks.

Comment on lines +140 to +144
Map<String, String> zkProperties = new HashMap<>(serverProperties);
zkProperties.put(RemoteLogManagerConfig.REMOTE_LOG_METADATA_MANAGER_LISTENER_NAME_PROP, "PLAINTEXT");

Map<String, String> raftProperties = new HashMap<>(serverProperties);
raftProperties.put(RemoteLogManagerConfig.REMOTE_LOG_METADATA_MANAGER_LISTENER_NAME_PROP, "EXTERNAL");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a comment here to explain why we need 2 different settings?

@brandboat brandboat Aug 3, 2024

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, after spending some time digging through the code I found out that in Type.ZK the default listener name is PLAINTEXT and is set via

@Override
public ListenerName listenerName() {
return clusterConfig.listenerName().map(ListenerName::normalised)
.orElseGet(() -> ListenerName.forSecurityProtocol(securityProtocol()));
}

while in Type.KRAFT/Type.CO_KRAFT, it is EXTERNAL, see
private String listeners(int node) {
if (nodes.isCombined(node)) {
return "EXTERNAL://localhost:0,CONTROLLER://localhost:0";
}
if (nodes.controllerNodes().containsKey(node)) {
return "CONTROLLER://localhost:0";
}
return "EXTERNAL://localhost:0";
}

Another thing is that ClusterConfig#setListenerName only works under ZK mode, in KRAFT it is useless. Perhaps we should make it work under Raft mode too. gentle ping @chia7712, any thoughts ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brandboat you are right. Could you please open a jira for that? KRAFT should honor the listener name and security protocol from ClusterConfig.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for double checking, filed https://issues.apache.org/jira/browse/KAFKA-17256

sendProducerRecords(this::getTopicName);
}

private void setUpRemoteLogTopics() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add some comment for this method. Ex:

In this method, we'll create 4 topics and produce records to the log like this:
topicRLS1 -> 1 segment
topicRLS2 -> 2 segments (1 local log segment + 1 segment in the remote storage)
topicRLS3 -> 3 segments (1 local log segment + 2 segments in the remote storage)
topicRLS4 -> 4 segments (1 local log segment + 3 segments in the remote storage)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the detailed comment, this will certainly help others grasp the details of the test 😃

Comment on lines +364 to +369
// test topics enable remote log storage
TestUtils.waitForCondition(() ->
Arrays.asList(
new Row("topicRLS2", 0, 0L),
new Row("topicRLS3", 0, 1L),
new Row("topicRLS4", 0, 2L))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add 1 more line for the comment to explain why topicRLS1 has no result:
topicRLS1 has no result because there's no log segments being uploaded to the remote storage

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything has been addressed in the latest commit, thank you

@chia7712 chia7712 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brandboat thanks for this nice patch. I leave some comments for this PR. The naming is part of public APIs, so we must have "accurate" naming before release.

serverProperties.put(ServerLogConfigs.LOG_INITIAL_TASK_DELAY_MS_CONFIG, "100");
serverProperties.put(RemoteLogManagerConfig.REMOTE_LOG_METADATA_MANAGER_LISTENER_NAME_PROP, "EXTERNAL");

return Arrays.asList(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can set listener name for all types even though setListenerName is no-op for kraft/co-kraft mode. That can simplify the code and it is still valid.

        return Collections.singletonList(
                ClusterConfig.defaultBuilder()
                        .setTypes(new HashSet<>(Arrays.asList(ZK, KRAFT, CO_KRAFT)))
                        .setServerProperties(serverProperties)
                        .setListenerName("EXTERNAL")
                        .build());

return OffsetSpec.latest();
case "max-timestamp":
return OffsetSpec.maxTimestamp();
case "earliest-local":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please update docs?

.describedAs("<timestamp> / -1 or latest / -2 or earliest / -3 or max-timestamp")

* and when Tiered Storage is not enabled, we won't return any offset (i.e. Unknown offset)
* Used to retrieve the highest offset of data stored in remote storage.
* <br/>
* Note: When tiered storage is not enabled, we will return unknown offset.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add test for this scenario?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* Local log start offset is the offset of a log above which reads
* are guaranteed to be served from the disk of the leader broker.
* <br/>
* Note: When tiered Storage is not enabled, it behaves the same as retrieving the earliest timestamp offset.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add test for it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do, thanks

* <br/>
* Note: When tiered Storage is not enabled, it behaves the same as retrieving the earliest timestamp offset.
*/
public static OffsetSpec earliestLocalSpec() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to this PR. The other specs don't use Spec as postfix. Maybe we should align the naming before release?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll remove the postfix

* Note: When tiered storage is not enabled, we will return unknown offset.
*/
public static OffsetSpec latestTierSpec() {
return new LatestTierSpec();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to this PR, but KIP-1005 (https://cwiki.apache.org/confluence/display/KAFKA/KIP-1005%3A+Expose+EarliestLocalOffset+and+TieredOffset) calls it LatestTieredSpec rather than LatestTierSpec

ping @FrankYang0529 as you are the author of #16781

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for finding this. Yes, we should follow the KIP. @brandboat, could you fix it in this PR? I'm afraid if I create another PR may block your progress.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything has been addressed, thanks everyone.

@FrankYang0529

Copy link
Copy Markdown
Member

@brandboat, I think we also need to update L296-297 in GetOffsetShell

throw new TerseException("Malformed time argument " + listOffsetsTimestamp + ". " +
                            "Please use -1 or latest / -2 or earliest / -3 or max-timestamp, or a specified long format timestamp");

@FrankYang0529 FrankYang0529 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for the patch.

serverProperties.put(RemoteLogManagerConfig.REMOTE_LOG_STORAGE_SYSTEM_ENABLE_PROP, "true");
serverProperties.put(RemoteLogManagerConfig.REMOTE_STORAGE_MANAGER_CLASS_NAME_PROP, LocalTieredStorage.class.getName());
serverProperties.put(RemoteLogManagerConfig.REMOTE_LOG_MANAGER_TASK_INTERVAL_MS_PROP, "1000");
serverProperties.put(TopicBasedRemoteLogMetadataManagerConfig.REMOTE_LOG_METADATA_TOPIC_PARTITIONS_PROP, "1");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add RemoteLogManagerConfig.DEFAULT_REMOTE_LOG_METADATA_MANAGER_CONFIG_PREFIX to set REMOTE_LOG_METADATA_TOPIC_PARTITIONS_PROP, but I might be wrong. Could you confirm the current change takes effect in the remote log topics?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah... I missed that. Thank you

@showuon showuon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@chia7712 chia7712 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@brandboat

brandboat commented Aug 4, 2024

Copy link
Copy Markdown
Member Author

failed test passed in my local env:

./gradlew cleanTest \
  core:test --tests kafka.zk.ZkMigrationFailoverTest.testDriverSkipsEventsFromOlderEpoch \
  tool:test --tests org.apache.kafka.tools.LeaderElectionCommandTest.testPreferredReplicaElection \
  clients:test --tests org.apache.kafka.common.record.MemoryRecordsBuilderTest.testBuffersDereferencedOnClose

@showuon
showuon merged commit 84add30 into apache:trunk Aug 5, 2024
@brandboat
brandboat deleted the KAFKA-16154 branch August 5, 2024 02:41
showuon pushed a commit that referenced this pull request Aug 5, 2024
This pr support EarliestLocalSpec LatestTierSpec in GetOffsetShell, and add integration tests.

Reviewers: Luke Chen <showuon@gmail.com>, Chia-Ping Tsai <chia7712@gmail.com>, PoAn Yang <payang@apache.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants