What Is Batch Size Tuning in Kafka?

What Is Batch Size Tuning in Kafka?

How Kafka producers group messages into batches, how batch size, linger time, compression and memory work together, and how to tune them for the right balance of throughput, latency and cost without guessing.

Imagine a delivery van that leaves the warehouse the moment a single parcel is ready. The van drives across the city, drops one parcel, and returns. Now imagine a van that waits ten minutes, loads fifty parcels, and makes one trip. The second van delivers far more parcels per hour with the same fuel and the same driver, but the first parcel in the van waits ten minutes before it starts its journey. Somewhere between “leave now” and “wait until the van is full” lies the sweet spot for your business. Finding it is the whole art of batch size tuning.

Apache Kafka producers face exactly this choice thousands of times per second. Every message can be sent alone, or grouped with others into a batch. Sending alone is fast for that one message but wasteful for the system. Sending in batches is efficient but adds a small wait. In this guide you will learn what a batch is, which settings control it, how to measure whether your batches are healthy, how to tune them step by step for different workloads, and which mistakes cause slow producers, wasted memory and unhappy brokers.

1What Batch Size Tuning Means

Batch size tuning is the practice of choosing how many bytes and how much waiting time a Kafka producer uses to group messages before sending them.

Start with the basic words. A message, also called a record, is a small piece of data such as “customer 17 clicked the buy button”. A producer is a program that sends messages to Kafka. A topic is a named log where messages are stored, and each topic is split into partitions, which are separate ordered logs that can live on different servers called brokers.

A batch is a group of messages that a producer sends to one partition in a single unit. Instead of sending one hundred separate messages over the network, the producer packs them into one batch, adds one header, and sends them together. The broker stores the batch as it arrived and later hands it to consumers as a batch as well.

Batch size tuning means adjusting the settings that control batches so that the producer sends the right amount of data at the right times. The main settings are batch.size, the maximum size of a batch in bytes, and linger.ms, how long the producer may wait for more messages before sending. Around them sit compression, memory, request limits and acknowledgment settings, which all interact.

Everyday analogy

Think of a lift in an office tower. If the lift leaves the moment one person steps in, it makes many trips carrying one person each. The queue grows and the lift wears out. If the lift waits until it is completely full, the first person may stand there for minutes. A sensible building programs the lift to leave when it is full or after a short wait, whichever comes first. That is exactly how batch.size and linger.ms cooperate.

The goal of tuning

Goal 1

Higher throughput

Send more messages per second using fewer network requests and less CPU on both producers and brokers.

Goal 2

Acceptable latency

Keep the delay between creating a message and storing it within what the business can accept.

Goal 3

Efficient resources

Use memory, network and disk sensibly, without waste or sudden spikes.

16 KB
long-standing default value of batch.size
0 to 5 ms
default linger.ms, depending on the Kafka version
32 MB
default memory the producer uses for buffering
i
Remember this

Tuning is not about finding the biggest number. It is about choosing the smallest batch settings that give your throughput target, so that latency and memory stay low.

2Why Batching Matters

Every request has a fixed cost that does not depend on how much data it carries. Batching spreads that cost over many messages.

When a producer sends data to a broker, a lot happens besides moving the message bytes. The producer builds a request with headers. The operating system copies data into network buffers. The network carries packets and confirmations. On the broker, a network thread reads the request, a request handler thread checks it, writes it to the log, and waits for replicas to copy it before acknowledging. All of this work has a fixed part and a part that grows with the number of bytes. Sending ten thousand tiny requests pays the fixed part ten thousand times. Sending one hundred batches pays it a hundred times.

CostWithout batchingWith batching
Network round tripsOne per messageOne per batch
Broker request handlingRepeated for every messageShared by all messages in the batch
Compression efficiencyAlmost none, since each message is tinyGood, because similar messages sit together
Disk writesMany small appendsFewer, larger appends
Replication overheadMany small fetches by followersFewer, larger fetches
CPU use on brokersHighMuch lower
Everyday analogy

Posting a hundred letters one by one means a hundred trips to the post box, a hundred stamps handled and a hundred queue waits. Putting them in one bag and dropping the bag once costs the same walk. The letters are the messages, the bag is the batch, and the walk is the fixed cost of a request.

What goes wrong when batches are too small

The chatty producer

A service sends fifty thousand small events per second with the default settings, and each event travels in its own request because the producer is idle whenever an event arrives. Broker CPU climbs, the request queue grows, and latency rises for everyone sharing the cluster, even though the total number of bytes is modest.

The compression that does nothing

A team turns on compression to save network and disk, but sees almost no benefit. The reason is that compression works on the batch, and their batches contain only one or two messages. There is nothing to compress against.

!
A common misunderstanding

Many people think batching is a special mode to turn on. In fact, Kafka producers always batch. What you tune is how large and how patient the batches are.

3The Anatomy of the Producer Pipeline

To tune batching you need a picture of what happens between your code calling send and the broker replying.

A Kafka producer is not a single loop. It is a small pipeline with two kinds of threads. Your application threads call send and return quickly. A separate background sender thread does the network work. Between them sits a shared memory area called the record accumulator, which holds batches waiting to be sent.

flowchart LR
  APP["Application Threads calling send"] --> SER["Serializer"]
  SER --> PART["Partitioner chooses partition"]
  PART --> ACC["Record Accumulator with one batch queue per partition"]
  ACC --> SEND["Sender Thread"]
  SEND --> NET["Network Client with requests per broker"]
  NET --> BR["Kafka Broker"]
  BR --> ACK["Acknowledgment"]
  ACK --> CB["Callback to application"]
  BUF["Buffer Memory Pool"] --> ACC
Figure 1: The path of a message through a Kafka producer.

The stages in plain words

1

Your code calls send

The message goes to the producer library, which returns almost at once, without waiting for the broker.

2

Serialization

The key and value are turned into bytes, because Kafka stores only bytes.

3

Partitioning

The partitioner picks the partition. If the message has a key, a hash of the key decides. If not, the producer chooses a partition using its own strategy.

4

Accumulation

The message is appended to the open batch for that partition, or a new batch is started using memory from the buffer pool.

5

Sending

The sender thread collects ready batches, groups them by destination broker, and sends one request per broker.

6

Acknowledgment

The broker replies once the data is stored as required. The producer completes the message and runs your callback.

i
Key insight

Batches are built per partition, but requests are built per broker. One request may carry several batches, one for each partition led by that broker. Tuning therefore affects both the batch and the request.

Everyday analogy

Think of a mail room. Workers drop letters into pigeonholes, one per destination city. A driver comes by regularly and collects whatever is in the holes for each road he travels, tying it up in one bundle per road. The pigeonholes are batches per partition, and the bundle per road is the request per broker.

