Skip to content

Commit 842f970

Browse files
xinyuiscoolprateekm
authored andcommitted
SAMZA-2352: Use min.compaction.lag.ms to avoid compacting the Kafka changelog topic (#1190)
1 parent e2928e1 commit 842f970

4 files changed

Lines changed: 55 additions & 2 deletions

File tree

samza-core/src/main/java/org/apache/samza/config/StorageConfig.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.apache.samza.execution.StreamManager;
3232
import org.apache.samza.util.StreamUtil;
3333

34+
import static com.google.common.base.Preconditions.*;
35+
3436

3537
/**
3638
* Config helper methods related to storage.
@@ -45,13 +47,18 @@ public class StorageConfig extends MapConfig {
4547
public static final String MSG_SERDE = STORE_PREFIX + "%s.msg.serde";
4648
public static final String CHANGELOG_STREAM = STORE_PREFIX + "%s" + CHANGELOG_SUFFIX;
4749
public static final String ACCESSLOG_STREAM_SUFFIX = "access-log";
50+
// TODO: setting replication.factor seems not working as in KafkaConfig.
4851
public static final String CHANGELOG_REPLICATION_FACTOR = STORE_PREFIX + "%s.changelog.replication.factor";
4952
public static final String CHANGELOG_MAX_MSG_SIZE_BYTES = STORE_PREFIX + "%s.changelog.max.message.size.bytes";
5053
public static final int DEFAULT_CHANGELOG_MAX_MSG_SIZE_BYTES = 1048576;
5154
public static final String DISALLOW_LARGE_MESSAGES = STORE_PREFIX + "%s.disallow.large.messages";
5255
public static final boolean DEFAULT_DISALLOW_LARGE_MESSAGES = false;
5356
public static final String DROP_LARGE_MESSAGES = STORE_PREFIX + "%s.drop.large.messages";
5457
public static final boolean DEFAULT_DROP_LARGE_MESSAGES = false;
58+
// The log compaction lag time for transactional state change log
59+
public static final String MIN_COMPACTION_LAG_MS = "min.compaction.lag.ms";
60+
public static final String CHANGELOG_MIN_COMPACTION_LAG_MS = STORE_PREFIX + "%s.changelog." + MIN_COMPACTION_LAG_MS;
61+
public static final long DEFAULT_CHANGELOG_MIN_COMPACTION_LAG_MS = TimeUnit.HOURS.toMillis(4);
5562

5663
static final String CHANGELOG_SYSTEM = "job.changelog.system";
5764
static final String CHANGELOG_DELETE_RETENTION_MS = STORE_PREFIX + "%s.changelog.delete.retention.ms";
@@ -207,6 +214,15 @@ public boolean getDropLargeMessages(String storeName) {
207214
return getBoolean(String.format(DROP_LARGE_MESSAGES, storeName), DEFAULT_DROP_LARGE_MESSAGES);
208215
}
209216

217+
public long getChangelogMinCompactionLagMs(String storeName) {
218+
String minCompactLagConfigName = String.format(CHANGELOG_MIN_COMPACTION_LAG_MS, storeName);
219+
// Avoid the inconsistency of overriding using stores.x.changelog.kafka...
220+
checkArgument(get("stores." + storeName + ".changelog.kafka." + MIN_COMPACTION_LAG_MS) == null,
221+
"Use " + minCompactLagConfigName + " to set kafka min.compaction.lag.ms property.");
222+
223+
return getLong(minCompactLagConfigName, DEFAULT_CHANGELOG_MIN_COMPACTION_LAG_MS);
224+
}
225+
210226
/**
211227
* Helper method to check if a system has a changelog attached to it.
212228
*/

samza-core/src/test/java/org/apache/samza/config/TestStorageConfig.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.common.collect.ImmutableList;
2626
import com.google.common.collect.ImmutableMap;
2727
import com.google.common.collect.ImmutableSet;
28+
import java.util.concurrent.TimeUnit;
2829
import org.apache.samza.SamzaException;
2930
import org.junit.Test;
3031

@@ -296,4 +297,17 @@ public void testGetDropLargeMessages() {
296297
new MapConfig(ImmutableMap.of(String.format(StorageConfig.DROP_LARGE_MESSAGES, STORE_NAME0), "true")));
297298
assertEquals(true, storageConfig.getDropLargeMessages(STORE_NAME0));
298299
}
300+
301+
@Test
302+
public void testGetChangelogMinCompactionLagMs() {
303+
// empty config, return default lag ms
304+
assertEquals(DEFAULT_CHANGELOG_MIN_COMPACTION_LAG_MS,
305+
new StorageConfig(new MapConfig()).getChangelogMinCompactionLagMs(STORE_NAME0));
306+
307+
long lagOverride = TimeUnit.HOURS.toMillis(6);
308+
StorageConfig storageConfig = new StorageConfig(
309+
new MapConfig(ImmutableMap.of(String.format(CHANGELOG_MIN_COMPACTION_LAG_MS, STORE_NAME0),
310+
String.valueOf(lagOverride))));
311+
assertEquals(lagOverride, storageConfig.getChangelogMinCompactionLagMs(STORE_NAME0));
312+
}
299313
}

