Published: 2026-06-01 โ€ข Updated: 2026-06-02

Performance Tuning and Optimizing Kafka

Apache Kafka is designed to handle millions of events per second with sub-millisecond latency. However, achieving this level of performance out of the box is rare. To get the absolute best out of your Kafka cluster, you must understand how to tune its producers, consumers, brokers, and underlying operating system. Performance tuning in Kafka is always a balancing act between throughput, latency, durability, and availability.

The Performance Tuning Quadrant

Before changing any configuration, you must understand the trade-offs. You cannot maximize all four pillars of performance simultaneously. Optimizing for one often requires sacrificing another.

+---------------------------------------------------------+
|                    THE KAFKA BALANCING ACT              |
+---------------------------------------------------------+
|                                                         |
|      HIGH THROUGHPUT               LOW LATENCY          |
|      (Large batch sizes,           (Immediate send,     |
|       compression, linger.ms)       linger.ms = 0)      |
|             ^                               ^           |
|             |                               |           |
|             +---------------+---------------+           |
|                             |                           |
|                             v                           |
|                     DURABILITY & SAFETY                 |
|                     (acks=all, min.insync.replicas)     |
|                                                         |
+---------------------------------------------------------+
    
  • Throughput: The volume of data Kafka can process per second.
  • Latency: The time it takes for a single message to travel from the producer to the broker, and finally to the consumer.
  • Durability: Guaranteeing that messages are safely written to disk and replicated across brokers.
  • Availability: The ability of the cluster to remain operational and accept writes/reads during node failures.

Producer Tuning for High Throughput

Producers are responsible for sending data to Kafka brokers. By default, Kafka producers are optimized for low latency, sending messages almost immediately. For high-throughput scenarios, you should configure the producer to batch messages before sending them.

1. Batching Configurations

Batching reduces the number of network requests by grouping multiple records into a single request. This significantly reduces CPU overhead on both the client and the broker.

  • batch.size: This controls the maximum size in bytes of a single batch. The default is 16,384 bytes (16KB). Increasing this to 65,536 (64KB) or 131,072 (128KB) allows more messages to be grouped together, improving throughput.
  • linger.ms: This tells the producer to wait up to a specified number of milliseconds before sending a batch, in the hope that more messages will arrive. The default is 0ms (send immediately). Setting this to 5ms to 20ms allows batches to fill up, drastically increasing throughput with only a minor latency penalty.

2. Compression

Enabling compression reduces network bandwidth usage and saves storage space on the brokers. Compression is handled by the producer and decompressed by the consumer, meaning the broker does not have to spend CPU cycles decompressing it unless it needs to validate the payload.

  • compression.type: Options include none, gzip, snappy, lz4, and zstd. For high throughput with low CPU overhead, lz4 or snappy are highly recommended. For maximum compression ratio at the cost of higher CPU usage, use zstd.

3. Acknowledgment and Durability Trade-offs

The acks configuration defines how many replicas must acknowledge a write before the producer considers it successful.

  • acks=0: The producer does not wait for any acknowledgment. This provides the highest throughput and lowest latency but offers zero durability guarantees.
  • acks=1: The producer waits for the leader replica to write the record to its local log. This is a balanced option for general use cases.
  • acks=all (or -1): The producer waits for the leader and all in-sync replicas (ISRs) to acknowledge the write. This provides maximum durability but introduces latency.

Here is an example of a highly optimized Java producer configuration for high throughput:

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

// Enable high throughput configurations
props.put("compression.type", "lz4");
props.put("linger.ms", "20");
props.put("batch.size", "65536"); // 64 KB batch size
props.put("acks", "1"); // Balanced durability and performance
props.put("max.in.flight.requests.per.connection", "5"); // High concurrency

Consumer Tuning for Optimal Processing

Consumer performance is determined by how quickly and efficiently consumers can poll and process data from the brokers without falling behind.

1. Fetch Configurations

Similar to producers, consumers can optimize network round-trips by fetching data in larger batches.

  • fetch.min.bytes: Specifies the minimum amount of data the broker should return on a fetch request. The default is 1 byte. Increasing this to 1024 or higher forces the broker to wait until enough data accumulates, which reduces network overhead.
  • fetch.max.wait.ms: The maximum time the broker will block before answering the fetch request if there isn't sufficient data to satisfy fetch.min.bytes. Setting this to 500ms ensures that consumers do not experience excessive delays when data volume is low.

2. Maximizing Parallelism

The primary mechanism for scaling consumer throughput is the number of partitions in a topic. Each partition can be consumed by only one consumer thread within a consumer group. If you have 10 partitions, you can have up to 10 active consumers in a single consumer group. If you need more throughput, you must increase the partition count and add more consumer instances.

Broker and OS-Level Optimizations

Brokers manage the storage and replication of messages. Tuning the broker involves optimizing disk I/O, memory usage, and JVM settings.

1. OS Page Cache Utilization

Kafka relies heavily on the operating system's page cache rather than managing its own in-memory cache. When a producer writes to Kafka, the data is written directly to the OS page cache and flushed to disk asynchronously. When a consumer reads data, Kafka attempts to serve it directly from the page cache, bypassing disk reads entirely. To optimize this:

  • Ensure your brokers have plenty of free RAM available for the OS page cache. Do not allocate all system memory to the JVM heap.
  • Set the JVM heap size to a moderate value (typically 6GB to 10GB is sufficient for most workloads) to leave the rest of the physical RAM for the page cache.

2. JVM Garbage Collection (GC) Tuning

Long Garbage Collection pauses can cause brokers to lose connection to ZooKeeper or KRaft controllers, leading to unwanted partition leader elections. It is highly recommended to use the G1GC (Garbage-First Garbage Collector) for Kafka brokers.

-XX:+UseG1GC
-XX:MaxGCPauseMillis=20
-XX:InitiatingHeapOccupancyPercent=35

Real-World Use Cases

Use Case 1: High-Volume IoT Telemetry Ingestion

An IoT platform needs to ingest billions of sensor events per day. Data loss of a few events is acceptable, but system throughput must be maximized to prevent backpressure on edge devices.

  • Producer Config: acks=1, compression.type=lz4, linger.ms=50, batch.size=131072.
  • Topic Config: High partition count (e.g., 64 partitions) to distribute the write load across multiple brokers.

Use Case 2: Low-Latency Financial Transaction Processing

A banking application processes payment transactions where latency must be under 10 milliseconds, and zero data loss is tolerated.

  • Producer Config: acks=all, linger.ms=0, max.in.flight.requests.per.connection=1.
  • Broker Config: min.insync.replicas=2 (with a replication factor of 3).

Common Mistakes to Avoid

  • Over-allocating JVM Heap: Setting the Kafka broker JVM heap to 32GB or higher on a 64GB machine. This starves the OS page cache, forcing Kafka to read from physical disks instead of RAM, which drastically slows down performance.
  • Setting linger.ms=0 for High Throughput: Keeping the default zero-latency configuration when your primary goal is high-volume data ingestion. This floods the network with tiny packets.
  • Under-partitioning Topics: Creating topics with only 1 or 2 partitions and wondering why scaling consumer instances does not improve processing speeds.
  • Ignoring Network Limits: Tuning software configurations without checking if the physical network interface card (NIC) is saturated.

Interview Notes

  • How does Kafka achieve high write performance? Kafka achieves high write throughput by using sequential disk writes (which are much faster than random disk access), utilizing the OS page cache, and leveraging zero-copy transfer mechanisms (using the sendfile system call) to send data directly from the page cache to the network socket.
  • What is the trade-off of setting acks=all? It guarantees maximum durability because a write is only successful when acknowledged by the leader and all in-sync replicas. However, it increases latency because the producer must wait for network round-trips between the leader and follower brokers.
  • How do you resolve consumer lag? First, check if the bottleneck is CPU, memory, or database writes on the consumer side. To scale, increase the number of partitions in the topic and spin up additional consumer instances within the same consumer group.

Summary

Optimizing Apache Kafka requires a deep understanding of your application's requirements. If you need high throughput, focus on batching, compression, and partitioning. If you need low latency, keep batching delays to a minimum. For durability, ensure proper replication and acknowledgment configurations. Always monitor your JVM garbage collection and ensure your operating system has sufficient RAM allocated to the page cache to keep Kafka running at peak performance.

About the Author

Naresh Kumar

Naresh Kumar

Senior Java Backend Engineer experienced in Banking, Payments, ISO 20022, Spring Boot, Microservices, Kafka, Docker, Kubernetes, AWS and Cloud Native Systems.

Built enterprise payment solutions, transaction processing systems, API platforms and scalable microservices used in production.

LinkedIn Profile