4What a Batch Really Is

A batch is not just a convenient bundle in memory. It is the same structure that goes over the network and onto the disk.

Kafka uses a single format for a batch of records, called a record batch, in memory, on the wire and in the log files on the broker. This design means the broker can usually write what it receives directly to disk and send it later to consumers without unpacking and repacking it. That is one of the reasons Kafka is so fast.

Part 1

Batch header

Holds information about the whole batch: the first offset, the number of records, timestamps, the producer identity and sequence numbers used for idempotence, and the compression type. It is a fixed cost of roughly sixty bytes.

Part 2

The records

Each record stores its key, value and headers, with small offsets relative to the start of the batch, which keeps per-record overhead low.

Part 3

Optional compression

If compression is on, the records section of the batch is compressed as one block, so the block gets smaller as similar records sit together.

Why this matters for tuning

Property of batchesEffect
Header cost is fixed per batchSmall batches pay this cost on few records, so it is proportionally larger
Compression works on the whole batchBigger batches usually compress better
Brokers store batches as receivedProducer batch size influences disk layout and read efficiency
Idempotence numbers batchesRetries resend whole batches and brokers detect duplicates per batch
Consumers fetch batchesA consumer reads at least a whole batch, even if it wants only one record
Everyday analogy

A batch is like a sealed shipping container with a single label on the door. The label costs the same whether the container holds one box or a thousand. Once packed, the container travels by ship, sits in a warehouse and is delivered without being opened. That is why packing it well at the start pays off all along the journey.

?
Batch versus request

Do not confuse a batch with a request. A batch belongs to one partition. A request is a network message to one broker and may contain batches for many partitions. Settings such as batch.size apply to batches, while max.request.size applies to requests.

5The batch.size Setting

batch.size is the maximum number of bytes the producer will put into one batch for one partition.

The setting batch.size is measured in bytes. Its long-standing default is 16,384 bytes, which is 16 kibibytes. When the open batch for a partition reaches this size, the batch is closed and becomes ready to send. A new batch is opened for the next message. The word to notice is maximum. The producer never waits until a batch is full merely because you set a large number. It only uses batch.size as a ceiling.

What batch.size does and does not do

What it does

  • Sets the largest size of one batch
  • Decides how much memory is reserved for each open batch
  • Triggers sending when a batch fills
  • Limits how much data one partition adds to a request

What it does not do

  • It does not make the producer wait for a full batch
  • It does not limit the size of a single record
  • It does not apply to the whole request
  • It does not guarantee that batches reach this size

The memory side effect

The producer takes memory from its buffer pool in chunks of batch.size for each new batch. If you set batch.size to one megabyte and write to two hundred partitions, the producer may try to hold two hundred megabytes of open batches, far beyond the default buffer of thirty-two megabytes. When the pool is short of memory, sending slows and calls may block. So a very large batch.size is not free, and it must be balanced against the number of active partitions.

Records larger than batch.size

If a single record is bigger than batch.size, the producer does not refuse it. It creates a batch just big enough for that one record. This means large messages travel alone, and the batching benefit is lost for them. If most of your messages are larger than batch.size, raising batch.size, or reducing message size, is the first thing to consider.

Everyday analogy

Think of shipping crates with a maximum capacity. You can decide that each crate holds at most forty boxes. You are not forced to fill it before it leaves. But the warehouse must reserve floor space for one crate of that size for every destination, whether it is full or not. Choosing a huge crate size for many destinations quickly fills the warehouse floor.

i
Commonly cited ranges

For throughput-oriented producers, teams often raise batch.size to values between 64 and 256 kibibytes, but the right number depends on message size, partition count and memory. Treat any range as a starting point for measurement, not a rule.

6The linger.ms Setting

linger.ms is the small delay that gives a batch a chance to fill before it is sent.

The setting linger.ms tells the producer how many milliseconds it may wait for more messages to join a batch before sending it. Older Kafka versions default to zero, which means “send as soon as the sender thread is free”. Newer releases, starting with the Kafka 4.0 line, changed the default to a few milliseconds. Check the documentation of your version.

With a linger of zero, batching still happens, but only by accident. While the sender thread is busy with an earlier request, new messages pile up in the accumulator and are sent together in the next round. Under light traffic, however, each message may go alone, because the sender is idle and finds one message waiting. A small positive linger creates a deliberate window in which messages can gather.

linger.ms valueBehaviorBest for
0Send as soon as possible; batches form only under loadExtremely latency sensitive paths with low traffic
1 to 5Tiny wait; often enough to collect a handful of messagesInteractive systems that want some batching at almost no delay
10 to 50Meaningful wait; batches fill well at moderate ratesMost streaming pipelines and event collection
100 or moreLong wait; large batches and best compressionBulk transfer where seconds of delay are acceptable

Linger is a maximum delay, not a fixed delay

Linger.ms does not add a fixed pause to every message. If the batch fills up sooner, it is sent immediately. Linger is the longest a message will wait. So at high traffic, where batches fill quickly, a large linger costs nothing, and at low traffic, it caps the extra delay at the linger value.

Everyday analogy

A shuttle bus at an airport leaves when it is full or after ten minutes, whichever comes first. At rush hour it leaves every couple of minutes because it fills quickly. In the quiet of night, passengers wait at most ten minutes. The ten-minute rule is linger.ms, and the seats in the bus are batch.size.

!
Latency is measured end to end

Adding a linger of twenty milliseconds adds up to twenty milliseconds to each message on this hop. If your service has a total latency budget of fifty milliseconds and calls the producer synchronously, a large linger may consume most of it. Decide the budget first.

7When Exactly Is a Batch Sent?

Several conditions can make a batch ready. Knowing them explains most of the surprises you will see in metrics.

flowchart TD
  A["Message added to partition batch"] --> B{"Is batch full at batch.size"}
  B -->|"Yes"| R["Batch is ready to send"]
  B -->|"No"| C{"Has linger.ms passed since batch was created"}
  C -->|"Yes"| R
  C -->|"No"| D{"Is buffer memory exhausted or flush called"}
  D -->|"Yes"| R
  D -->|"No"| W["Keep waiting for more messages"]
  R --> S["Sender thread includes batch in request to its broker"]
Figure 2: The main conditions that make a batch ready.
TriggerExplanationWhat you will notice
Batch is fullThe batch reached batch.sizeHigh traffic: batches near their maximum size
Linger expiredThe batch waited the allowed timeModerate traffic: batches smaller than the maximum but consistent
Memory pressureThe buffer pool is full and other calls wait for spaceBatches sent early and small; blocking in send calls
Flush or closeThe application forces everything outBursts of small batches at flush time
Riding alongThe sender is already sending to this broker and includes other waiting batchesBatches leaving before their own timers expire

