Guide · AWS MSK Replication
MSK Replication for MCP Servers — Cross-Region DR, Replication Factor, and Producer Acks
MSK Replication (generally available since 2024) copies topics from a source MSK cluster to a destination cluster in a different region, enabling active-passive disaster recovery for MCP probe pipelines. Unlike MirrorMaker2, which requires you to run and manage the connector yourself, MSK Replication is a fully managed replication service: you define the source cluster, destination cluster, and which topics to replicate via an MSKReplicationInfo resource — AWS handles the replication process. However, MSK Replication is only available on provisioned MSK clusters; MSK Serverless clusters cannot be a source or destination. For in-region durability, the more important levers are replication factor (how many broker copies exist per partition) and producer acks (how many replicas must acknowledge a write before the producer considers it durable).
TL;DR
Use replication.factor=3 with min.insync.replicas=2 and producer acks=all for durable probe result ingestion. This guarantees that a write is lost only if two of the three brokers fail simultaneously before the write is consumed. For cross-region DR, enable MSK Replication on your provisioned cluster and point a standby consumer group at the destination cluster. Monitor ReplicationByteLag in CloudWatch — an increasing lag means the destination cluster is falling behind the source. On failover, restart the consumer group from the last committed offset on the destination cluster; expect a brief replay of the lag window.
Replication factor and in-sync replicas
The replication factor (RF) is the number of broker copies for each partition. For a 3-broker cluster, RF=3 means all three brokers hold a copy of every partition. The in-sync replica set (ISR) is the subset of replicas that are caught up to within the replica lag threshold — by default, any replica that is more than 30 seconds behind the leader is removed from the ISR.
min.insync.replicas (ISR) controls the minimum number of ISR members required before a producer write with acks=all is acknowledged. With RF=3 and min.insync.replicas=2:
- The cluster can tolerate one broker failure (ISR drops from 3 to 2, still meets the minimum of 2)
- If a second broker fails, the ISR drops to 1, which is below min.insync.replicas=2 — the topic becomes unavailable for
acks=allproducers (they receiveNotEnoughReplicasException) - Consumers can still read from the leader even when ISR < min.insync.replicas
| Configuration | Durability | Availability trade-off | Recommended for… |
|---|---|---|---|
| RF=1, acks=1 | Data lost if broker fails before consume | Highest availability (single broker) | Development/staging only |
| RF=3, min.ISR=1, acks=1 | Data lost if leader fails before followers catch up | Good: partition available with 1 live broker | Probe command topics (low value, can miss one) |
| RF=3, min.ISR=2, acks=all | Data lost only if 2 of 3 brokers fail simultaneously | Partition unavailable if <2 brokers live | Probe result topics (durable, must not drop) |
| RF=3, min.ISR=3, acks=all | Maximum durability: all 3 must ack | Unavailable if any broker fails | Audit/compliance topics only |
Producer acks: three settings compared
The acks producer config controls which acknowledgement the broker sends back before the producer considers a send complete:
| acks setting | Who acknowledges | Durability | Latency |
|---|---|---|---|
acks=0 | Nobody — fire and forget | Zero: message lost on any network blip | Lowest (no round-trip wait) |
acks=1 | Partition leader only | Message survives if leader does not fail within the replication window | Low (one network hop) |
acks=all (or acks=-1) | All ISR members (subject to min.insync.replicas) | Message survives unless more than (RF − min.ISR) brokers fail simultaneously | Higher (waits for all ISR acks) |
The interaction with retries: with acks=all, a producer that gets a NotEnoughReplicasException (ISR < min.insync.replicas) will retry if retries > 0. Set retries=Integer.MAX_VALUE or a high value with delivery.timeout.ms to bound the total retry window. For probe result ingestion, a 30-second delivery timeout aligns with the 60-second probe cycle — if the write hasn't succeeded in 30 seconds, the result is dropped and the next probe will re-verify the endpoint status.
// CDK: MSK cluster with RF=3 and min.insync.replicas=2
import { aws_msk as msk } from 'aws-cdk-lib';
const clusterConfig = new msk.ClusterConfigurationProperty({
// MSK configuration resource (applied to cluster)
// Set default topic-level min.insync.replicas
serverProperties: [
'min.insync.replicas=2',
'default.replication.factor=3',
'auto.create.topics.enable=false', // prevent accidental topic creation
].join('\n'),
});
const cluster = new msk.CfnCluster(this, 'ProbeCluster', {
clusterName: 'alivemcp-probe-us-east-1',
kafkaVersion: '3.6.0',
numberOfBrokerNodes: 3,
brokerNodeGroupInfo: { /* ... */ },
configurationInfo: {
arn: clusterConfig.ref,
revision: 1,
},
encryptionInfo: {
encryptionInTransit: { clientBroker: 'TLS', inCluster: true },
},
});
MSK Replication: cross-region active-passive setup
MSK Replication copies topics from a source cluster to a destination cluster in a different region. The destination cluster is read-only during normal operations — probe result consumers are directed to the destination cluster only during failover. To configure MSK Replication:
- Create a destination MSK cluster in the DR region (eu-west-1 for us-east-1 primary). It does not need the same broker count — a smaller cluster is fine for standby.
- Create an MSK Replicator resource in the source region specifying source cluster ARN, destination cluster ARN, and topic patterns.
- Grant the MSK Replication service IAM permissions to read from the source and write to the destination cluster.
// CloudFormation / CDK L1 for MSK Replication
// (No CDK L2 construct as of late 2026 — use CfnReplicator)
import { aws_msk as msk } from 'aws-cdk-lib';
const replicator = new msk.CfnReplicator(this, 'ProbeResultReplicator', {
replicatorName: 'probe-results-us-to-eu',
description: 'Replicate probe result topics to EU DR cluster',
serviceExecutionRoleArn: replicationRole.roleArn,
kafkaClusters: [
{
amazonMskCluster: { mskClusterArn: sourceClusterArn },
vpcConfig: { subnetIds: sourceSubnetIds, securityGroupIds: [sourceSgId] },
},
{
amazonMskCluster: { mskClusterArn: destClusterArn },
vpcConfig: { subnetIds: destSubnetIds, securityGroupIds: [destSgId] },
},
],
replicationInfoList: [{
sourceKafkaClusterArn: sourceClusterArn,
targetKafkaClusterArn: destClusterArn,
targetCompressionType: 'SNAPPY',
topicReplication: {
topicsToReplicate: ['probe-results', 'alert-dispatch', 'audit-events'],
detectAndCopyNewTopics: true,
copyTopicConfigurations: true,
},
consumerGroupReplication: {
consumerGroupsToReplicate: ['probe-archiver', 'alert-worker'],
detectAndCopyNewConsumerGroups: true,
synchroniseConsumerGroupOffsets: true,
},
}],
});
With synchroniseConsumerGroupOffsets: true, MSK Replication translates source-cluster offsets to destination-cluster offsets and writes them to the __consumer_offsets topic on the destination. On failover, a consumer pointed at the destination cluster resumes from the translated offset — you do not need to manually reset offsets.
Monitoring replication lag
MSK Replication emits the ReplicationByteLag CloudWatch metric (bytes) per topic partition. A lag value that grows over time indicates the destination is falling behind — the DR cluster would not be a safe failover target until it catches up.
// CDK alarm: alert if replication lag exceeds 50 MB on any partition
import { aws_cloudwatch as cloudwatch, aws_cloudwatch_actions as cw_actions } from 'aws-cdk-lib';
new cloudwatch.Alarm(this, 'ReplicationLagAlarm', {
alarmName: 'msk-probe-replication-lag',
metric: new cloudwatch.Metric({
namespace: 'AWS/MSK/Replicator',
metricName: 'ReplicationByteLag',
dimensionsMap: {
ReplicatorName: 'probe-results-us-to-eu',
},
statistic: 'Maximum',
period: cdk.Duration.minutes(1),
}),
threshold: 50 * 1024 * 1024, // 50 MB
evaluationPeriods: 3, // sustained for 3 minutes
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
alarmDescription: 'MSK DR replication falling behind — failover would replay this lag on resume',
});
Common failure modes
| Symptom | Cause | Fix |
|---|---|---|
Producer receives NotEnoughReplicasException | Cluster ISR count dropped below min.insync.replicas (e.g., one broker restarting) | Expected during broker rolling restart; configure producer delivery.timeout.ms=30000 to wait for restart to complete. Reduce min.insync.replicas to 1 only for non-critical topics. |
UnderReplicatedPartitions metric > 0 for extended period | A follower broker is not catching up — could be network partition or disk pressure | Inspect broker logs; check ReplicaMaxLag; if a broker is permanently unhealthy, replace the broker node |
MSK Replication fails with AccessDenied | Replication IAM role missing permissions on source or destination cluster | Add kafka:DescribeCluster, kafka:GetBootstrapBrokers, and kafka-cluster:* actions for both cluster ARNs to the service execution role |
| Consumer on destination cluster reads duplicate messages after failover | Replication lag at failover time — destination consumer resumes behind source committed offset | Expected: the consumer will replay the lag window. Make consumer idempotent (upsert by probe run ID) so replays are safe. |
| MSK Replication only available on provisioned; using MSK Serverless | MSK Replication does not support MSK Serverless clusters as source or destination | Implement a consumer-producer bridge Lambda that reads from the Serverless source cluster and writes to a provisioned destination cluster in the DR region |