Skip to content

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

Kafka Message Compression

Kafka supports message compression to reduce network bandwidth and storage requirements. Compression operates at the batch level, providing efficient encoding of multiple messages. This guide covers compression codecs, configuration, and performance trade-offs.

Batch compression from producer through broker storage to consumerBatch compression from producer through broker storage to consumerProducerMessagesBrokerConsumerMessagesRecord Batch(Uncompressed)Compressed BatchMsg 1Msg 2Msg 3Log Segment(Compressed)DecompressedRecord BatchMsg 1Msg 2Msg 3Compression applied toentire batch, notindividual messagescompressproducefetchdecompress

CodecIDCPU CostRatioLatencyUse Case
None0None1:1LowestLow latency required
GZIP1High4-8:1HigherMaximum compression
Snappy2Low2-3:1LowBalanced default
LZ43Low2-4:1LowestHigh throughput
ZSTD4Medium3-6:1MediumBest ratio/speed

Illustrative figures

Compression ratios and CPU costs vary by data type, batch size, and hardware. Treat the tables and charts as directional guidance, not guarantees.

Compression Codec Trade-offsCompression Codec Trade-offsCompression RatioCompression SpeedDecompression SpeedGZIP: ████████████ZSTD: █████████LZ4: ██████Snappy: █████LZ4: ████████████Snappy: ██████████ZSTD: ███████GZIP: ███LZ4: ████████████Snappy: ██████████ZSTD: █████████GZIP: █████

# Enable compression
compression.type=lz4
# Batch settings affect compression efficiency
batch.size=65536
linger.ms=10
# Broker-level compression policy
compression.type=producer # Use producer's codec (default)
# compression.type=lz4 # Force specific codec
# compression.type=uncompressed # Decompress all
# Per-topic override
# kafka-configs.sh --alter --topic my-topic \
# --add-config compression.type=zstd

Consumers automatically decompress messages. No configuration required:

// Decompression is transparent to consumer
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
// record.value() is already decompressed
String value = record.value();
}

Batch compression in the producer sender pathBatch compression in the producer sender pathRecordAccumulatorPartition QueueBatch 1 (building)SenderNetworkBatch 2 (ready)Record ARecord BRecord CCompressionCompressedPayloadCompress entire batch:- Better ratio than per-message- Amortized CPU cost- Single CRCdraincompress

Larger batches compress more efficiently:

Batch SizeCompression Ratio (LZ4)CPU per Message
1 KB1.5:1High
16 KB2.5:1Medium
64 KB3.5:1Low
256 KB4.0:1Very Low
# Larger batches = better compression
batch.size=131072 # 128 KB
# Allow time for batch accumulation
linger.ms=20
# Limit memory for batching
buffer.memory=67108864 # 64 MB

Best compression ratio but highest CPU cost.

compression.type=gzip

Characteristics:

  • Compression ratio: 4-8:1
  • Algorithm: DEFLATE (LZ77 + Huffman)
  • Java implementation: java.util.zip.GZIPOutputStream
  • Best for: Archival, bandwidth-constrained networks

Fast compression with moderate ratio. Google-developed.

compression.type=snappy

Characteristics:

  • Compression ratio: 2-3:1
  • Algorithm: LZ77 variant
  • Library: org.xerial.snappy
  • Best for: General purpose, legacy compatibility

Fastest compression and decompression.

compression.type=lz4

Characteristics:

  • Compression ratio: 2-4:1
  • Algorithm: LZ77 variant optimized for speed
  • Library: net.jpountz.lz4
  • Best for: High-throughput, latency-sensitive

Best balance of ratio and speed. Facebook-developed.

compression.type=zstd

Characteristics:

  • Compression ratio: 3-6:1
  • Algorithm: FSE + Huffman + LZ77
  • Library: com.github.luben.zstd-jni
  • Available: Kafka 2.1.0+
  • Best for: New deployments, optimal trade-off

ZSTD Compression Levels (Kafka 2.4+):

# ZSTD compression level (1-22, default 3)
# Higher = better ratio, more CPU
compression.zstd.level=3
LevelRatioSpeedUse Case
1LowerFastestReal-time
3BalancedFastDefault
9HigherSlowerBatch processing
19+HighestSlowestArchival

