-
Notifications
You must be signed in to change notification settings - Fork 15.1k
KAFKA-16977: Reapply dynamic remote configs after broker restart #16353
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ | |
| import kafka.log.remote.quota.RLMQuotaManager; | ||
| import kafka.log.remote.quota.RLMQuotaManagerConfig; | ||
| import kafka.server.BrokerTopicStats; | ||
| import kafka.server.KafkaConfig; | ||
| import kafka.server.QuotaType; | ||
| import kafka.server.StopPartition; | ||
| import org.apache.kafka.common.KafkaException; | ||
|
|
@@ -151,7 +152,7 @@ public class RemoteLogManager implements Closeable { | |
|
|
||
| private static final Logger LOGGER = LoggerFactory.getLogger(RemoteLogManager.class); | ||
| private static final String REMOTE_LOG_READER_THREAD_NAME_PREFIX = "remote-log-reader"; | ||
| private final RemoteLogManagerConfig rlmConfig; | ||
| private final KafkaConfig config; | ||
| private final int brokerId; | ||
| private final String logDir; | ||
| private final Time time; | ||
|
|
@@ -192,7 +193,7 @@ public class RemoteLogManager implements Closeable { | |
| /** | ||
| * Creates RemoteLogManager instance with the given arguments. | ||
| * | ||
| * @param rlmConfig Configuration required for remote logging subsystem(tiered storage) at the broker level. | ||
| * @param config Configuration required for remote logging subsystem(tiered storage) at the broker level. | ||
| * @param brokerId id of the current broker. | ||
| * @param logDir directory of Kafka log segments. | ||
| * @param time Time instance. | ||
|
|
@@ -202,7 +203,7 @@ public class RemoteLogManager implements Closeable { | |
| * @param brokerTopicStats BrokerTopicStats instance to update the respective metrics. | ||
| * @param metrics Metrics instance | ||
| */ | ||
| public RemoteLogManager(RemoteLogManagerConfig rlmConfig, | ||
| public RemoteLogManager(KafkaConfig config, | ||
| int brokerId, | ||
| String logDir, | ||
| String clusterId, | ||
|
|
@@ -211,7 +212,7 @@ public RemoteLogManager(RemoteLogManagerConfig rlmConfig, | |
| BiConsumer<TopicPartition, Long> updateRemoteLogStartOffset, | ||
| BrokerTopicStats brokerTopicStats, | ||
| Metrics metrics) throws IOException { | ||
| this.rlmConfig = rlmConfig; | ||
| this.config = config; | ||
| this.brokerId = brokerId; | ||
| this.logDir = logDir; | ||
| this.clusterId = clusterId; | ||
|
|
@@ -226,7 +227,8 @@ public RemoteLogManager(RemoteLogManagerConfig rlmConfig, | |
| rlmCopyQuotaManager = createRLMCopyQuotaManager(); | ||
| rlmFetchQuotaManager = createRLMFetchQuotaManager(); | ||
|
|
||
| indexCache = new RemoteIndexCache(rlmConfig.remoteLogIndexFileCacheTotalSizeBytes(), remoteLogStorageManager, logDir); | ||
| RemoteLogManagerConfig rlmConfig = config.remoteLogManagerConfig(); | ||
| indexCache = new RemoteIndexCache(config.remoteLogIndexFileCacheTotalSizeBytes(), remoteLogStorageManager, logDir); | ||
| delayInMs = rlmConfig.remoteLogManagerTaskIntervalMs(); | ||
| rlmScheduledThreadPool = new RLMScheduledThreadPool(rlmConfig.remoteLogManagerThreadPoolSize()); | ||
|
|
||
|
|
@@ -274,27 +276,29 @@ Duration quotaTimeout() { | |
| } | ||
|
|
||
| RLMQuotaManager createRLMCopyQuotaManager() { | ||
| return new RLMQuotaManager(copyQuotaManagerConfig(rlmConfig), metrics, QuotaType.RLMCopy$.MODULE$, | ||
| return new RLMQuotaManager(copyQuotaManagerConfig(config), metrics, QuotaType.RLMCopy$.MODULE$, | ||
| "Tracking copy byte-rate for Remote Log Manager", time); | ||
| } | ||
|
|
||
| RLMQuotaManager createRLMFetchQuotaManager() { | ||
| return new RLMQuotaManager(fetchQuotaManagerConfig(rlmConfig), metrics, QuotaType.RLMFetch$.MODULE$, | ||
| return new RLMQuotaManager(fetchQuotaManagerConfig(config), metrics, QuotaType.RLMFetch$.MODULE$, | ||
| "Tracking fetch byte-rate for Remote Log Manager", time); | ||
| } | ||
|
|
||
| public boolean isRemoteLogFetchQuotaExceeded() { | ||
| return rlmFetchQuotaManager.isQuotaExceeded(); | ||
| } | ||
|
|
||
| static RLMQuotaManagerConfig copyQuotaManagerConfig(RemoteLogManagerConfig rlmConfig) { | ||
| return new RLMQuotaManagerConfig(rlmConfig.remoteLogManagerCopyMaxBytesPerSecond(), | ||
| static RLMQuotaManagerConfig copyQuotaManagerConfig(KafkaConfig config) { | ||
| RemoteLogManagerConfig rlmConfig = config.remoteLogManagerConfig(); | ||
| return new RLMQuotaManagerConfig(config.remoteLogManagerCopyMaxBytesPerSecond(), | ||
| rlmConfig.remoteLogManagerCopyNumQuotaSamples(), | ||
| rlmConfig.remoteLogManagerCopyQuotaWindowSizeSeconds()); | ||
| } | ||
|
|
||
| static RLMQuotaManagerConfig fetchQuotaManagerConfig(RemoteLogManagerConfig rlmConfig) { | ||
| return new RLMQuotaManagerConfig(rlmConfig.remoteLogManagerFetchMaxBytesPerSecond(), | ||
| static RLMQuotaManagerConfig fetchQuotaManagerConfig(KafkaConfig config) { | ||
| RemoteLogManagerConfig rlmConfig = config.remoteLogManagerConfig(); | ||
| return new RLMQuotaManagerConfig(config.remoteLogManagerFetchMaxBytesPerSecond(), | ||
| rlmConfig.remoteLogManagerFetchNumQuotaSamples(), | ||
| rlmConfig.remoteLogManagerFetchQuotaWindowSizeSeconds()); | ||
| } | ||
|
|
@@ -311,6 +315,7 @@ private <T> T createDelegate(ClassLoader classLoader, String className) { | |
|
|
||
| @SuppressWarnings("removal") | ||
| RemoteStorageManager createRemoteStorageManager() { | ||
| RemoteLogManagerConfig rlmConfig = config.remoteLogManagerConfig(); | ||
| return java.security.AccessController.doPrivileged(new PrivilegedAction<RemoteStorageManager>() { | ||
| private final String classPath = rlmConfig.remoteStorageManagerClassPath(); | ||
|
|
||
|
|
@@ -327,13 +332,14 @@ public RemoteStorageManager run() { | |
| } | ||
|
|
||
| private void configureRSM() { | ||
| final Map<String, Object> rsmProps = new HashMap<>(rlmConfig.remoteStorageManagerProps()); | ||
| final Map<String, Object> rsmProps = new HashMap<>(config.remoteLogManagerConfig().remoteStorageManagerProps()); | ||
| rsmProps.put(ServerConfigs.BROKER_ID_CONFIG, brokerId); | ||
| remoteLogStorageManager.configure(rsmProps); | ||
| } | ||
|
|
||
| @SuppressWarnings("removal") | ||
| RemoteLogMetadataManager createRemoteLogMetadataManager() { | ||
| RemoteLogManagerConfig rlmConfig = config.remoteLogManagerConfig(); | ||
| return java.security.AccessController.doPrivileged(new PrivilegedAction<RemoteLogMetadataManager>() { | ||
| private final String classPath = rlmConfig.remoteLogMetadataManagerClassPath(); | ||
|
|
||
|
|
@@ -360,7 +366,7 @@ private void configureRLMM() { | |
| rlmmProps.put(REMOTE_LOG_METADATA_COMMON_CLIENT_PREFIX + "security.protocol", e.securityProtocol().name); | ||
| }); | ||
| // update the remoteLogMetadataProps here to override endpoint config if any | ||
| rlmmProps.putAll(rlmConfig.remoteLogMetadataManagerProps()); | ||
| rlmmProps.putAll(config.remoteLogManagerConfig().remoteLogMetadataManagerProps()); | ||
|
|
||
| rlmmProps.put(ServerConfigs.BROKER_ID_CONFIG, brokerId); | ||
| rlmmProps.put(LOG_DIR_CONFIG, logDir); | ||
|
|
@@ -412,7 +418,7 @@ public void onLeadershipChange(Set<Partition> partitionsBecomeLeader, | |
| Map<String, Uuid> topicIds) { | ||
| LOGGER.debug("Received leadership changes for leaders: {} and followers: {}", partitionsBecomeLeader, partitionsBecomeFollower); | ||
|
|
||
| if (this.rlmConfig.isRemoteStorageSystemEnabled() && !isRemoteLogManagerConfigured()) { | ||
| if (config.remoteLogManagerConfig().isRemoteStorageSystemEnabled() && !isRemoteLogManagerConfigured()) { | ||
|
Member
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. this is unrelated to this PR, but
Contributor
Author
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. yes, this is the main issue. We access the remote configurations using So, changed the usages to
Member
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. As we have great If this PR aims to fix it for zk mode, maybe we can make sure the
@kamalcph WDYT?
Contributor
Author
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. Can we take this refactoring as part of KAFKA-16976 ticket?
Member
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. @chia7712 Good point. A similar issue is raised in the comment. We can fix the bug with the current approach in 3.8 and finish cleaning up the raised issues in a followup as part of KAFKA-16976
Member
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. |
||
| throw new KafkaException("RemoteLogManager is not configured when remote storage system is enabled"); | ||
| } | ||
|
|
||
|
|
@@ -1742,9 +1748,10 @@ public Future<Void> asyncRead(RemoteStorageFetchInfo fetchInfo, Consumer<RemoteL | |
|
|
||
| void doHandleLeaderOrFollowerPartitions(TopicIdPartition topicPartition, | ||
| Consumer<RLMTask> convertToLeaderOrFollower) { | ||
| RemoteLogManagerConfig rlmConfig = config.remoteLogManagerConfig(); | ||
| RLMTaskWithFuture rlmTaskWithFuture = leaderOrFollowerTasks.computeIfAbsent(topicPartition, | ||
| topicIdPartition -> { | ||
| RLMTask task = new RLMTask(topicIdPartition, this.rlmConfig.remoteLogMetadataCustomMetadataMaxBytes()); | ||
| RLMTask task = new RLMTask(topicIdPartition, rlmConfig.remoteLogMetadataCustomMetadataMaxBytes()); | ||
| // set this upfront when it is getting initialized instead of doing it after scheduling. | ||
| convertToLeaderOrFollower.accept(task); | ||
| LOGGER.info("Created a new task: {} and getting scheduled", task); | ||
|
|
||
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.
not sure whether I have caught the context, so please feel free to correct me.
RemoteLogManager, right?remote.log.manager.copy.max.bytes.per.second,remote.log.manager.fetch.max.bytes.per.second) can be updated byreconfigureprocess, so it should be fine to initialize them with "stale" (static) configs after broker restart, right?Uh oh!
There was an error while loading. Please reload this page.
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.
No, KafkaServer/BrokerServer does
config.dynamicConfig.initializebefore creating the RemoteLogManager instance so the dynamic configs gets updated in theKafkaConfigobject but not in theKafkaConfig.remoteLogManagerConfig().I have tested the patch only with ZooKeeper. I think the behavior should be similar for KRaftMetadataCache/ConfigRepository.
This is correct, the
reconfigureupdates the dynamic value but we are referring to the static value as explained above.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.
That is a good point, and maybe they do have something difference.
kafka/core/src/main/scala/kafka/server/DynamicBrokerConfig.scala
Line 228 in bcf7812
in kraft,
zkClientOptis none so it does not update it with dynamical parts.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.
Yes, I confirmed in KRaft, it won't have this issue.
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.
Sorry that I'm not sure which issue you confirmed. If we are taking about dynamic configs in starting. According to above comments, it seems to me this fix which tries to return latest (dynamic) configs works well only if kafka is in zk. In kraft, this fix is no-op as it still return static configs.
Please correct me If I'm lost
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.
@chia7712 , yes, you're right! To KRaft, this fix is no-op.