The ride-along effect

When at least one batch for a broker is ready, the sender builds a request for that broker and usually includes waiting batches for other partitions on the same broker, even if they are neither full nor expired. This means that the batch size you observe can be smaller than what linger.ms and batch.size alone would predict. It also means that spreading writes across many partitions on the same broker does not always cause the smallest possible batches, but it does cause smaller ones than concentrating writes would.

i
Debugging tip

If your average batch size is far below batch.size and your linger is generous, look for the other triggers: memory pressure, frequent flush calls, or a very high number of partitions at low traffic per partition.

8Partitions, Keys and Batching

Batches are per partition, so how messages spread over partitions decides how easily batches fill.

Suppose a producer sends ten thousand messages per second. If all go to one partition, each batch fills quickly. If they are spread evenly over one hundred partitions, each partition receives only one hundred messages per second, and each batch takes one hundred times longer to fill. The same total traffic yields far smaller batches.

FactorEffect on batches
More partitions on the topicFewer messages per partition per second, so smaller batches at the same linger
Keyed messages with many distinct keysSpread across all partitions, so each partition batch fills slowly
Keyed messages with a few hot keysSome partitions receive nearly all traffic and fill fast; others stay almost empty
Messages without keysThe producer may choose partitions to help batching, as described below
Many producers instancesEach instance has its own batches, so total batch count multiplies

Sticky partitioning for messages without keys

For messages without a key, older producers rotated through partitions message by message, which produced many tiny batches. Since Kafka 2.4, the default strategy is sticky: the producer sends all keyless messages to one partition until its batch is full or the linger time has passed, then switches to another partition. Over time the load is balanced, but each individual batch is larger. Later versions improved this by adapting to broker speed so that slow brokers receive fewer batches.

Everyday analogy

Imagine handing out flyers at a station with ten exits. Giving one flyer to each exit in turn means you are always walking. Standing at one exit until your stack for that exit is complete, then moving to the next, saves many steps and delivers the same total number of flyers over the day.

Production example: the partition count surprise

A team increases a topic from twelve to two hundred partitions to allow more consumers. Their producers, tuned earlier for twelve partitions, now build two hundred small batches at the same total rate. Request counts rise, brokers do more work per byte, and throughput drops until the team raises the linger time and reviews the batch settings for the new layout.

!
Partition count is a batching decision

Adding partitions improves parallelism for consumers but weakens batching for producers. When you change partition counts, re-check your batch metrics.

9Compression and Batches

Compression and batch size are partners. Bigger batches compress better, and compressed batches move faster.

The producer setting compression.type chooses whether and how batches are compressed. The options are none, gzip, snappy, lz4 and zstd. Compression is applied to the whole batch, not message by message. Similar messages placed together share patterns, such as repeated field names in JSON, that the compressor can replace with short references.

TypeSpeedCompression ratioTypical use
noneFastestNoneAlready compressed or tiny data
lz4Very fastModerateHigh throughput with low CPU cost
snappyVery fastModerateSimilar to lz4; widely used in older setups
zstdFast to moderateHighBest balance when network or disk cost matters
gzipSlowerHighWhen compression ratio matters more than CPU

How batch size affects compression

A batch containing one message of two hundred bytes compresses badly, because the compressor has nothing to compare it with. A batch of one hundred similar messages compresses very well. This is why two producers with identical data can see very different compression ratios: the one with better batching wins. When you tune batch size upward, expect the compression ratio to improve, up to a point of diminishing returns.

Everyday analogy

Packing suitcases for a family holiday, you fit more clothes if you fold and roll them together in one large bag than if you pack each shirt in its own small box. Compression finds the “folding” pattern across many messages. A batch with only one shirt has nothing to fold.

Where the CPU cost lands

The producer compresses batches, using its own CPU. Brokers normally store batches as they are, when the topic compression setting is left at its default of “producer”, so they do not spend CPU recompressing. Consumers decompress batches when reading. Spending CPU at the producer to save network, broker disk and consumer fetch bandwidth is often a good trade for high-volume topics.

i
Check the ratio

The producer reports its average compression rate as a metric. If the ratio is close to one, either the data is not compressible or the batches are too small to compress well. Compare the ratio before and after changing batch size to see which one applies.

10Buffer Memory and Backpressure

Batches wait in memory. When memory runs out, the producer pushes back on your code.

The setting buffer.memory is the total memory the producer may use to hold batches that are waiting to be sent or waiting for acknowledgment. The default is thirty-two mebibytes. If your application produces faster than the brokers can accept, the buffer fills. When it is full, calls to send block for up to max.block.ms, which defaults to sixty seconds, and then fail with a timeout. This blocking is called backpressure, and it protects the producer from running out of memory.

flowchart TD
  A["Application calls send"] --> B{"Is buffer memory available"}
  B -->|"Yes"| C["Message joins a batch in the accumulator"]
  B -->|"No"| D["Call blocks and waits"]
  D --> E{"Space freed before max.block.ms"}
  E -->|"Yes"| C
  E -->|"No"| F["Send fails with a timeout error"]
  C --> G["Sender thread sends the batch and frees memory after acknowledgment"]
  G --> B
Figure 3: A full buffer makes send calls wait, then fail.

Why the buffer fills

Cause 1

Slow brokers

If brokers are overloaded, acknowledgments arrive late and batches stay in memory longer.

Cause 2

Network trouble

Lost connections or slow links delay requests and force retries.

Cause 3

Oversized batch settings

A large batch.size across many partitions reserves more memory than the pool contains.

Cause 4

Producing faster than the cluster can absorb

Sustained input above the capacity of the topic’s partitions and brokers always ends with a full buffer.

Everyday analogy

Picture the loading dock of a warehouse. Pallets waiting for trucks sit in a fixed-size yard. If trucks arrive slowly, the yard fills up, and the forklift drivers must stop bringing new pallets until space appears. If they wait too long, the manager gives up and cancels the order. The yard is buffer.memory, and the waiting is backpressure.

!
Do not hide backpressure by raising memory blindly

A bigger buffer only delays the moment it fills. If the cluster cannot keep up, more memory means longer delays and bigger loss if the process crashes. Find out why acknowledgments are slow before enlarging the buffer.

11Size Limits: Requests, Records and Brokers

Several limits sit around batches. If they disagree, messages are rejected.

SettingWhereDefaultWhat it limits
batch.sizeProducer16 KiBTarget maximum size of one batch for one partition
max.request.sizeProducer1 MiBLargest request, and the largest single record, the producer will send
message.max.bytesBrokerAbout 1 MiBLargest batch the broker will accept
max.message.bytesTopicInherits the broker valuePer-topic override of the largest batch accepted
replica.fetch.max.bytesBroker1 MiBAmount followers fetch per partition when replicating

How the limits relate

Notice that the broker limit and the topic limit apply to a batch, not to a single record, in modern Kafka versions. A producer batch that is larger than the broker limit is rejected with a “message too large” error. The producer limit max.request.size applies to the whole request, so a request carrying many batches cannot exceed it. To send large messages safely, all three levels must agree: the producer, the broker or topic, and the replication fetch size.

1

Decide the largest record you need

Measure the biggest realistic message, not the average.

2

Raise the topic limit first

Set the topic-level maximum so that the broker accepts the larger batch.

3

Make sure replication can keep up

Followers must be allowed to fetch batches of that size, or replication stalls.

4

Raise the producer request limit

Allow the producer to send requests that contain the larger batch.

5

Set consumer fetch limits

Consumers must be able to fetch a full batch from a partition, or they cannot read it.

i
Better idea for very large payloads

For files, images or documents of many megabytes, store the payload in object storage and send only a reference through Kafka. This keeps batches small, brokers healthy and consumers quick.

12Acknowledgments, In-Flight Requests and Batching

How long a producer waits for the broker changes how many batches can be in motion, and so changes batching behavior.

The setting acks decides when the producer considers a batch delivered. With acks set to zero it does not wait at all. With one it waits for the leader to write. With all it waits until every in-sync replica has the batch. Stronger acknowledgment means the broker takes longer to reply, and the producer holds the batch in memory for longer.

The setting max.in.flight.requests.per.connection, by default five, limits how many unacknowledged requests the producer may have outstanding on one connection to a broker. While the connection is at its limit, new messages keep gathering in the accumulator and form larger batches. Slower acknowledgment therefore tends to produce larger batches by itself: the sender thread has less chance to send early, so more messages wait together.

SettingEffect on batchingCaution
acks allSlower replies; batches wait longer and often grow largerBest durability; requires healthy replicas
acks oneFaster replies; smaller natural batchesData may be lost if the leader fails at the wrong time
acks zeroNo waiting; batching depends on linger aloneNo delivery confirmation at all
Higher in-flight limitMore parallel requests; less natural accumulationWith idempotence, keep at five or fewer to preserve ordering
Idempotence onBatches are numbered so retries are deduplicatedRequires acks all and retries enabled
Everyday analogy

Consider a courier who may have at most five unsigned parcels out at any time. If customers are slow to sign, the courier cannot leave with more parcels, so new orders pile up at the depot and are loaded together in the next big trip. A slow signature process leads to bigger loads, but also to longer waits.

!
Never trade durability for batch size

Some teams lower acks to make producers faster instead of tuning batches. The lower setting risks data loss for a small, often unnecessary, gain. Tune batching first and keep durability settings at the level the business requires.

13The Throughput and Latency Trade-off

Every tuning choice moves you along one line: more waiting gives more efficiency, less waiting gives faster individual messages.

Throughput is how many messages, or bytes, the system moves per second. Latency is how long one message takes from creation to safe storage. Batching improves throughput because each request carries more data. It can worsen latency because messages wait for company. The two are in tension, but the tension is gentler than most people expect, because a small amount of waiting often brings most of the benefit.

flowchart LR
  A["Tiny batches and no linger"] --> B["Lowest wait per message"]
  A --> C["Highest request rate and CPU use"]
  D["Moderate batches and small linger"] --> E["Small added wait"]
  D --> F["Much lower request rate and good compression"]
  G["Huge batches and long linger"] --> H["Long wait for early messages"]
  G --> I["Little extra gain and more memory used"]
Figure 4: The gains from batching flatten out while the costs keep growing.

The shape of the curve

RegionTypical settingsWhat you see
Too little batchingLinger 0, small batches, high partition countMany small requests, high broker CPU, poor compression
Sweet spotLinger of a few to a few tens of milliseconds, batch of tens to a few hundreds of KiBGood throughput, small added delay, healthy compression
Too much batchingLinger in seconds, very large batchesLong delays, large memory use, spiky traffic and costly retries
Everyday analogy

Think of a restaurant kitchen that cooks orders one at a time versus cooking in trays. Cooking each meal alone is quick for the first diner but exhausts the cooks. Waiting for a full tray makes the first diner wait too long. A kitchen that starts a tray every few minutes serves most people quickly and keeps the ovens busy. Most of the benefit arrives with a short wait, not a long one.

i
Start with the budget

Ask the business for a latency budget before touching any setting. “Events must be stored within one hundred milliseconds” allows generous batching. “Within five milliseconds” does not. The budget picks the region of the curve.

14Worked Example: From Tiny Batches to Healthy Batches

A small calculation shows why linger.ms often matters more than batch.size.

A service sends ten thousand messages per second, each one kilobyte in size, to a topic with ten partitions. Keys are well distributed, so each partition receives about one thousand messages per second, which is one megabyte per second, or roughly one kilobyte per millisecond. The producer uses the default batch.size of sixteen kibibytes and a linger of zero.

With the defaults

Because linger is zero, the sender thread ships whatever is waiting the moment it is free. A request to a broker takes about two milliseconds round trip. During those two milliseconds, each partition collects about two messages. So every batch holds about two kilobytes, far below the sixteen kibibyte limit. The producer sends about five hundred requests per second per broker, each carrying tiny batches.

With a linger of ten milliseconds

Now each partition may collect messages for up to ten milliseconds. At one kilobyte per millisecond, a batch holds about ten kilobytes when the timer expires, still under the size limit. Requests to each broker drop to about one hundred per second, one fifth as many, and each batch is five times bigger. Compression improves and broker work falls. The price is at most ten milliseconds of extra delay.

With a larger batch size and linger of twenty milliseconds

With batch.size raised to sixty-four kibibytes and a linger of twenty milliseconds, a batch would grow to about twenty kilobytes before the timer fires. The size limit is not reached, so raising it made no difference. Linger was the limiting factor. This example shows the general rule: at moderate rates, linger decides the batch size, and batch.size only sets the ceiling.

Setting combinationApprox. batch sizeRequests per second per brokerAdded delay
Linger 0, batch 16 KiBAbout 2 KBAbout 500Almost none
Linger 10 ms, batch 16 KiBAbout 10 KBAbout 100Up to 10 ms
Linger 20 ms, batch 64 KiBAbout 20 KBAbout 50Up to 20 ms
Linger 20 ms, batch 8 KiBAbout 8 KB, limited by sizeAbout 125Under 20 ms, since batches fill first
!
Illustrative numbers

These figures are simplified examples that assume even traffic and a steady round trip. Real behavior varies. Use the calculation to build intuition and then confirm with your own metrics.

15Measuring: Producer Metrics That Matter

You cannot tune what you cannot see. The producer publishes exactly the numbers you need.