End-to-end compressed batch flow including replicationProducerLeader BrokerFollower BrokerConsumerProducerProducerLeader BrokerLeader BrokerFollower BrokerFollower BrokerConsumerConsumerCompress batchSend compressed batchStore compressedReplicate compressedStore compressedFetch requestSend compressed batchDecompress batchData stored compressedNo re-compression
compression.typeBehavior
producerStore as-is (default)
uncompressedDecompress before storing
gzip/snappy/lz4/zstdRe-compress with specified codec

Re-compression Overhead

Setting broker compression.type to a different codec than producer causes re-compression, significantly increasing broker CPU usage.


Throughput vs Compression LevelThroughput vs Compression LevelNo CompressionLZ4/SnappyZSTDGZIPHighest throughputHighest bandwidthHigh throughput~60% bandwidthGood throughput~40% bandwidthLower throughput~25% bandwidth
ScenarioProducer CPUBroker CPUConsumer CPU
No compressionLowLowLow
LZ4+10-15%0%+10-15%
ZSTD+20-30%0%+15-25%
GZIP+50-100%0%+30-50%

Example with JSON log data:

CodecOriginal SizeCompressedSavings
None100 MB100 MB0%
Snappy100 MB45 MB55%
LZ4100 MB40 MB60%
ZSTD100 MB30 MB70%
GZIP100 MB25 MB75%

Data TypeCompressibilityRecommended Codec
JSONHighZSTD or LZ4
AvroMedium-HighLZ4 or ZSTD
ProtobufMediumLZ4
Already compressed (images, video)Very LowNone
Random/encrypted dataNoneNone
Codec selection by message contentCodec selection by message contentAnalyze message contentAlready compressed?(images, video, etc.)yesnoAvoid double compressioncompression.type=noneHigh compressibility?(JSON, text, logs)yesnocompression.type=zstdLatency critical?yesnocompression.type=lz4compression.type=snappy

MetricDescription
compression-rate-avgAverage compression ratio
record-size-avgAverage uncompressed record size
batch-size-avgAverage compressed batch size
produce-throttle-time-avgTime throttled by quota limits
MetricDescription
fetch-size-avgAverage compressed fetch size
records-consumed-rateRecords per second (after decompression)
Terminal window
# Check compression ratio
kafka-run-class.sh kafka.tools.JmxTool \
--jmx-url service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi \
--object-name kafka.producer:type=producer-metrics,client-id=* \
--attributes compression-rate-avg

SymptomCauseSolution
Producer CPU spikeHigh compression levelUse LZ4 or lower ZSTD level
Consumer CPU spikeDecompression overheadScale consumers
Broker CPU spikeRe-compressionSet compression.type=producer
SymptomCauseSolution
Ratio near 1:1Already compressed dataDisable compression
Ratio near 1:1Small batch sizeIncrease batch.size
Ratio near 1:1Random/encrypted dataDisable compression
org.apache.kafka.common.errors.CorruptRecordException:
Record is corrupt (stored crc = X, computed crc = Y)

Causes:

  • Network corruption
  • Disk corruption
  • Mismatched compression codec
  • Bug in compression library

Resolution:

  1. Check network health
  2. Verify disk integrity
  3. Ensure consistent codec across clients
  4. Update Kafka client version

FeatureMinimum Version
GZIP, Snappy0.8.0
LZ40.8.2
ZSTD2.1.0
ZSTD compression level2.4.0
Broker-side compression0.10.0

PracticeRationale
Use ZSTD for new deploymentsBest ratio/speed trade-off
Use LZ4 for latency-sensitiveFastest compression
Increase batch sizeBetter compression efficiency
Match producer and broker codecAvoid re-compression
Monitor compression metricsDetect issues early
# High-throughput, good compression
compression.type=lz4
batch.size=131072
linger.ms=10
# Maximum compression
compression.type=zstd
compression.zstd.level=6
batch.size=262144
linger.ms=50
# Minimum latency
compression.type=none
batch.size=16384
linger.ms=0