MirrorMaker 2 Reference
MirrorMaker 2 (MM2) is Apache Kafka's tool for replicating data between Kafka clusters. Built on Kafka Connect, it provides topic replication, consumer offset synchronization, and automatic topic configuration mirroring.
What is MirrorMaker 2?
Section titled “What is MirrorMaker 2?”MirrorMaker 2 replaces the legacy MirrorMaker (MM1) with a redesigned architecture based on Kafka Connect. It addresses fundamental limitations of MM1:
| Limitation (MM1) | Solution (MM2) |
|---|---|
| No offset translation | Checkpoint-based offset synchronization |
| Topic configuration not synced | Automatic config mirroring |
| No ACL replication | ACL synchronization support |
| Manual topic creation | Automatic topic creation |
| Single cluster pair | Multiple cluster topologies |
| Difficult to monitor | Kafka Connect metrics and status |
MirrorMaker 2 Components
Section titled “MirrorMaker 2 Components”MM2 consists of three Kafka Connect connectors:
| Connector | Purpose |
|---|---|
| MirrorSourceConnector | Replicates topic data from source to target cluster |
| MirrorCheckpointConnector | Synchronizes consumer group offsets between clusters |
| MirrorHeartbeatConnector | Emits heartbeats for replication health monitoring |
Deployment Models
Section titled “Deployment Models”Dedicated MM2 Cluster
Section titled “Dedicated MM2 Cluster”Run MM2 as a standalone Connect cluster dedicated to replication.
Advantages:
- Isolated from other Connect workloads
- Independent scaling
- Clear resource allocation
Embedded in Existing Connect Cluster
Section titled “Embedded in Existing Connect Cluster”Deploy MM2 connectors alongside other connectors.
Advantages:
- Simpler infrastructure
- Shared monitoring
- Lower operational overhead
Disadvantages:
- Resource contention with other connectors
- Replication affected by other connector issues
Co-located with Target Cluster
Section titled “Co-located with Target Cluster”Run MM2 workers on target cluster broker nodes.
Advantages:
- Reduced network hops for writes
- Simpler networking
Disadvantages:
- Competes for broker resources
- Not recommended for high-volume replication
Configuration Reference
Section titled “Configuration Reference”Cluster Configuration
Section titled “Cluster Configuration”# Define clustersclusters = source, target
# Source cluster connectionsource.bootstrap.servers = source-broker-1:9092,source-broker-2:9092,source-broker-3:9092
# Target cluster connectiontarget.bootstrap.servers = target-broker-1:9092,target-broker-2:9092,target-broker-3:9092
# Security for source cluster (if required)source.security.protocol = SASL_SSLsource.sasl.mechanism = SCRAM-SHA-512source.sasl.jaas.config = org.apache.kafka.common.security.scram.ScramLoginModule required \ username="mm2-user" \ password="secret";
# Security for target cluster (if required)target.security.protocol = SASL_SSLtarget.sasl.mechanism = SCRAM-SHA-512target.sasl.jaas.config = org.apache.kafka.common.security.scram.ScramLoginModule required \ username="mm2-user" \ password="secret";Replication Flow Configuration
Section titled “Replication Flow Configuration”# Enable replication from source to targetsource->target.enabled = true
# Topics to replicate (regex patterns)source->target.topics = .*
# Topics to exclude from replicationsource->target.topics.exclude = .*[\-\.]internal, .*\.replica, __.*
# Consumer groups to replicate offsets forsource->target.groups = .*
# Groups to excludesource->target.groups.exclude = console-consumer-.*, connect-.*Topic Configuration
Section titled “Topic Configuration”# Replication factor for replicated topicsreplication.factor = 3
# Replication factor for MM2 internal topicscheckpoints.topic.replication.factor = 3heartbeats.topic.replication.factor = 3offset-syncs.topic.replication.factor = 3
# Topic creation settingsrefresh.topics.enabled = truerefresh.topics.interval.seconds = 60
# Sync topic configurationssync.topic.configs.enabled = truesync.topic.configs.interval.seconds = 60
# Sync topic ACLs (requires ACL access)sync.topic.acls.enabled = falseOffset Synchronization
Section titled “Offset Synchronization”# Enable consumer group offset syncsync.group.offsets.enabled = truesync.group.offsets.interval.seconds = 60
# Emit checkpoints for offset translationemit.checkpoints.enabled = trueemit.checkpoints.interval.seconds = 60
# Emit heartbeatsemit.heartbeats.enabled = trueemit.heartbeats.interval.seconds = 1Performance Tuning
Section titled “Performance Tuning”# Number of tasks (parallelism)tasks.max = 10
# Producer settings for replicationproducer.buffer.memory = 67108864producer.batch.size = 524288producer.linger.ms = 100producer.compression.type = lz4
# Consumer settingsconsumer.fetch.min.bytes = 1048576consumer.fetch.max.wait.ms = 500consumer.max.poll.records = 1000
# Offset sync frequencyoffset.lag.max = 100Naming Configuration
Section titled “Naming Configuration”# Replication policy (controls topic naming)replication.policy.class = org.apache.kafka.connect.mirror.DefaultReplicationPolicy
# Topic separator (default is ".")replication.policy.separator = .
# Custom replication policy example:# replication.policy.class = com.example.CustomReplicationPolicyTopic Naming
Section titled “Topic Naming”Default Naming (DefaultReplicationPolicy)
Section titled “Default Naming (DefaultReplicationPolicy)”Replicated topics are prefixed with the source cluster alias:
| Source Cluster | Source Topic | Target Topic |
|---|---|---|
east | orders | east.orders |
west | events | west.events |
prod | user.activity | prod.user.activity |
Identity Naming (IdentityReplicationPolicy)
Section titled “Identity Naming (IdentityReplicationPolicy)”Preserves original topic names (use with caution—requires careful loop prevention):
replication.policy.class = org.apache.kafka.connect.mirror.IdentityReplicationPolicy| Source Topic | Target Topic |
|---|---|
orders | orders |
Loop Prevention Required
IdentityReplicationPolicy requires explicit topic filtering to prevent replication loops in bidirectional setups.
Custom Replication Policy
Section titled “Custom Replication Policy”Implement custom naming logic:
public class CustomReplicationPolicy implements ReplicationPolicy {
@Override public String formatRemoteTopic(String sourceClusterAlias, String topic) { // Custom naming: replicated-<source>-<topic> return "replicated-" + sourceClusterAlias + "-" + topic; }
@Override public String topicSource(String topic) { if (topic.startsWith("replicated-")) { String[] parts = topic.split("-", 3); return parts.length >= 2 ? parts[1] : null; } return null; }
@Override public String upstreamTopic(String topic) { if (topic.startsWith("replicated-")) { String[] parts = topic.split("-", 3); return parts.length >= 3 ? parts[2] : null; } return null; }
@Override public boolean isInternalTopic(String topic) { return topic.endsWith(".internal") || topic.startsWith("__"); }}Offset Translation
Section titled “Offset Translation”How Offset Translation Works
Section titled “How Offset Translation Works”Source and target clusters have different offsets for the same logical data. MM2 maintains mappings via checkpoints.
Checkpoint Format
Section titled “Checkpoint Format”{ "consumer_group": "my-consumer-group", "topic": "orders", "partition": 0, "upstream_offset": 1000, "downstream_offset": 1000, "metadata": ""}Translating Offsets During Failover
Section titled “Translating Offsets During Failover”# View checkpointskafka-console-consumer.sh \ --bootstrap-server target:9092 \ --topic source.checkpoints.internal \ --from-beginning \ --property print.key=true \ --property key.separator=": "
# Use RemoteClusterUtils API for programmatic translation// Programmatic offset translationMap<TopicPartition, OffsetAndMetadata> translatedOffsets = RemoteClusterUtils.translateOffsets( targetProperties, "source", consumerGroupId, Duration.ofSeconds(30) );
// Reset consumer to translated offsetsconsumer.commitSync(translatedOffsets);Deployment Procedures
Section titled “Deployment Procedures”Initial Deployment
Section titled “Initial Deployment”- Create MM2 configuration file
clusters = source, targetsource.bootstrap.servers = source:9092target.bootstrap.servers = target:9092source->target.enabled = truesource->target.topics = .*replication.factor = 3- Start MirrorMaker 2
# Dedicated modeconnect-mirror-maker.sh mm2.properties
# Or as Connect connectorscurl -X POST -H "Content-Type: application/json" \ --data @mirror-source-connector.json \ http://connect:8083/connectors- Verify replication
# Check connector statuscurl http://connect:8083/connectors/MirrorSourceConnector/status
# Verify topics created on targetkafka-topics.sh --bootstrap-server target:9092 --list | grep "source\."
# Check replication lagkafka-consumer-groups.sh --bootstrap-server target:9092 \ --group connect-MirrorSourceConnector \ --describeAdding Topics to Replication
Section titled “Adding Topics to Replication”Topics matching the configured patterns are automatically replicated when created. To replicate additional existing topics:
- Update topic pattern:
source->target.topics = orders.*,events.*,new-topic-pattern.*-
Restart or reconfigure MM2
-
Verify new topics appear on target
Removing Topics from Replication
Section titled “Removing Topics from Replication”- Update exclusion pattern:
source->target.topics.exclude = .*internal,deprecated-topic-
Restart or reconfigure MM2
-
Optionally delete replicated topic from target:
kafka-topics.sh --bootstrap-server target:9092 \ --delete --topic source.deprecated-topicMonitoring
Section titled “Monitoring”Key Metrics
Section titled “Key Metrics”| Metric | Description | Alert Threshold |
|---|---|---|
kafka.connect.mirror.source.connector.record-count | Records replicated | Sudden drops |
kafka.connect.mirror.source.connector.record-age-ms | Age of last replicated record | > 60000 ms |
kafka.connect.mirror.source.connector.replication-latency-ms | End-to-end replication latency | > 30000 ms |
kafka.connect.mirror.source.connector.byte-count | Bytes replicated | Baseline deviation |
kafka.connect.mirror.checkpoint.connector.checkpoint-latency-ms | Checkpoint sync delay | > 120000 ms |
Health Checks
Section titled “Health Checks”# Connector statuscurl -s http://connect:8083/connectors/MirrorSourceConnector/status | jq .
# Task statuscurl -s http://connect:8083/connectors/MirrorSourceConnector/tasks/0/status | jq .
# Replication lagkafka-consumer-groups.sh --bootstrap-server target:9092 \ --group connect-MirrorSourceConnector \ --describe
# Heartbeat verificationkafka-console-consumer.sh --bootstrap-server target:9092 \ --topic heartbeats \ --from-beginning \ --max-messages 5Lag Monitoring Script
Section titled “Lag Monitoring Script”#!/bin/bashCONNECT_HOST="localhost:8083"TARGET_BOOTSTRAP="target:9092"
# Check connector statusSTATUS=$(curl -s "http://${CONNECT_HOST}/connectors/MirrorSourceConnector/status" | jq -r '.connector.state')echo "Connector status: ${STATUS}"
# Check consumer group lagkafka-consumer-groups.sh --bootstrap-server ${TARGET_BOOTSTRAP} \ --group connect-MirrorSourceConnector \ --describe 2>/dev/null | \ awk 'NR>1 {sum += $6} END {print "Total lag: " sum}'Failover Procedures
Section titled “Failover Procedures”Planned Failover
Section titled “Planned Failover”-
Stop producers to source cluster
-
Wait for replication to complete
# Check lag is zerokafka-consumer-groups.sh --bootstrap-server target:9092 \ --group connect-MirrorSourceConnector \ --describe-
Stop MirrorMaker 2
-
Translate consumer offsets
# For each consumer groupkafka-consumer-groups.sh --bootstrap-server target:9092 \ --group my-app \ --reset-offsets \ --to-offset <translated-offset> \ --topic source.my-topic \ --execute-
Redirect applications to target cluster
-
Start consumers on target cluster
Unplanned Failover
Section titled “Unplanned Failover”-
Detect source cluster failure
-
Stop MirrorMaker 2 (prevent split-brain when source recovers)
-
Assess data loss
# Compare last checkpoint with consumer positionkafka-console-consumer.sh --bootstrap-server target:9092 \ --topic source.checkpoints.internal \ --from-beginning | tail -n 100-
Translate offsets using last known checkpoint
-
Accept potential data loss (records between last checkpoint and failure)
-
Redirect applications
-
Start consumers
Failback Procedure
Section titled “Failback Procedure”-
Restore source cluster
-
Configure reverse replication (target -> source)
-
Replicate changes made during outage
-
Stop reverse replication
-
Redirect applications back to source
-
Resume normal replication (source -> target)
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”| Issue | Symptoms | Resolution |
|---|---|---|
| Connector not starting | FAILED state | Check logs, verify connectivity, check credentials |
| High replication lag | Increasing lag metric | Increase tasks.max, tune producer/consumer settings |
| Topics not replicating | Missing topics on target | Verify topic pattern matches, check ACLs |
| Offset sync failing | Checkpoint connector errors | Verify consumer groups exist, check permissions |
| Authentication failures | SASL errors in logs | Verify credentials, check JAAS config |
Diagnostic Commands
Section titled “Diagnostic Commands”# View connector logsdocker logs kafka-connect 2>&1 | grep -i mirror
# Check source cluster connectivitykafka-broker-api-versions.sh --bootstrap-server source:9092
# Verify topic exists on sourcekafka-topics.sh --bootstrap-server source:9092 --describe --topic my-topic
# Check target cluster ACLskafka-acls.sh --bootstrap-server target:9092 --list
# Test producer to targetecho "test" | kafka-console-producer.sh --bootstrap-server target:9092 --topic test-topicPerformance Issues
Section titled “Performance Issues”# Check task distributioncurl -s http://connect:8083/connectors/MirrorSourceConnector/tasks | jq .
# Monitor network throughputiftop -i eth0 -f "port 9092"
# Check producer metricscurl -s http://connect:8083/connectors/MirrorSourceConnector/tasks/0/status | jq '.trace'Configuration Examples
Section titled “Configuration Examples”Active-Passive DR
Section titled “Active-Passive DR”clusters = primary, drprimary.bootstrap.servers = primary-1:9092,primary-2:9092,primary-3:9092dr.bootstrap.servers = dr-1:9092,dr-2:9092,dr-3:9092
primary->dr.enabled = trueprimary->dr.topics = .*primary->dr.topics.exclude = .*\.internal, __.*primary->dr.groups = .*
sync.group.offsets.enabled = trueemit.checkpoints.enabled = true
replication.factor = 3tasks.max = 10Active-Active Bidirectional
Section titled “Active-Active Bidirectional”Active-active replication requires careful provenance configuration to prevent infinite replication loops and enable consumers to distinguish data origins.
How Provenance Works
Section titled “How Provenance Works”The DefaultReplicationPolicy automatically handles provenance by prefixing replicated topics with the source cluster alias:
Loop Prevention: MM2 never replicates prefixed topics. east.orders in the West cluster is not replicated back to East because it already has the east. prefix, indicating it originated from East.
Configuration
Section titled “Configuration”clusters = east, westeast.bootstrap.servers = east-1:9092,east-2:9092,east-3:9092west.bootstrap.servers = west-1:9092,west-2:9092,west-3:9092
# East to Westeast->west.enabled = trueeast->west.topics = orders, events, users
# West to Eastwest->east.enabled = truewest->east.topics = orders, events, users
# Use DefaultReplicationPolicy (default) - adds cluster prefixreplication.policy.class = org.apache.kafka.connect.mirror.DefaultReplicationPolicy
# Both directionssync.group.offsets.enabled = trueemit.checkpoints.enabled = trueemit.heartbeats.enabled = true
replication.factor = 3tasks.max = 6Topic Naming Results
Section titled “Topic Naming Results”| Cluster | Local Topic | Replicated From | Resulting Topic |
|---|---|---|---|
| East | orders | - | orders |
| East | - | West | west.orders |
| West | orders | - | orders |
| West | - | East | east.orders |
Consumer Configuration for Global View
Section titled “Consumer Configuration for Global View”Consumers that need to see all data from both clusters must subscribe to both local and replicated topics:
// Consumer in East cluster wanting all orders globallyconsumer.subscribe(Arrays.asList( "orders", // Local East orders "west.orders" // Replicated West orders));
// Process with origin awarenessfor (ConsumerRecord<String, Order> record : records) { String origin = record.topic().startsWith("west.") ? "west" : "east"; processOrder(record.value(), origin);}Conflict Avoidance Strategies
Section titled “Conflict Avoidance Strategies”| Strategy | Description | Configuration |
|---|---|---|
| Topic prefixing | Each DC writes to local topic, reads both | Default behavior |
| Key partitioning | Route specific keys to owning DC | Application-level routing |
| Last-write-wins | Accept all writes, latest timestamp wins | Application-level merge |
Recommended Pattern
Use the default DefaultReplicationPolicy with topic prefixing. Have consumers subscribe to both local and prefixed topics. This provides clear provenance with no additional configuration.
Fan-Out (One to Many)
Section titled “Fan-Out (One to Many)”clusters = central, region-us, region-eu, region-apac
central.bootstrap.servers = central:9092region-us.bootstrap.servers = us:9092region-eu.bootstrap.servers = eu:9092region-apac.bootstrap.servers = apac:9092
central->region-us.enabled = truecentral->region-us.topics = global-.*
central->region-eu.enabled = truecentral->region-eu.topics = global-.*
central->region-apac.enabled = truecentral->region-apac.topics = global-.*
replication.factor = 3Aggregation (Many to One)
Section titled “Aggregation (Many to One)”clusters = region-us, region-eu, region-apac, central
region-us.bootstrap.servers = us:9092region-eu.bootstrap.servers = eu:9092region-apac.bootstrap.servers = apac:9092central.bootstrap.servers = central:9092
region-us->central.enabled = trueregion-us->central.topics = events
region-eu->central.enabled = trueregion-eu->central.topics = events
region-apac->central.enabled = trueregion-apac->central.topics = events
# Central sees: region-us.events, region-eu.events, region-apac.eventsreplication.factor = 3Related Documentation
Section titled “Related Documentation”- Multi-Datacenter Concepts - Architecture patterns
- Kafka Connect - Connect framework
- Cluster Management - Operational procedures
- Monitoring - Metrics and alerting