MetricWhat it tells youHow to read it
batch-size-avgAverage size of batches in bytesCompare with batch.size; far below means linger or traffic is limiting
batch-size-maxLargest batch seenClose to batch.size means some batches are hitting the ceiling
records-per-request-avgAverage records in a requestLow values mean little batching
record-queue-time-avgAverage time a record waits in the accumulatorApproximates the delay your batching adds
request-rateRequests sent per secondShould fall as batching improves
request-latency-avgRound trip time of a requestRising values show slow brokers or network
compression-rate-avgRatio of compressed to original sizeLower is better; near one means little benefit
bufferpool-wait-ratioShare of time threads waited for memoryAbove zero means buffer pressure
buffer-available-bytesMemory not currently usedNear zero means the buffer is full
record-error-rate and record-retry-rateFailures and retriesRetries multiply the cost of large batches

Read them as a group

Pattern

Small batches, high request rate

You are under-batching. Raise linger, and check partition counts and flush calls.

Pattern

Batches at maximum size, high queue time

Batches fill too slowly to send, or the sender cannot keep up. Consider a larger batch.size or faster brokers.

Pattern

Buffer nearly empty of free space

Memory pressure. Look at slow acknowledgments before raising buffer.memory.

Pattern

Compression rate near one

Batches are too small or data is not compressible. Test with larger batches.

i
Where to see them

The producer client exposes these metrics through its built-in metrics interface and JMX. Export them to your monitoring system and chart them per producer instance.

16Broker-Side Signals

Well-tuned producers make brokers calmer. Broker metrics confirm that your tuning helped.

The broker measures how long it takes to handle each type of request and how busy its threads are. After tuning producers, look for these changes on the broker.

Broker signalMeaningExpected change after better batching
Produce request rateNumber of produce requests per secondFalls
Request handler idle ratioShare of time request threads are idleRises, meaning more spare capacity
Network processor idle ratioShare of time network threads are idleRises
Produce request queue timeTime a request waits before being handledFalls
Produce total timeWhole time to serve a produce requestMay rise slightly per request, since requests are bigger
Bytes in per secondData volumeUnchanged, since the same data arrives
CPU usageProcessor loadFalls

Interpreting produce time

The total time of a produce request is made of parts: waiting in the queue, local processing, waiting for followers when acks is all, and sending the response. Bigger batches slightly increase the local and replication parts, since there is more data, but they reduce the queue part, because there are fewer requests. Overall, a well-tuned producer lowers the load, even if a single request takes a little longer.

Everyday analogy

Picture a customs officer at an airport. Checking one thousand separate parcels each with its own forms overwhelms the desk. Checking ten pallets, each with a single set of papers, takes each check a little longer but clears the same goods with the desk far less busy. The queue outside shrinks.

!
Shared clusters

Many producers share the same brokers. One badly tuned producer sending tiny batches at a high rate can slow everyone. Watch broker metrics as a whole and find the heavy request senders when idle ratios fall.

17A Step-by-Step Tuning Method

Change one thing at a time, measure, and stop when the target is met.

1

Write down targets

State the required throughput, the latency budget and the resource limits. Without targets, tuning never ends.

2

Measure the baseline

Record batch-size-avg, records-per-request-avg, request-rate, record-queue-time and broker idle ratios under realistic load.

3

Set durability first and leave it

Choose acks, idempotence and replication according to business needs. Do not trade them for speed.

4

Raise linger.ms in small steps

Try values such as five, ten and twenty milliseconds. Watch average batch size and queue time. Stop when the gain flattens or the latency budget is near.

5

Raise batch.size if batches hit the ceiling

If batch-size-avg is near batch.size, double the batch size and check memory. If it is far below, leave it alone.

6

Choose compression

Test lz4 or zstd. Compare compression rate, producer CPU and broker load.

7

Check memory

Confirm that buffer.memory suits the number of active partitions and the batch size, with no time spent waiting for memory.

8

Test failure behavior

Restart a broker or add network delay and see how batches, retries and buffers behave.

9

Document and monitor

Record final settings with the reason for each, and alert when metrics drift from the measured norm.

flowchart TD
  A["Set targets and measure baseline"] --> B["Change one setting"]
  B --> C["Run realistic load"]
  C --> D{"Targets met and metrics healthy"}
  D -->|"No"| B
  D -->|"Yes"| E["Test failure cases"]
  E --> F["Document settings and set alerts"]
Figure 5: The tuning loop. Change one thing, measure, repeat.
i
The one-change rule

If you change linger, batch size and compression together and throughput improves, you will not know which change helped. If it worsens, you will not know which one hurt. Change one setting, then measure.

18Tuning Recipes by Workload

Different jobs need different starting points. These recipes are places to begin, not final answers.

Workloadlinger.msbatch.sizeCompressionNotes
Interactive, very low latency0 to 2DefaultNone or lz4Accept smaller batches; keep partitions per producer modest
Balanced event collection5 to 2032 to 128 KiBlz4 or zstdTypical starting point for application events
High throughput logging or metrics20 to 100128 to 512 KiBzstd or lz4Check memory carefully across many partitions
Bulk load or backfill100 or more512 KiB to 1 MiBzstdDelay is acceptable; watch broker limits
Large messages5 to 20At least a few times the message sizeDepends on dataAlign request and broker limits
Very many partitionsHigher than usualSmaller than usuallz4 or zstdBatches fill slowly; watch total memory

How to use a recipe

Step 1

Pick the nearest row

Choose the workload that looks most like yours as a starting point.

Step 2

Test with your own data

Message size, key spread and compressibility change results, so measure with real samples.

Step 3

Adjust from evidence

Use the metrics of chapter fifteen to move up or down.

!
Numbers are not universal

Published recommendations come from particular hardware, message shapes and Kafka versions. Use them to save time on the first guess, not as proof that your system needs the same values.

19The Consumer Side: Fetch Batching

Consumers have their own version of batching. It controls how much data one fetch request brings back.

Just as producers batch messages before sending, consumers batch what they receive. A consumer sends a fetch request to a broker, and the broker replies with data from one or more partitions. Several settings shape that reply.

SettingDefaultMeaning
fetch.min.bytes1 byteThe broker waits until at least this much data is available before answering
fetch.max.wait.ms500 msThe longest the broker waits for fetch.min.bytes to accumulate
fetch.max.bytes50 MiBMaximum data returned by a whole fetch response
max.partition.fetch.bytes1 MiBMaximum data returned per partition
max.poll.records500Maximum records returned to your code by one poll call

How they resemble producer settings

Match

fetch.min.bytes and fetch.max.wait.ms

Together they work like batch.size and linger.ms: wait for enough data, but not longer than a limit.

Match

max.partition.fetch.bytes

Bounds the amount taken per partition, like a batch ceiling.

Match

max.poll.records

Controls how much work one loop iteration receives, which affects processing time and rebalancing.

Raising fetch.min.bytes reduces the number of fetch requests and lowers broker load, at the cost of latency up to fetch.max.wait.ms. This is a good change for consumers that process data in bulk and do not need every message the moment it arrives. On the other hand, a consumer that reads a topic with very large batches must have fetch limits big enough to hold at least one full batch, or it cannot make progress.

Everyday analogy

Think of a shopper who visits the market. Buying one apple per trip wastes time, so the shopper decides to leave the market only after collecting enough for the week, but never stays longer than an hour. Fetch min bytes is “enough for the week”, and fetch max wait is “no more than an hour”.

i
Balance both ends

Well-tuned producer batches do not help if consumers fetch tiny amounts at a fast rate. Review both sides together when a topic carries heavy traffic.

20Streams, Connect and Other Frameworks

You often use producers indirectly. The same settings apply, but you must know where to set them.

Kafka Streams

Producer settings with a prefix

A Streams application creates internal producers. You pass producer settings through the Streams configuration using a producer prefix. Streams also flushes on each commit, which affects batch size, especially with a short commit interval.

Kafka Connect

Worker and connector overrides

Source connectors use producers. Settings go in the worker configuration with a producer prefix, and connectors can override them if the worker allows overrides.

Spring and frameworks

Framework properties

Application frameworks expose Kafka producer properties under their own names. Find the mapping in their documentation and check what defaults the framework itself sets.

Log shippers

Agent settings

Agents that ship logs to Kafka often have their own batching layer on top of the producer. Tune both layers so they do not fight each other.

The commit interval effect in Kafka Streams

Kafka Streams flushes its producers whenever it commits progress. With exactly-once processing, the commit interval defaults to a tenth of a second, which means batches are forced out at least ten times per second regardless of linger settings. Very small commit intervals therefore limit batch size. If your Streams application shows tiny batches and you can accept a slightly longer delay in results, raising the commit interval is the effective lever.

!
Flush calls shrink batches

Any code that calls flush after every message, or every few messages, turns batching off. It is common in wrapper libraries and tests. Search your code for flush calls before spending time on tuning.

21Sizing Producer Memory

A simple estimate shows whether your batch settings fit inside the memory you have given the producer.

Memory used by open batches is roughly the number of partitions the producer writes to actively, multiplied by batch.size, multiplied by the number of batches per partition that may be waiting or in flight at once. To this add space for compressed copies and for the requests that are being sent. A generous rule is to allow two to three times batch.size per active partition.

1

Count active partitions

How many partitions does this producer instance write to in a typical minute?

2

Multiply by batch.size

This gives the memory for one open batch on each active partition.

3

Allow for in-flight batches

Multiply by two or three so that sent batches waiting for acknowledgment do not block new ones.

4

Compare with buffer.memory

If the estimate exceeds the buffer, reduce batch.size, reduce partitions per producer, or raise the buffer.

An example

A producer instance writes to 120 partitions with a batch.size of 128 kibibytes. One open batch on each partition takes 120 times 128 kibibytes, which is about 15 mebibytes. Allowing three times that for in-flight batches gives about 45 mebibytes. The default buffer of 32 mebibytes is too small, so the producer would spend time waiting for memory. Either raise the buffer to 64 mebibytes, or reduce the batch size to 64 kibibytes, which brings the estimate to about 22 mebibytes.

InputValueResult
Active partitions120
batch.size128 KiB15 MiB for open batches
In-flight allowanceThree timesAbout 45 MiB needed
Default buffer.memory32 MiBToo small; memory waits appear
Fix option Abuffer.memory 64 MiBFits with room
Fix option Bbatch.size 64 KiBAbout 22 MiB; fits in the default
i
Also mind the heap

The producer’s buffer lives in the application’s memory. Make sure the application has enough heap for the buffer plus its own work, or long garbage collection pauses will appear as latency spikes.

22Advantages, Disadvantages and Trade-offs

Batching is one of the best bargains in Kafka, but it is not free. Know both sides.

Advantages of good batching

  • Far fewer network requests, so less overhead per message.
  • Lower CPU use on producers and brokers.
  • Better compression, which saves network and disk.
  • Higher total throughput from the same hardware.
  • Calmer brokers, leaving room for other clients.
  • Lower cost on cloud networks that charge by traffic.

Disadvantages and risks

  • Added waiting time for messages in a slow stream.
  • More memory used by producers.
  • Larger loss when a producer crashes, because unsent messages disappear with it.
  • Bigger retries after a failure, since a whole batch is sent again.
  • One bad record can affect the rest of its batch.
  • More settings that must agree with each other.

Trade-offs in plain words

You gainYou payWhen it is worth it
ThroughputLatencyWhen a few milliseconds do not matter to the user
CompressionCPU and small delayWhen data is text-like and traffic is large
Fewer requestsMemoryWhen the application has memory to spare
Simplicity of defaultsLower efficiencyWhen traffic is small and not worth tuning
Everyday analogy

A moving company that packs one big truck is cheaper per box, but if the truck breaks down, more boxes are delayed at once. Smaller trucks cost more per box, yet each failure hurts less. Choosing the truck size is choosing between efficiency and the size of each loss.

23Performance and Scalability

Batching decides how far one producer, and one cluster, can scale.

Each producer instance has a maximum request rate it can sustain before its sender thread or network becomes the limit. Bigger batches lift that limit because each request carries more work. When you add more producer instances, though, each one sends its own small batches unless it too is tuned. Ten instances with poor batching can produce ten times the request load of one.

Producer scaling

Fewer, busier producers

A single producer sharing one buffer usually forms better batches than many small producers. Reuse the producer object across threads.

Partition scaling

Watch the spread

More partitions mean each gets fewer messages per second and batches fill slower. Add partitions with awareness of this effect.

Broker scaling

Request handling capacity

Brokers spend effort per request. Fewer, larger requests stretch broker capacity further.

Network scaling

Compression helps

Compressed batches lower bandwidth, which matters between data centers and clouds.

i
Share the producer

The producer is safe to use from many threads. Creating one per thread or per message splits traffic into many small buffers and wastes the benefit of batching.

24High Availability and Reliability

Batching interacts with failures. Understand what happens to a batch when things go wrong.

Retries

When a request fails with a temporary error, the producer retries the whole batch. With idempotence enabled, the broker recognizes repeated batches and discards duplicates, so retries are safe. Without idempotence, a retry after a lost acknowledgment may store the batch twice. Large batches make a duplicate larger, which is another reason to keep idempotence on.

Timeouts

