Chapter 52 · Managing Amazon Msk
Subchapter 52.10
references/troubleshoot-performance.mdMarkdown9 KBView on GitHub
Run aws kafka describe-cluster-v2 --cluster-arn <arn>. If instance type starts with express., skip all EBS-related checks — Express has no customer-managed EBS.
Get CpuUser and RequestHandlerAvgIdlePercent from CloudWatch (PER_BROKER level, namespace AWS/Kafka).
Decision tree:
compression.type is not producer), message format conversions — FetchMessageConversionsPerSec, ProduceMessageConversionsPerSec (Standard only), log compaction (log.cleaner.min.cleanable.ratio too low), high GC — HeapMemoryAfterGC > 60% (Standard only — Express does not emit this metric) (reduce transactional.id.expiration.ms from 7 days to 1 day to lower memory footprint), or excessive Prometheus scraping (use 60s+ scrape interval).num.io.threads/num.network.threads — see size-and-choose-cluster.md for recommended values.Compute average message size: BytesInPerSec / MessagesInPerSec. If average message size is very small (under 1 KB) and MessagesInPerSec is very high relative to BytesInPerSec, the root cause is likely small producer batches.
Confirm with (PER_BROKER level): RequestHandlerAvgIdlePercent < 30% and NetworkProcessorAvgIdlePercent dropping. If monitoring is DEFAULT: the average message size calculation (BytesInPerSec / MessagesInPerSec) combined with high CPU is sufficient — tiny messages (< 1 KB) with high message rates confirm small-batch saturation without needing PER_BROKER metrics.
Root cause: Poor producer batching configuration — typically linger.ms=0 (sends immediately, no batching), small batch.size (default 16 KB), and no compression. Each message becomes its own produce request, consuming a request handler thread regardless of payload size.
Fix: Recommend client-side batching changes — see configure-clients.md. All three settings matter: linger.ms >= 5 (recommend 25ms), batch.size >= 65536 (64-128 KB), and compression.type = lz4 or zstd. These work together — linger.ms allows time to fill the batch, batch.size sets the batch capacity, compression reduces the final payload. Do NOT recommend broker scaling as the first action.
Other CPU contributing factors (check if batch size is not the cause):
compression.type is not producer) consumes CPUlog.cleaner.min.cleanable.ratio set too low (e.g., 0.01 instead of 0.5)ConnectionCreationRate especially with SASL/SCRAM or IAM authkafka-consumer-groups.sh --bootstrap-server <bootstrap> --list | wc -l — excessive consumer groups increase coordinator overhead and heap memory usageSkip this step for Express brokers.
Check the EBS volume type and size. MSK Standard brokers use EBS volumes with throughput ceilings:
BurstBalance that depletes under sustained IO.kafka.m5.4xlarge+ or kafka.m7g.2xlarge+.Calculate effective throughput demand: BytesInPerSec × ReplicationFactor. For RF=3 and 83 MiB/s ingress, total write IO = 250 MiB/s, hitting GP2 ceiling.
Confirm with CloudWatch (PER_BROKER level): VolumeWriteBytes, VolumeReadBytes, VolumeTotalWriteTime, VolumeTotalReadTime, VolumeQueueLength. Elevated queue length and write time confirm EBS saturation. If monitoring is DEFAULT: check CpuIoWait — sustained elevation indicates threads blocked on disk I/O, a free proxy for EBS saturation.
Fix options (in order of preference):
kafka.m5.4xlarge or larger (or kafka.m7g.2xlarge or larger). Max throughput varies by broker size (593 MiB/s for m5.4xl up to 1000 MiB/s for m5.12xl+).Skip this step for Express brokers — go to Step 6.
Standard brokers run on EC2 instances with network bandwidth limits enforced by the hypervisor. When exceeded, packets are shaped (dropped/delayed), causing latency spikes without high CPU.
Check these PER_BROKER level metrics:
BwInAllowanceExceeded > 0: Inbound bandwidth exceededBwOutAllowanceExceeded > 0: Outbound bandwidth exceededPpsAllowanceExceeded > 0: Packets-per-second limit exceeded (many small messages)ConntrackAllowanceExceeded > 0: Connection tracking limit exceeded (too many concurrent connections)TrafficShaping (DEFAULT level) > 0: Aggregate indicator that any shaping is occurringIf any traffic shaping metrics are nonzero:
BytesInPerSec and BytesOutPerSec. If some brokers handle 2-3x more traffic than others, the load is unevenly distributed.
client.rack set, causing all reads to route to brokers in that AZ.LeaderCount per broker).Fix options:
client.rack) are required, ensure write traffic and partition leadership are balanced across AZs firstExpress brokers do NOT have EC2-level traffic shaping metrics (BwInAllowanceExceeded, BwOutAllowanceExceeded, etc. are not emitted). Instead, Express enforces per-broker throughput quotas directly. When exceeded, MSK throttles client traffic at the Kafka protocol level.
Check these PER_BROKER level metrics:
ProduceThrottleTime > 0: Ingress quota exceeded — producers are being throttledFetchThrottleTime > 0: Egress quota exceeded — consumers are being throttledProduceThrottleByteRate / FetchThrottleByteRate: Bytes/sec being throttledProduceThrottleQueueSize / FetchThrottleQueueSize: Requests queued due to throttlingCheck the MSK Express broker quotas (opens in a new tab) for current per-broker throughput limits. Each Express broker size has a sustained threshold (no degradation) and a maximum quota (hard throttle). Between sustained and max quota, you get higher throughput but with degraded performance (higher latency). At max quota, MSK hard-throttles client traffic.
Also check for AZ skew on Express: Compare per-broker BytesInPerSec and BytesOutPerSec. If some brokers are throttled while others have headroom, the issue is uneven traffic distribution — same causes and fixes as Standard (consumer client.rack in one AZ, unbalanced partition leadership).
Fix options: