Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka on AWS

Production deployment guide for Apache Kafka on Amazon Web Services.


Kafka brokers across three availability zones with EBS gp3 volumesKafka brokers across three availability zones with EBS gp3 volumesAWS RegionVPCAZ-aAZ-bAZ-cClient VPCBroker 1EBS gp3Broker 2EBS gp3Broker 3EBS gp3ProducersConsumersReplicationReplicationReplication

WorkloadInstance TypevCPUsMemoryNetworkUse Case
Developmentm6i.large28 GBUp to 12.5 GbpsTesting
Small Productionm6i.xlarge416 GBUp to 12.5 GbpsLow throughput
Medium Productionm6i.2xlarge832 GBUp to 12.5 GbpsModerate throughput
Large Productionr6i.4xlarge16128 GBUp to 12.5 GbpsHigh throughput
High Performancei3en.2xlarge864 GBUp to 25 GbpsI/O intensive
  • Network-optimized instances (m6i, r6i) should be used for most deployments
  • Storage-optimized instances (i3en, d3en) may be used for I/O-intensive workloads
  • Memory-optimized instances (r6i) should be used when large page cache is required
  • A minimum of 3 brokers should be deployed across 3 availability zones

Volume TypeIOPSThroughputUse Case
gp33,000-16,000125-1,000 MB/sRecommended default
io2Up to 64,000Up to 4,000 MB/sHigh-performance
st1Baseline 40 MB/s per TBUp to 500 MB/sCold data, cost-optimized
Terminal window
# Create gp3 volume with custom IOPS and throughput
aws ec2 create-volume \
--availability-zone us-east-1a \
--volume-type gp3 \
--size 1000 \
--iops 6000 \
--throughput 500 \
--encrypted \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=kafka-data}]'
MetricRecommendation
Volume Size10x daily data volume
IOPS3,000 + (500 × partitions per broker)
Throughput2x expected peak MB/s
Terminal window
# Format with XFS
mkfs.xfs /dev/nvme1n1
# Mount options for Kafka
echo '/dev/nvme1n1 /kafka xfs noatime,nodiratime 0 2' >> /etc/fstab
mount /kafka
# Create Kafka directories
mkdir -p /kafka/data
chown -R kafka:kafka /kafka

Terminal window
# Create VPC
aws ec2 create-vpc --cidr-block 10.0.0.0/16
# Create subnets in each AZ
aws ec2 create-subnet --vpc-id vpc-xxx --cidr-block 10.0.1.0/24 --availability-zone us-east-1a
aws ec2 create-subnet --vpc-id vpc-xxx --cidr-block 10.0.2.0/24 --availability-zone us-east-1b
aws ec2 create-subnet --vpc-id vpc-xxx --cidr-block 10.0.3.0/24 --availability-zone us-east-1c
Terminal window
# Kafka broker security group
aws ec2 create-security-group \
--group-name kafka-brokers \
--description "Kafka broker security group" \
--vpc-id vpc-xxx
# Allow inter-broker communication
aws ec2 authorize-security-group-ingress \
--group-id sg-xxx \
--protocol tcp \
--port 9092-9094 \
--source-group sg-xxx
# Allow client access
aws ec2 authorize-security-group-ingress \
--group-id sg-xxx \
--protocol tcp \
--port 9092 \
--cidr 10.0.0.0/16

Ports depend on your listener configuration; the table below shows common defaults.

PortProtocolPurpose
9092TCPClient or inter-broker (PLAINTEXT example)
9093TCPClient or inter-broker (SSL)
9094TCPClient or inter-broker (SASL_SSL)

Enhanced networking should be enabled for improved network performance.

Terminal window
# Verify enhanced networking
aws ec2 describe-instances --instance-ids i-xxx \
--query "Reservations[].Instances[].EnaSupport"

Brokers must be distributed across multiple availability zones for fault tolerance.

# server.properties - Rack awareness
broker.rack=us-east-1a
# Replica placement
default.replication.factor=3
min.insync.replicas=2
# Broker 1 (AZ-a)
broker.id=1
broker.rack=us-east-1a
# Broker 2 (AZ-b)
broker.id=2
broker.rack=us-east-1b
# Broker 3 (AZ-c)
broker.id=3
broker.rack=us-east-1c

{
"LaunchTemplateName": "kafka-broker",
"LaunchTemplateData": {
"ImageId": "ami-xxx",
"InstanceType": "m6i.2xlarge",
"KeyName": "kafka-key",
"SecurityGroupIds": ["sg-xxx"],
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"VolumeSize": 100,
"VolumeType": "gp3"
}
},
{
"DeviceName": "/dev/sdf",
"Ebs": {
"VolumeSize": 1000,
"VolumeType": "gp3",
"Iops": 6000,
"Throughput": 500
}
}
],
"UserData": "base64-encoded-startup-script"
}
}

Auto Scaling Limitations

Kafka does not automatically rebalance partitions when brokers are added or removed. Partition reassignment must be performed manually after scaling operations.


main.tf
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "kafka_broker" {
count = 3
ami = "ami-xxx"
instance_type = "m6i.2xlarge"
subnet_id = element(var.subnet_ids, count.index)
vpc_security_group_ids = [aws_security_group.kafka.id]
root_block_device {
volume_type = "gp3"
volume_size = 100
}
tags = {
Name = "kafka-broker-${count.index + 1}"
Role = "kafka-broker"
}
}
resource "aws_ebs_volume" "kafka_data" {
count = 3
availability_zone = element(var.availability_zones, count.index)
size = 1000
type = "gp3"
iops = 6000
throughput = 500
encrypted = true
tags = {
Name = "kafka-data-${count.index + 1}"
}
}
resource "aws_volume_attachment" "kafka_data" {
count = 3
device_name = "/dev/sdf"
volume_id = aws_ebs_volume.kafka_data[count.index].id
instance_id = aws_instance.kafka_broker[count.index].id
}
resource "aws_security_group" "kafka" {
name = "kafka-brokers"
description = "Kafka broker security group"
vpc_id = var.vpc_id
ingress {
from_port = 9092
to_port = 9094
protocol = "tcp"
cidr_blocks = [var.vpc_cidr]
}
ingress {
from_port = 9092
to_port = 9094
protocol = "tcp"
self = true
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

Terminal window
# Install CloudWatch agent
sudo yum install amazon-cloudwatch-agent
# Configure for Kafka JMX metrics
cat > /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json << 'EOF'
{
"metrics": {
"metrics_collected": {
"jmx": {
"jvm": true,
"kafka": {
"measurement": [
"kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec",
"kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec",
"kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions"
]
}
}
}
}
}
EOF