The delivery timeout covers everything from the moment a record is added until it is acknowledged, including the time spent waiting in the buffer. If linger, retries and broker delays together exceed that limit, records fail. Keep the delivery timeout larger than linger plus the request timeout.

Batch splitting

If a batch turns out to be too large for the broker to accept, the producer may split it into smaller ones and try again. This wastes work. Metrics for batch splits, when present, are a hint that size limits are not aligned.

Producer crashes

Records still sitting in the buffer are lost if the application dies. Larger linger times mean more records at risk. Applications that cannot lose data should call flush during a controlled shutdown, and should wait for acknowledgments before treating work as done.

flowchart TD
  A["Batch sent to leader"] --> B{"Acknowledged in time"}
  B -->|"Yes"| C["Records marked done"]
  B -->|"No, temporary error"| D["Retry same batch"]
  D --> E{"Idempotence on"}
  E -->|"Yes"| F["Broker drops duplicates"]
  E -->|"No"| G["Possible duplicate batch"]
  D --> H{"Delivery timeout reached"}
  H -->|"Yes"| I["Records fail and error is reported"]
Figure 6: What happens to a batch when an acknowledgment does not arrive.
!
Do not confuse speed with safety

Setting acks to zero or one to make batches finish faster increases the chance of lost data. Choose durability first, then tune batching within that choice.

25Security and Governance

Batch settings look like performance knobs, but they also touch security and fair use.

Quotas

Protect the cluster

Brokers can limit how much data or request time each client may use. A producer that sends too aggressively will be slowed down, and the throttle time appears in its metrics.

Encryption

Cost of TLS

Encrypted connections add CPU work for each request. Fewer, larger requests reduce that cost per message.

Authorization

Who may produce

Access control lists decide which identities may write to which topics. Tuning does not replace them.

Config control

Review changes

Producer settings live in application code or files. Treat them like other production configuration, with review and version history.

Denial of service

Limit oversized requests

Broker size limits stop a client from sending enormous requests that strain memory.

Data exposure

Compression and secrets

Compression before encryption can leak information in rare designs when attackers control part of the data. Keep this in mind for sensitive payloads.

i
Governance habit

Publish approved producer profiles, such as “low latency” and “high throughput”, so teams pick a tested set of values instead of inventing their own.

26Monitoring, Logging and Alerting

Turn the metrics of chapter fifteen into dashboards and alerts that catch problems early.

AlertCondition (example)Likely cause
Batches too smallbatch-size-avg falls far below its normal rangeTraffic drop, flush calls added, partition count change
Delay too highrecord-queue-time-avg exceeds the latency budgetLinger raised, sender saturated
Memory pressurebufferpool-wait-ratio above zero for minutesSlow brokers or undersized buffer
Request latency risingrequest-latency-avg well above baselineBroker overload or network trouble
Throttlingproduce-throttle-time above zeroClient quota reached
Errorsrecord-error-rate above zeroTimeouts, size limits, authorization

Logging

Producer logs at the warning level report timeouts, expired batches and disconnections. Send them to a central place and search them during incidents. Log the effective configuration at startup, so you can see what values a running instance actually uses, rather than what you believe you set.

Everyday analogy

A car dashboard shows speed, fuel and engine heat. You do not stare at it all the time, but warning lights tell you when to look. Metrics are the dials, alerts are the warning lights.

i
Alert on change, not only on limits

A sudden halving of average batch size is a sign of trouble even if no fixed limit is crossed. Compare with the same time last week where possible.

27Failure Scenarios and How to Read Them

When something breaks, batch metrics often show the first clue.

SymptomPossible causeWhat to checkTypical fix
Timeouts expiring batchesBroker slow, delivery timeout too shortrequest-latency, broker load, timeout valuesRelieve brokers; align timeouts with linger
Send calls blockingBuffer fullbufferpool-wait-ratio, available bytesFix slow acknowledgments; resize buffer
Record too large errorRecord above a size limitmax.request.size and broker limitsAlign limits or shrink records
High CPU on producerHeavy compression or tiny batchesCompression rate, batch sizeChange codec or raise linger
Latency spikes at low trafficLinger too long for slow streamsrecord-queue-timeLower linger for this producer
Uneven partition loadHot keyPer-partition trafficImprove key choice
Throughput drops after upgradeDefault values changedEffective config logSet values explicitly
flowchart TD
  A["Producer slow or failing"] --> B{"Send calls blocking"}
  B -->|"Yes"| C["Check buffer and acknowledgment speed"]
  B -->|"No"| D{"Batches expiring"}
  D -->|"Yes"| E["Check broker health and timeouts"]
  D -->|"No"| F{"Batches tiny"}
  F -->|"Yes"| G["Check linger, flush calls, partitions"]
  F -->|"No"| H["Check compression and CPU"]
Figure 7: A simple path for diagnosing a struggling producer.

28Testing and Benchmarking

Measure with realistic tests before changing production.

Kafka ships with a producer performance test tool. It generates messages of a chosen size at a chosen rate and reports throughput and latency percentiles. You pass the same producer settings you plan to use. It is useful for comparing settings side by side on a test cluster.

1

Use a similar cluster

Match broker count, replication factor, disks and network as closely as you can.

2

Use realistic messages

Real payloads compress differently from random bytes. Use samples of your own data where possible.

3

Warm up first

Ignore the first seconds while connections and caches settle.

4

Run each setting several times

Single runs can mislead. Compare averages and high percentiles.

5

Look at tail latency

The slowest one percent of messages often matters more than the average.

6

Test at rates you expect and at peaks

Settings good at peak may be poor at quiet times, and the reverse.

!
Beware of unlimited test rates

A test that sends as fast as possible fills batches instantly, hiding the effect of linger. Test also at fixed realistic rates.

29Design Patterns and Anti-patterns

Patterns that repeatedly work, and mistakes that repeatedly cause trouble.

Pattern

Shared, long-lived producer

Context: Many threads in one application send messages.

Decision: Create one producer for the application and share it.

Consequence: Batches fill from all threads, and connections are reused.

Pattern

Small linger plus compression

Context: Moderate traffic and a latency budget of tens of milliseconds.

Decision: Set a linger of a few milliseconds and use lz4 or zstd.

Consequence: Most of the batching gain with a small delay.

Pattern

Separate producers by workload

Context: One application sends both urgent alerts and bulk logs.

Decision: Use two producers with different settings.

Consequence: Urgent messages are not delayed by bulk-oriented linger.

Anti-pattern

Producer per message

Problem: Creating and closing a producer for each message.

Effect: No batching, constant connection setup, heavy load.

Better: Keep one producer alive.

Anti-pattern

Flush after every send

Problem: Calling flush to make sure each message leaves at once.

Effect: Batches contain one record.

Better: Use callbacks and let batches form.

