This guide covers performance optimization for Kafka producers and consumers, including configuration tuning, batching strategies, compression, and monitoring recommendations.
Producer, network, and consumer performance factors Producer, network, and consumer performance factors Performance Factors Producer Network Consumer Batching Compression Acks Buffer Size Bandwidth Latency Connections Fetch Size Poll Interval Processing Parallelism
Factor Impact Optimization Goal Batching Throughput Larger batches = higher throughput Compression Network, storage Reduce data size Acknowledgments Durability vs latency Balance requirements Parallelism Throughput Match partitions to consumers
Property Default Throughput Latency batch.size16384 Increase Increase linger.ms0 Increase Increase buffer.memory33554432 Increase - compression.typenone Improves Increases CPU acksall Decrease Increases max.in.flight.requests.per.connection5 Increase -
# Batching - larger batches
batch.size =131072 # 128KB
linger.ms =20 # Wait up to 20ms for batch
buffer.memory =134217728 # 128MB total buffer
compression.type =lz4 # Fast compression
max.in.flight.requests.per.connection =5
delivery.timeout.ms =120000
acks =1 # Only leader acknowledgment
linger.ms =0 # Send immediately
batch.size linger.ms Throughput Latency 16KB 0 Low Lowest 16KB 5 Medium Low 64KB 10 High Medium 128KB 20 Highest Higher
These values are example starting points; tune based on payload size and latency targets.
// Monitor batch efficiency
producer . metrics () . get ( " batch-size-avg " ) ;
producer . metrics () . get ( " records-per-request-avg " ) ;
producer . metrics () . get ( " record-queue-time-avg " ) ;
Codec Compression Ratio CPU Speed none1:1 None Fastest lz4~2:1 Low Fast snappy~2:1 Low Fast zstd~3:1 Medium Medium gzip~3:1 High Slow
# Recommended for most workloads
# For maximum compression (CPU available)
# Producer-side compression level (zstd)
Scenario Recommended High throughput, balanced lz4 Network constrained zstd CPU constrained none or snappy Storage optimization zstd Legacy compatibility gzip
Property Default Impact fetch.min.bytes1 Wait for data to accumulate fetch.max.bytes52428800 Maximum per fetch max.partition.fetch.bytes1048576 Maximum per partition fetch.max.wait.ms500 Maximum wait for min.bytes max.poll.records500 Records per poll
fetch.min.bytes =65536 # 64KB minimum
fetch.max.bytes =104857600 # 100MB maximum
max.partition.fetch.bytes =10485760 # 10MB per partition
fetch.max.wait.ms =1000 # Wait longer for batches
max.poll.interval.ms =600000 # 10 minutes
Consumer parallelism using multiple consumers or a worker thread pool Consumer parallelism using multiple consumers or a worker thread pool Parallelism Options Option 1: Multiple Consumers Option 2: Consumer + Thread Pool Consumer 1 Partitions 0,1 Consumer 2 Partitions 2,3 Consumer 3 Partitions 4,5 Consumer (single thread) Worker Pool (many threads) dispatch
Multiple Consumers:
// One consumer per thread
int numConsumers = Math . min ( partitionCount, availableCores ) ;
ExecutorService executor = Executors . newFixedThreadPool ( numConsumers ) ;
for ( int i = 0 ; i < numConsumers; i ++ ) {
executor . submit ( new ConsumerRunnable ( createConsumer ())) ;
Consumer with Worker Pool:
// Single consumer with async processing
ExecutorService workers = Executors . newFixedThreadPool ( 10 ) ;
ConsumerRecords < String , String > records = consumer . poll ( Duration . ofMillis ( 100 )) ;
List < CompletableFuture < Void >> futures = new ArrayList <>();
for ( ConsumerRecord < String , String > record : records) {
futures . add ( CompletableFuture . runAsync ( () -> process ( record ) , workers )) ;
CompletableFuture . allOf ( futures . toArray ( new CompletableFuture [ 0 ] )) . join () ;
socket.send.buffer.bytes =131072 # 128KB
socket.receive.buffer.bytes =131072 # 128KB
receive.buffer.bytes =131072
connections.max.idle.ms =540000 # 9 minutes
reconnect.backoff.max.ms =1000
buffer.memory =134217728 # 128MB
max.block.ms =60000 # Wait up to 60s
Memory consumption per consumer:
Fetch buffer: fetch.max.bytes × assigned partitions
Record buffer: Records in poll() result
Deserialization overhead
// Monitor consumer memory
consumer . metrics () . get ( " fetch-size-avg " ) ;
consumer . metrics () . get ( " records-consumed-rate " ) ;
# Cache for reducing writes to state stores
cache.max.bytes.buffering =10485760 # 10MB per thread
rocksdb.config.setter =com.example.CustomRocksDBConfig
Metric Description Target record-send-rateRecords sent per second As high as needed record-retry-rateRetries per second < 1% of send rate batch-size-avgAverage batch size Close to batch.size records-per-request-avgRecords per request Higher = better batching request-latency-avgRequest latency < 100ms outgoing-byte-rateNetwork throughput Network capacity buffer-available-bytesAvailable buffer > 0 buffer-exhausted-rateBuffer full events 0
Metric Description Target records-consumed-rateRecords consumed per second Match production rate records-lagOffset lag As low as acceptable records-lag-maxMaximum lag Alert threshold fetch-latency-avgFetch latency < 500ms fetch-rateFetches per second Stable commit-latency-avgCommit latency < 1000ms
// Access metrics programmatically
Map < MetricName , ? extends Metric > metrics = producer . metrics () ;
for ( Map . Entry < MetricName , ? extends Metric > entry : metrics . entrySet () ) {
MetricName name = entry . getKey () ;
Metric metric = entry . getValue () ;
if ( name . name () . equals ( " record-send-rate " ) ) {
log . info ( " Send rate: {} " , metric . metricValue ()) ;
# Kafka performance test tool
kafka-producer-perf-test.sh \
bootstrap.servers=kafka:9092 \
kafka-consumer-perf-test.sh \
--bootstrap-server kafka:9092 \
public class ProducerBenchmark {
public static void main ( String [] args ) {
Properties props = loadConfig () ;
Producer < String , byte []> producer = new KafkaProducer <>(props);
int numRecords = 1_000_000 ;
byte [] payload = new byte [recordSize];
long start = System . currentTimeMillis () ;
CountDownLatch latch = new CountDownLatch ( numRecords ) ;
for ( int i = 0 ; i < numRecords; i ++ ) {
new ProducerRecord <>( " benchmark " , Integer . toString ( i ) , payload),
(metadata, exception) -> latch . countDown ()
long elapsed = System . currentTimeMillis () - start;
System . out . printf ( " Sent %d records in %d ms%n " , numRecords, elapsed ) ;
System . out . printf ( " Throughput: %.2f records/sec%n " , numRecords * 1000.0 / elapsed ) ;
System . out . printf ( " Throughput: %.2f MB/sec%n " ,
numRecords * recordSize / 1024.0 / 1024.0 * 1000.0 / elapsed ) ;
bootstrap.servers =kafka-1:9092,kafka-2:9092,kafka-3:9092
max.in.flight.requests.per.connection =5
delivery.timeout.ms =120000
# Acknowledgments (if durability allows)
bootstrap.servers =kafka-1:9092,kafka-2:9092,kafka-3:9092
group.id =high-throughput-consumers
fetch.max.bytes =104857600
max.partition.fetch.bytes =10485760
max.poll.interval.ms =600000
heartbeat.interval.ms =15000
partition.assignment.strategy =org.apache.kafka.clients.consumer.CooperativeStickyAssignor
Symptom Cause Solution Small batches linger.ms=0 Increase linger.ms High latency acks=all Consider acks=1 if safe CPU bound Compression Use faster codec Network bound No compression Enable compression
Symptom Cause Solution Long queue time Large batches Reduce batch.size, linger.ms Slow acks acks=all, slow replicas Check replica health Network delay High latency network Increase timeouts
Symptom Cause Solution Growing lag Slow processing Increase parallelism Frequent rebalances Long processing Increase max.poll.interval.ms Small fetches fetch.min.bytes Increase fetch size
Practice Recommendation Measure first Benchmark before tuning Change one thing Isolate variable impact Monitor continuously Track performance metrics Test in production-like Use realistic data and load
Practice Recommendation Use compression LZ4 for most workloads Tune batching Balance throughput and latency Handle backpressure Monitor buffer.memory usage Use callbacks Handle delivery results
Practice Recommendation Match partitions Consumers <= Partitions Process async For CPU-intensive work Commit carefully After processing, not before Monitor lag Alert on threshold breach