🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

MSK Connect for Data Engineers

AWS Data EngineeringManaged Kafka Connect on AWS⭐ Premium

Advertisement

MSK Connect for Data Engineers

Managed Kafka Connect on AWS - Seamless Data Integration Between Apache Kafka and External Systems

14 min readIntermediate

Why This Matters

MSK Connect eliminates the operational burden of running Kafka Connect infrastructure. It enables seamless data movement between Apache Kafka and external systems like databases, S3, and search engines. Understanding MSK Connect architecture, connector patterns, and error handling is essential for building reliable streaming data integration pipelines that scale automatically and handle failures gracefully. MSK Connect supports hundreds of pre-built connectors and custom plugins for any data source.


MSK Connect Architecture

MSK Connect ArchitectureSource SystemsRDS, DynamoDBS3, MongoDBSource ConnectorMSK Connect Worker GroupWorker 1Tasks 1-2Worker 2Tasks 3-4Worker 3Tasks 5-6Connector PluginsManaged ConnectorsCustom JAR/ZIPS3-hosted pluginsSMTsInsertFieldMaskFieldTimestampRouterError HandlingDead Letter QueueRetry PoliciesError ToleranceAmazon MSKKafka TopicsBroker ClusterSink Connectors: S3, Redshift, OpenSearch, DynamoDB, JDBCRecords flow from MSK topics through sink connectors to external destinationsOffsets tracked automatically for exactly-once semantics | DLQ for failed recordsCloudWatch metrics for monitoring throughput, errors, and capacity utilization

Real-World Project Structure

Architecture Diagram
msk-connect-project/
+-- connectors/
�   +-- rds-source/
�   �   +-- connector-config.json
�   �   +-- custom-plugin.zip
�   �   +-- deploy.sh
�   +-- s3-sink/
�   �   +-- connector-config.json
�   �   +-- custom-plugin.zip
�   �   +-- deploy.sh
�   +-- opensearch-sink/
�       +-- connector-config.json
�       +-- deploy.sh
+-- plugins/
�   +-- debezium-postgres-2.4.zip
�   +-- confluent-s3-sink-10.7.zip
�   +-- custom-transforms.zip
+-- deploy/
�   +-- create-connector.sh
�   +-- update-connector.sh
�   +-- delete-connector.sh
�   +-- cfn-template.yaml
+-- monitoring/
�   +-- cloudwatch-dashboard.json
�   +-- alarms.yaml
�   +-- custom_metrics.py
+-- tests/
    +-- test-connectors.sh
    +-- validate-config.py

Source vs Sink Connectors

AspectSource ConnectorSink Connector
DirectionExternal system to MSK topicMSK topic to external system
Common UseCDC from databases, log ingestionData lake writes, search indexing
Offset TrackingSource system positionKafka consumer offset
Key SMTsTimestampRouter, RegexRouterFlatten, InsertField
Error HandlingRetry with backoffDLQ for failed records
ThroughputLimited by sourceLimited by sink

Source Connector Configuration

{
  "name": "my-rds-source",
  "kafkaConnectVersion": "2.7.1",
  "capacity": {
    "provisionedThroughput": {
      "readCapacityUnits": 10,
      "writeCapacityUnits": 10
    }
  },
  "plugin": {
    "customPluginArn": "arn:aws:kafkaconnect:us-east-1:123456789012:custom-plugin/my-rds-connector"
  },
  "connectorConfiguration": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "my-rds-instance.cluster-xxxx.us-east-1.rds.amazonaws.com",
    "database.port": "5432",
    "database.user": "admin",
    "database.password": "secretsmanager:arn:aws:secretsmanager:us-east-1:123456789012:secret:db-cred:password::",
    "database.dbname": "mydb",
    "database.server.name": "myserver",
    "plugin.name": "pgoutput",
    "topic.prefix": "cdc"
  }
}

Sink Connector Configuration

{
  "name": "my-s3-sink",
  "kafkaConnectVersion": "2.7.1",
  "capacity": {
    "provisionedThroughput": {
      "readCapacityUnits": 10,
      "writeCapacityUnits": 10
    }
  },
  "plugin": {
    "customPluginArn": "arn:aws:kafkaconnect:us-east-1:123456789012:custom-plugin/my-s3-sink"
  },
  "connectorConfiguration": {
    "connector.class": "io.confluent.connect.s3.S3SinkConnector",
    "s3.bucket.name": "my-kafka-data-bucket",
    "s3.region": "us-east-1",
    "topics": "cdc.server1.users",
    "format.class": "io.confluent.connect.s3.format.parquet.ParquetFormat",
    "partitioner.class": "io.confluent.connect.storage.partitioner.TimeBasedPartitioner",
    "path.format": "'year'=YYYY/'month'=MM/'day'=dd",
    "flush.size": "1000",
    "rotate.interval.ms": "60000"
  }
}

Custom Connector Deployment

Step-by-Step Process

# Step 1: Package connector with dependencies
mvn clean package
mkdir -p /tmp/connector-plugin
cp target/my-custom-connector-1.0.jar /tmp/connector-plugin/
cp target/dependency/*.jar /tmp/connector-plugin/
cd /tmp/connector-plugin && zip -r my-custom-connector.zip .

# Step 2: Upload to S3
aws s3 cp my-custom-connector.zip s3://my-connectors-bucket/plugins/my-custom-connector.zip

# Step 3: Register as MSK Connect plugin
aws kafkaconnect create-custom-plugin \
  --name my-custom-connector \
  --content-type ZIP \
  --location-s3-location "{
    \"bucketArn\": \"arn:aws:s3:::my-connectors-bucket\",
    \"objectKey\": \"plugins/my-custom-connector.zip\"
  }"

# Step 4: Create connector
aws kafkaconnect create-connector \
  --connector-name my-connector \
  --connector-configuration file://connector-config.json \
  --kafkaconnect-version 2.7.1 \
  --connector-plugin "{
    \"customPluginArn\": \"arn:aws:kafkaconnect:us-east-1:123456789012:custom-plugin/my-custom-connector\"
  }" \
  --capacity "{
    \"provisionedThroughput\": {
      \"readCapacityUnits\": 10,
      \"writeCapacityUnits\": 10
    }
  }" \
  --worker-configuration "{
    \"workerConfigurationArn\": \"arn:aws:kafkaconnect:us-east-1:123456789012:worker-configuration/my-workers\"
  }" \
  --kafka-cluster "{
    \"apacheKafkaCluster\": {
      \"bootstrapServers\": \"b-1.mycluster.abc123.c2.kafka.us-east-1.amazonaws.com:9092\",
      \"vpc\": {
        \"securityGroups\": [\"sg-0123456789abcdef0\"],
        \"subnets\": [\"subnet-0123456789abcdef0\"]
      }
    }
  }"

Single Message Transforms (SMTs)

SMTPurposeExample Use
InsertFieldAdd a fieldAdd processing timestamp
ReplaceFieldRename or remove fieldsDrop PII columns
MaskFieldMask sensitive valuesMask email addresses
TimestampRouterRoute to time-based topicsPartition by date
RegexRouterRoute by patternSend to environment topics
HoistFieldWrap record in new fieldRestructure payload
{
  "transforms": "insertTimestamp,maskEmail",
  "transforms.insertTimestamp.type": "org.apache.kafka.connect.transforms.InsertField$Value",
  "transforms.insertTimestamp.timestamp.field": "event_timestamp",
  "transforms.maskEmail.type": "org.apache.kafka.connect.transforms.MaskField$Value",
  "transforms.maskEmail.fields": "email",
  "transforms.maskEmail.replacement": "*****"
}

Performance Considerations

MetricDescriptionTarget
bytesReadPerSecData read rate (source)Match source capacity
bytesWrittenPerSecData write rate (sink)Match sink capacity
recordsReadPerSecRecord read rateMonitor for lag
recordsWrittenPerSecRecord write rateMonitor throughput
ErrorCountNumber of errors< 1% of records
ProvisionedCapacityUnitsCurrent provisioned capacityMatch consumed
ConsumedCapacityUnitsActual consumed capacityBelow provisioned
Task StatusRunning/Failed/PausedAll running

Security Considerations

ConcernImplementation
AuthenticationIAM roles for MSK and connector access
AuthorizationMSK ACLs for topic-level access
Encryption in TransitTLS 1.2+ for worker-to-broker communication
Secrets ManagementReference Secrets Manager in connector configs
Network SecurityVPC deployment, security groups, private subnets
Audit LoggingCloudTrail for all MSK Connect API calls
Access ControlsIAM policies with least-privilege
Data ResidencyDeploy in specific regions

Interview Questions and Answers

Q1: What is MSK Connect and how does it relate to Kafka Connect?

Answer: MSK Connect is a fully managed AWS service that runs Kafka Connect connectors on Amazon MSK clusters. Kafka Connect is the open-source framework for streaming data between Kafka and other systems. MSK Connect handles all the infrastructure management - provisioning workers, scaling, patching, and failover - so you only need to define connector configurations. It eliminates the operational overhead of self-managing Kafka Connect clusters.

Q2: What is the difference between a source connector and a sink connector?

Answer: A source connector reads data from an external system (like a database, S3 bucket, or API) and writes it to an MSK topic. A sink connector reads data from an MSK topic and writes it to an external destination (like S3, Redshift, or OpenSearch). Source connectors are the entry point for data into Kafka; sink connectors are the exit point. Understanding this distinction is fundamental to designing data flow architectures.

Q3: How does MSK Connect handle scaling?

Answer: MSK Connect automatically scales the number of workers based on throughput. You define minimum and maximum capacity bounds, and MSK Connect adds or removes workers to match actual demand. This is driven by CloudWatch metrics like ConsumedCapacityUnits vs. ProvisionedCapacityUnits. Start conservative with capacity, monitor metrics, and adjust bounds based on observed traffic patterns.

Q4: What is a Dead Letter Queue (DLQ) in MSK Connect?

Answer: A DLQ is a Kafka topic where records that cannot be processed by a sink connector are sent instead of being discarded. This commonly happens due to schema mismatches, serialization errors, or data validation failures. DLQs allow you to inspect failed records and reprocess them later without losing data. Configure with errors.tolerance: all and errors.deadletterqueue.topic.name.

Q5: What are Single Message Transforms (SMTs)?

Answer: SMTs are lightweight, record-level transformations that are applied as data flows through a connector. They run inside the connector worker process and are defined in the connector configuration. Common uses include adding timestamps, masking sensitive fields, renaming fields, and routing records to different topics. For heavier transformations, use Kafka Streams or Lambda instead.

Q6: How do you deploy a custom connector to MSK Connect?

Answer: (1) Develop and test your connector locally. (2) Package it as a JAR or ZIP with all dependencies. (3) Upload the package to an S3 bucket. (4) Register it as a custom plugin using the CreateCustomPlugin API. (5) Create a connector configuration that references the plugin ARN. MSK Connect will download and run the plugin on managed workers. Always version your plugins for rollback capability.

Q7: How does MSK Connect ensure exactly-once delivery?

Answer: For source connectors, MSK Connect tracks offsets in the external system and commits them atomically with Kafka produces, so records are not duplicated on restart. For sink connectors, Kafka consumer offsets are committed only after successful writes to the destination. This coordination ensures exactly-once semantics within the connector framework, though end-to-end exactly-once depends on the external system capabilities.

Q8: When would you use MSK Connect versus Kinesis Data Firehose?

Answer: Use MSK Connect when your data pipeline is centered around Apache Kafka and you need to integrate external systems with Kafka topics using the Kafka Connect ecosystem. Use Kinesis Data Firehose when you need a simpler, fully managed delivery stream to S3, Redshift, OpenSearch, or HTTP endpoints without managing a Kafka cluster. MSK Connect is better for complex, bidirectional Kafka-integrated workflows; Firehose is better for straightforward delivery pipelines.


Common Pitfalls

PitfallImpactSolution
Not configuring DLQData loss on errorsAlways enable DLQ with error tolerance
Ignoring SMT performanceSlow connector throughputUse SMTs for lightweight ops only
Hardcoded secretsSecurity riskUse Secrets Manager references
Over-provisioning capacityUnnecessary costStart conservative, monitor and adjust
Not versioning pluginsNo rollback capabilityUse S3 object versioning
Missing CloudWatch alarmsBlind to failuresSet up alarms for ErrorCount and status
Not testing locallyProduction failuresTest with connect-distributed first
Ignoring task parallelismBottlenecksConfigure task count per connector


See Also

Additional Deep Dive: Connector Lifecycle Management

Connector States

StateDescriptionAction Required
RUNNINGConnector is processing data normallyMonitor metrics
PAUSEDConnector has been paused by userResume or investigate
FAILEDConnector has encountered an errorCheck logs, fix config
RESTARTINGConnector is restarting after failureWait for completion
DELETINGConnector is being deletedNone
UPDATINGConnector is being updatedWait for completion

Connector Monitoring Script

import boto3

def monitor_msk_connectors(cluster_arn: str):
    """Monitor MSK Connect connectors and report health status."""
    client = boto3.client('kafkaconnect')

    try:
        response = client.list_connectors(
            kafkaClusterArn=cluster_arn
        )

        for connector in response.get('connectors', []):
            name = connector['connectorName']
            state = connector['connectorState']
            print(f"Connector: {name}, State: {state}")

            if state == 'FAILED':
                print(f"  WARNING: {name} is in FAILED state")
                # Get connector status for more details
                status = client.describe_connector(
                    connectorArn=connector['connectorArn']
                )
                print(f"  Status: {status['connectorStatus']}")

    except Exception as e:
        print(f"Error monitoring connectors: {str(e)}")
        raise

Scaling Configuration

import boto3

def update_connector_capacity(connector_arn: str, read_units: int, write_units: int):
    """Update MSK Connect connector capacity."""
    client = boto3.client('kafkaconnect')

    try:
        response = client.update_connector(
            connectorArn=connector_arn,
            capacityUpdate={
                'provisionedThroughput': {
                    'readCapacityUnits': read_units,
                    'writeCapacityUnits': write_units
                }
            }
        )
        print(f"Capacity updated: {response}")
    except Exception as e:
        print(f"Error updating capacity: {str(e)}")
        raise

Common SMT Configurations

{
  "transforms": "addTimestamp,maskPII,routeToTopic",
  "transforms.addTimestamp.type": "org.apache.kafka.connect.transforms.InsertField$Value",
  "transforms.addTimestamp.timestamp.field": "processed_at",
  "transforms.maskPII.type": "org.apache.kafka.connect.transforms.MaskField$Value",
  "transforms.maskPII.fields": "ssn,credit_card",
  "transforms.maskPII.replacement": "MASKED",
  "transforms.routeToTopic.type": "org.apache.kafka.connect.transforms.RegexRouter$Value",
  "transforms.routeToTopic.regex": ".*",
  "transforms.routeToTopic.replacement": "processed-${topic}"
}

Error Handling Configuration

{
  "errors.tolerance": "all",
  "errors.deadletterqueue.topic.name": "dlq-connect-errors",
  "errors.deadletterqueue.topic.replication.factor": "3",
  "errors.deadletterqueue.context.headers.enable": true,
  "errors.log.enable": true,
  "errors.log.include.messages": true,
  "errors.log.exclude.messages": false,
  "errors.retry.timeout": 30000,
  "errors.retry.delay.max.ms": 60000
}

Worker Configuration

{
  "key.converter": "org.apache.kafka.connect.json.JsonConverter",
  "value.converter": "org.apache.kafka.connect.json.JsonConverter",
  "key.converter.schemas.enable": true,
  "value.converter.schemas.enable": true,
  "tasks.max": 10,
  "heartbeat.interval.ms": 30000,
  "session.timeout.ms": 180000,
  "max.poll.interval.ms": 300000
}

Connector Health Check Script

#!/bin/bash
# MSK Connect health check script

CONNECTOR_NAME=$1
REGION=${2:-us-east-1}

echo "Checking health of connector: $CONNECTOR_NAME"

# Get connector status
STATUS=$(aws kafkaconnect describe-connector \
    --connector-arn "arn:aws:kafkaconnect:${REGION}:123456789012:connector/${CONNECTOR_NAME}" \
    --region ${REGION} \
    --query 'connectorStatus.connectorState' \
    --output text)

echo "Connector Status: $STATUS"

if [ "$STATUS" = "FAILED" ]; then
    echo "CRITICAL: Connector is in FAILED state"
    exit 1
elif [ "$STATUS" = "PAUSED" ]; then
    echo "WARNING: Connector is paused"
    exit 2
elif [ "$STATUS" = "RUNNING" ]; then
    echo "OK: Connector is running normally"
    exit 0
else
    echo "UNKNOWN: Connector status is $STATUS"
    exit 3
fi

CloudWatch Alarm Setup

# Create alarm for connector errors
aws cloudwatch put-metric-alarm \
    --alarm-name "MSKConnect-HighErrorRate" \
    --alarm-description "Alarm when MSK Connect error rate exceeds threshold" \
    --metric-name "ErrorCount" \
    --namespace "AWS/KafkaConnect" \
    --statistic Sum \
    --period 300 \
    --evaluation-periods 2 \
    --threshold 100 \
    --comparison-operator GreaterThanOrEqualToThreshold \
    --dimensions Name=ConnectorName,Value=my-connector \
    --alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts \
    --region us-east-1

# Create alarm for connector status
aws cloudwatch put-metric-alarm \
    --alarm-name "MSKConnect-ConnectorFailed" \
    --alarm-description "Alarm when connector enters FAILED state" \
    --metric-name "ConnectorStatus" \
    --namespace "AWS/KafkaConnect" \
    --statistic Maximum \
    --period 300 \
    --evaluation-periods 1 \
    --threshold 1 \
    --comparison-operator GreaterThanOrEqualToThreshold \
    --dimensions Name=ConnectorName,Value=my-connector \
    --alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts \
    --region us-east-1

Performance Tuning Guide

ConfigurationRecommended ValueImpact
tasks.max5-10 per connectorParallelism level
batch.size1000-5000Records per batch
linger.ms100-500Batch collection time
buffer.memory32MB-64MBBuffer size
max.block.ms60000Max wait time
compression.typelz4Compression for network
fetch.min.bytes1Minimum fetch size
fetch.max.wait.ms500Max wait for fetch

Integration Patterns

PatternDescriptionUse Case
CDCChange Data CaptureDatabase replication
Event SourcingImmutable event logAudit trails
Data Lake IngestionBatch and streamingS3 data lake
Search IndexingReal-time indexingOpenSearch/Elasticsearch
Cache PopulationReal-time cache updatesRedis/Memcached
API IntegrationEvent-driven APIsMicroservices
🔒

Premium Content

MSK Connect for Data Engineers

You've previewed the first section. Unlock this full lesson and 900+ advanced tutorials with a Premium plan.

🎯End-to-end Projects
💼Interview Prep
📜Certificates
🤝Community Access

Already a member? Log in

Advertisement