Anti-pattern

Huge batch size with no linger

Problem: Raising batch.size alone and expecting bigger batches.

Effect: Memory is reserved but batches stay small.

Better: Raise linger too, or fix the real limit.

30Best Practices and Common Mistakes

A short checklist to keep tuning sane.

Best practices

  • Start from measurements, not from advice on the internet.
  • Set a latency budget before tuning.
  • Change one setting at a time.
  • Enable idempotence and choose acks for durability first.
  • Use lz4 or zstd unless you have a reason not to.
  • Share one producer across threads.
  • Align size limits on producer, broker and topic.
  • Log effective configuration and chart batch metrics.
  • Set important values explicitly, so upgrades do not surprise you.

Common mistakes

  • Raising batch.size and ignoring linger.
  • Calling flush after every message.
  • Creating a producer for every request.
  • Trading durability for speed without a decision.
  • Copying settings from a different workload.
  • Forgetting the memory cost of many partitions.
  • Ignoring consumer fetch settings.
  • Testing only with unlimited send rates.
  • Never checking metrics after the change.
i
The best change is often a small one

A modest linger and a good codec solve most cases. Reach for large values only when metrics show they are needed.

31Real-World Examples

These are illustrations of common situations, not reports about specific companies.

Clickstream collection for a website

A website sends a message for every click. Thousands of small events arrive per second. A linger of about ten to twenty milliseconds, a batch size of several tens of kibibytes and lz4 compression cut requests sharply. A delay of twenty milliseconds is invisible to analysts reading dashboards.

Payment confirmation events

A payment service must publish an event before responding to a customer. Here the latency budget is strict, so linger stays near zero and acks is all with idempotence on. Batching gains are modest, but volume is low, so this is fine.

Log shipping from many servers

Thousands of servers ship logs. Each agent has low volume, so batches fill slowly. Raising linger to a few hundred milliseconds and compressing the batches saves large amounts of bandwidth, and logs are read later, so the delay is acceptable.

Nightly data backfill

A migration job copies millions of old records into a topic. Nobody waits for individual messages. Large batches, a long linger and zstd compression finish the job faster and with less load on the cluster.

Sensor readings from devices

Small readings arrive from a gateway that serves many devices. Messages are tiny, so batch size matters less than linger. A short linger groups hundreds of readings per batch with little delay.

32Glossary

Plain meanings for the words used in this guide.

TermMeaning
ProducerA program or library that sends messages to Kafka.
BrokerA Kafka server that stores messages.
TopicA named stream of messages.
PartitionOne ordered slice of a topic.
RecordOne message with key, value and metadata.
BatchA group of records for one partition sent together.
RequestOne network call carrying batches for one broker.
Record accumulatorThe producer’s in-memory area where batches form.
Sender threadThe background worker that ships batches to brokers.
batch.sizeMaximum size in bytes of a batch for one partition.
linger.msHow long the producer waits for more records before sending.
buffer.memoryTotal memory the producer may use for unsent records.
BackpressureSlowing down senders when a buffer is full.
CompressionShrinking data to save space and bandwidth.
IdempotenceProtection against duplicate writes when retrying.
Acknowledgment (acks)How many brokers must confirm a write.
ThroughputAmount of data handled per second.
LatencyTime taken for one message to be stored.
QuotaA limit on how much a client may use.

33Frequently Asked Questions

Short answers to questions that come up again and again.

Q1 Is a bigger batch.size always better?

No. It only raises the ceiling. If batches never reach the ceiling, a bigger value wastes memory and changes nothing.

Q2 What should linger.ms be?

It depends on your latency budget. A few to a few tens of milliseconds is a common starting range. Measure and adjust.

Q3 Does batching change message order?

Within one partition, order is kept, provided idempotence is on or in-flight requests are limited. Across partitions, there is no global order anyway.

Q4 Does batching cause data loss?

Not by itself. Unsent records in memory are lost if the application crashes, so flush during shutdown and use acknowledgments properly.

Q5 Why are my batches tiny even with a large batch.size?

Common reasons are linger at zero with low traffic, many partitions, flush calls, or a producer created per message.

Q6 Which compression should I use?

lz4 is fast and light on CPU. zstd usually compresses better. Test on your data.

Q7 Is compression done per message or per batch?

Per batch. That is why larger batches compress better.

Q8 What does the sticky partitioner do?

For records without keys, it fills one partition’s batch before moving to another, which produces fuller batches than spreading each record across partitions.

Q9 Do defaults change between Kafka versions?

They can. Check the documentation for your version and set important values explicitly.

Q10 Should consumers be tuned as well?

Yes, when traffic is heavy. Fetch settings act like consumer batching and affect broker load.

Q11 How do I know tuning worked?

Average batch size rises, request rate falls, broker idle ratios improve, and latency stays within budget.

Q12 What if I need the lowest possible latency?

Keep linger near zero, use light or no compression, and accept smaller batches. Give latency-critical messages their own producer.

Q13 Can one producer serve many threads?

Yes, and it should. Sharing improves batching and saves connections.

Q14 Should I raise linger on a topic with almost no traffic?

Usually not. If only a few records arrive each second, waiting rarely adds a second record to the batch. You add delay and gain almost nothing. Batching pays off when many records arrive within the waiting window, so measure the arrival rate per partition before deciding.

Q15 Can batching hide a slow broker?

It can mask the problem for a while. Buffers absorb short slowdowns, so senders see no delay at first. When the buffer fills, calls to send begin to block and errors follow. Watch request latency and buffer metrics together, so a slow broker is noticed before the buffer runs out.

Q16 How often should I revisit these settings?

Review them whenever traffic changes a lot, partition counts change, message sizes change, or you upgrade Kafka clients. Settings that were ideal for last year’s traffic may be wasteful or too cautious today. A short review each quarter, guided by the dashboard, is usually enough.

34Summary and Key Takeaways

Batch size tuning is the craft of balancing waiting time against efficiency, one measured step at a time.

Kafka producers gather records into batches per partition and send them to brokers together. Batch size, linger, compression and memory decide how full those batches are. Good tuning lowers the load on brokers and networks while keeping delay within what the business accepts. It starts with a latency budget, proceeds with careful measurement, and ends with monitoring that keeps the result healthy.

Key Takeaways

  • A batch is a group of records for one partition; batch.size is a ceiling, not a target.
  • linger.ms is often the more powerful lever, because it lets batches fill before sending.
  • Compression works per batch, so bigger batches compress better.
  • Buffer memory, partition count and batch size must fit together, or the producer blocks.
  • Choose durability settings first, then tune batching within them.
  • Change one setting at a time and watch batch-size-avg, queue time and broker idle ratios.
  • Consumers have their own fetch batching; tune both ends of the pipe.