samza-kafka/src/main/scala/org/apache/samza/config/KafkaConfig.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,18 @@ class KafkaConfig(config: Config) extends ScalaMapConfig(config) {
336336
kafkaChangeLogProperties.setProperty("max.message.bytes", getChangelogStreamMaxMessageByte(name))
337337
}
338338

339+
val storageConfig = new StorageConfig(config)
339340
kafkaChangeLogProperties.setProperty("segment.bytes", KafkaConfig.CHANGELOG_DEFAULT_SEGMENT_SIZE)
340-
kafkaChangeLogProperties.setProperty("delete.retention.ms", String.valueOf(new StorageConfig(config).getChangeLogDeleteRetentionInMs(name)))
341+
kafkaChangeLogProperties.setProperty("delete.retention.ms", String.valueOf(storageConfig.getChangeLogDeleteRetentionInMs(name)))
342+
343+
// To enable transactional state, we will need to avoid the head of the changelog
344+
// (the messages after last checkpoint) being log-compacted so we can trim the rest of the updates.
345+
// We use min.compaction.log.ms to control the compaction time.
346+
if (new TaskConfig(this).getTransactionalStateRestoreEnabled) {
347+
kafkaChangeLogProperties.setProperty(StorageConfig.MIN_COMPACTION_LAG_MS,
348+
String.valueOf(storageConfig.getChangelogMinCompactionLagMs(name)))
349+
}
350+
341351
filteredConfigs.asScala.foreach { kv => kafkaChangeLogProperties.setProperty(kv._1, kv._2) }
342352
kafkaChangeLogProperties
343353
}

samza-kafka/src/test/scala/org/apache/samza/config/TestKafkaConfig.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.apache.samza.config
2121

2222
import java.util.Properties
23+
import java.util.concurrent.TimeUnit
2324

2425
import org.apache.samza.config.factories.PropertiesConfigFactory
2526
import org.junit.Assert._
@@ -82,11 +83,11 @@ class TestKafkaConfig {
8283

8384
@Test
8485
def testChangeLogProperties() {
86+
props.setProperty("job.changelog.system", SYSTEM_NAME)
8587
props.setProperty("systems." + SYSTEM_NAME + ".samza.factory", "org.apache.samza.system.kafka.KafkaSystemFactory")
8688
props.setProperty("stores.test1.changelog", "kafka.mychangelog1")
8789
props.setProperty("stores.test2.changelog", "kafka.mychangelog2")
8890
props.setProperty("stores.test2.changelog.max.message.bytes", "1024000")
89-
props.setProperty("job.changelog.system", "kafka")
9091
props.setProperty("stores.test3.changelog", "otherstream")
9192
props.setProperty("stores.test1.changelog.kafka.cleanup.policy", "delete")
9293
props.setProperty("stores.test4.rocksdb.ttl.ms", "3600")
@@ -107,6 +108,7 @@ class TestKafkaConfig {
107108
assertEquals("otherstream", storeToChangelog.getOrDefault("test3", ""))
108109
assertNull(kafkaConfig.getChangelogKafkaProperties("test1").getProperty("retention.ms"))
109110
assertNull(kafkaConfig.getChangelogKafkaProperties("test2").getProperty("retention.ms"))
111+
assertNull(kafkaConfig.getChangelogKafkaProperties("test1").getProperty("min.compaction.lag.ms"))
110112

111113
props.setProperty("systems." + SYSTEM_NAME + ".samza.factory", "org.apache.samza.system.kafka.SomeOtherFactory")
112114
val storeToChangelog1 = kafkaConfig.getKafkaChangelogEnabledStores()
@@ -138,6 +140,17 @@ class TestKafkaConfig {
138140
String.valueOf(KafkaConfig.DEFAULT_RETENTION_MS_FOR_BATCH))
139141
assertEquals(batchKafkaConfig.getChangelogKafkaProperties("test3").getProperty("max.message.bytes"),
140142
KafkaConfig.DEFAULT_LOG_COMPACT_TOPIC_MAX_MESSAGE_BYTES)
143+
144+
// test compaction config for transactional state
145+
val lagOverride = String.valueOf(TimeUnit.HOURS.toMillis(6))
146+
props.setProperty(TaskConfig.TRANSACTIONAL_STATE_RESTORE_ENABLED, "true")
147+
props.setProperty("stores.test2.changelog.min.compaction.lag.ms", lagOverride)
148+
val tsMapConfig = new MapConfig(props.asScala.asJava)
149+
val tsKafkaConfig = new KafkaConfig(tsMapConfig)
150+
assertEquals(String.valueOf(StorageConfig.DEFAULT_CHANGELOG_MIN_COMPACTION_LAG_MS),
151+
tsKafkaConfig.getChangelogKafkaProperties("test1").getProperty("min.compaction.lag.ms"))
152+
assertEquals(lagOverride,
153+
tsKafkaConfig.getChangelogKafkaProperties("test2").getProperty("min.compaction.lag.ms"))
141154
}
142155

143156
@Test

0 commit comments

Comments
 (0)