• New
The Zilla MCP Gateway is available — governed agent access to your APIs, services, and real-time data.
Read the launch →
New AWS+Aklivity Joint Blog: Secure Cross-Account Access to MSK Serverless
Read on AWS Big Data Blog →

Engineering

October 15, 2026

Encryption and Structured Field Encryption: Zilla Benchmark Series (Part 3)

Zilla Plus delivers high-throughput Kafka encryption with extremely low latency, supporting whole-payload and field-level protection without client changes.

Authors
Ankit Kumar
Team Aklivity

Introduction

Part 1 of this series measured Zilla Plus proxying self-managed Apache Kafka. Part 2 ran the same workload against Confluent Cloud.

In both, Zilla Plus forwarded records without changing them. This post measures what happens when Zilla Plus also encrypts record data on produce and decrypts it on fetch.

We ran four configurations against the same Kafka cluster and the same workload:

  • Direct: clients connect to Kafka with no proxy.
  • TLS passthrough: clients connect through Zilla Plus, records unchanged.
  • Whole-payload encryption: Zilla Plus encrypts the entire record value.
  • Structured field encryption: Zilla Plus encrypts only the schema fields tagged as sensitive.

TL;DR

  • Throughput held in every configuration. All four sustained their target rate for the full 60-minute measurement window with zero publish errors.
  • The proxy hop is small. TLS passthrough added 0.9 ms at p50 and 10.2 ms at p99. 
  • Whole-payload encryption adds a few milliseconds at the median. Over passthrough, it added 3.4 ms at p50 and 37.9 ms at p99.
  • Structured field encryption adds more per record. Over passthrough, it added 14.8 ms at p50 and 56.1 ms at p99, and leaves non-sensitive fields readable downstream.
p99 increase png

Why Encrypt at the Gateway

TLS protects records in transit. Once a record is written to a broker, it is stored in plaintext and readable by anyone with access to:

  • the topic
  • broker disks and snapshots
  • backups, mirrors, and replicated clusters
  • tiered storage

Encrypting record data before it reaches the broker means all of those hold ciphertext.

Doing that in the gateway keeps the work out of application code:

  • No client changes: producers and consumers use standard Kafka clients and the Kafka wire protocol.
  • Central key handling: keys are resolved from a vault configured in Zilla Plus, not distributed to every application.
  • Identity-based decryption: a guard decides which authenticated consumers receive plaintext.

Zilla Plus applies encryption inside its kafka-proxy binding, the same binding used in Part 1 and Part 2.

Whole-Payload Encryption

Whole-payload encryption treats the record value as opaque bytes and encrypts all of it. It needs no schema, so it works for any payload format.

kafka_proxy_encrypt:
  type: kafka-proxy
  kind: proxy
  options:
    topics:
      - name: "*"
        value:
          model: bytes
          transforms:
            guarded:
              inline_guard: []
            encryption:
              vault:
                secrets:
                  - payload-key

‍

On produce, Zilla Plus encrypts the value before forwarding it to Kafka. On fetch, it decrypts the value for consumers that satisfy the guarded clause.

Structured Field Encryption

Structured field encryption parses each record against a schema and encrypts only the fields tagged for protection. Every other field stays readable, so downstream tools can still filter, route, and index on non-sensitive data.

The schema used in this benchmark tags a single field, ssn:

{
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "status": { "type": "string" },
    "ssn": { "type": "string", "x-kind": "pii-encrypt" },
    "notes": { "type": "string" }
  }
}

‍

The Zilla Plus configuration selects fields by that tag:

‍

kafka_proxy_encrypt:
  type: kafka-proxy
  kind: proxy
  options:
    topics:
      - name: "*"
        value:
          model: json
          catalog:
            my_catalog:
              - subject: test-topic-value
                version: latest
          transforms:
            - select:
                - type: structure
                  fields:
                    - tagged:
                        - x-kind: pii-encrypt
              guarded:
                inline_guard: []
              encryption:
                vault:
                  secrets:
                    - payload-key

‍

The flow below shows what Zilla Plus does on each path. Dashed steps run only in structured field encryption; whole-payload encryption skips them and encrypts the full value.

encryption flow png

Adding a new sensitive field is a schema change. The Zilla Plus configuration and the client applications stay the same.

Why Structured Field Encryption Matters

Most records that carry sensitive data are mostly non-sensitive. A payment event might hold an ID, an amount, a merchant, a timestamp, and one card number.

With whole-payload encryption, every consumer that needs the amount or the merchant also needs decrypt access. Plaintext access to the card number spreads to every one of those consumers.

Structured field encryption scopes protection to the fields that need it:

  • Least-privilege access: consumers read non-sensitive fields without decrypt rights. Only consumers that satisfy the guard receive sensitive values in plaintext.
  • Downstream processing keeps working: stream processors, connectors, search indexes, and analytics jobs can still filter, join, and aggregate on unencrypted fields.
  • Records stay schema-valid: encrypted fields keep their place in the record, so schema registries and schema-aware tools continue to work.
  • Sensitivity is declared in the schema: a tag such as x-kind: pii-encrypt marks a field for protection, so data owners define it where the data is defined.

Whole-payload encryption fits records that are sensitive end to end or have no schema, such as secrets or binary blobs.

Benchmark Setup

We used the Aklivity fork of the Linux Foundation's OpenMessaging Benchmark (OMB), as in the previous parts.

topology png

Configurations

Configuration Client connects to What Zilla Plus does
Direct Kafka brokers Not in path
TLS passthrough Zilla Plus, port 9093 Proxies records unchanged
Whole-payload encryption Zilla Plus, port 9095 Encrypts and decrypts the full value
Structured field encryption Zilla Plus, port 9096 Validates JSON against the schema, encrypts and decrypts tagged fields

Security protocol

Every configuration runs TLS end to end.

Configuration Client connection
Direct SSL, straight to Kafka
TLS passthrough SSL to Zilla Plus
Whole-payload encryption SASL_SSL (PLAIN) to Zilla Plus
Structured field encryption SASL_SSL (PLAIN) to Zilla Plus

In the encryption runs, clients authenticate with SASL/PLAIN so the Zilla Plus guard has an identity to evaluate before decrypting on fetch.

Infrastructure

The infrastructure matches Part 1.

Service Instance type Count
Zilla Plus m5.xlarge 3
Kafka brokers m5.xlarge 6
Benchmark clients m5.xlarge 6
Controllers m5.xlarge 3
Prometheus m5.xlarge 1
  • Apache Kafka 3.6.0 with KRaft
  • GP3 EBS: 500 GB, 3,000 IOPS, 125 MB/s per broker

Workload

  • Message size: 1 KiB JSON event (id, status, ssn, notes)
  • Target throughput: about 24 MB/s
  • Topics: 45, with 200 partitions each
  • Producers: 1 per topic
  • Consumers: 3 consumer groups per topic, 1 consumer per group
  • Config: acks=all, linger.ms=10, replication factor 3, min.insync.replicas=2
  • Warm-up: 30 minutes; measurement: 60 minutes

The same JSON payload was used in all four configurations, so the whole-payload and structured runs encrypt identical records.

Encryption details

  • Cipher: AES-GCM with a fresh 12-byte IV per operation and a 16-byte authentication tag, adding 28 bytes per encrypted value.
  • Key source: a filesystem vault on each Zilla Plus instance. The key is resolved once and cached, so no external KMS calls happen on the measured path.
  • Decryption: consumers authenticate through the same guard, so every fetch is decrypted. With 3 consumer groups per topic, Zilla Plus performs three decryptions for each encryption.

Publish Latency

Publish latency is the time from the producer sending a record to receiving the broker acknowledgment.

Percentile (ms) Direct TLS passthrough Whole-payload encryption Structured field encryption
p50 27.1 28.0 31.4 42.8
p75 38.5 39.7 45.7 59.7
p95 62.0 64.9 81.3 98.5
p99 86.3 96.5 134.4 152.6
p99.9 139.4 157.1 220.0 250.5

Added publish latency relative to TLS passthrough:

Percentile Whole-payload encryption Structured field encryption
p50 +3.4 ms (+12%) +14.8 ms (+53%)
p95 +16.4 ms (+25%) +33.6 ms (+52%)
p99 +37.9 ms (+39%) +56.1 ms (+58%)
p99.9 +62.9 ms (+40%) +93.4 ms (+59%)

End-to-End Latency

End-to-end latency: time from the producer sending a record to a consumer receiving it. In the encryption runs, this includes the encrypt on produce and the decrypt on fetch.

Percentile (ms) Direct TLS passthrough Whole-payload encryption Structured field encryption
p50 27 28 32 45
p75 38 40 46 63
p95 62 66 82 105
p99 86 99 135 161
p99.9 139 159 221 262

Added end-to-end latency relative to TLS passthrough:

Percentile Whole-payload encryption Structured field encryption
p50 +4 ms (+14%) +17 ms (+61%)
p95 +16 ms (+24%) +39 ms (+59%)
p99 +36 ms (+36%) +62 ms (+63%)
p99.9 +62 ms (+39%) +103 ms (+65%)

End-to-end numbers track publish latency closely in every configuration. At p50, the gap between publish and end-to-end latency is under 1 ms for whole-payload encryption and about 2 ms for structured field encryption, which covers the decrypt on fetch.

The Cost of Each Layer

Each configuration adds one layer, so the difference between neighbors isolates that layer's publish latency cost:

Layer Compared p50 p95 p99
Proxy hop Passthrough vs. direct +0.9 ms +2.9 ms +10.2 ms
Encryption Whole-payload vs. passthrough +3.4 ms +16.4 ms +37.9 ms
Structure-aware processing Structured vs. whole-payload +11.4 ms +17.2 ms +18.2 ms
layer cost png

Whole-payload encryption runs AES-GCM over the full 1 KiB value. Most of its cost shows up past p95, while the median moves by a few milliseconds.

Structured field encryption encrypts less data, since only the ssn value is ciphertext. Its extra latency comes from the work around the cipher:

  • parsing each record as JSON
  • validating it against the catalog schema
  • locating the tagged fields
  • re-serializing the record with the encrypted field in place

The same steps run in reverse on each fetch.

Whole-Payload Encryption at 60,000 Messages/Second

To evaluate Zilla Plus under a higher-throughput encryption workload, we ran an additional benchmark using a single Kafka topic at 60,000 messages per second. The test measured throughput and latency with whole-payload encryption on produce and decryption on fetch.

Workload and setup

Setting Zilla Plus run
Message size 1 KiB
Target rate 60,000 msg/s
Topics 1
Producers / consumers 1 / 1
Producer settings acks=all, linger.ms=1, batch.size=128 KiB
Durability RF 3, min.insync.replicas=2
Security SASL_SSL
Encryption Whole-payload AES-GCM, decrypted on fetch
Key source Filesystem vault, key cached
Gateway 1 × c7i.xlarge (4 vCPU / 8 GiB), 2 engine workers using 2 vCPU
Brokers 3 × m5n.2xlarge, Apache Kafka 3.6.0
Duration 2-minute warm-up, 5-minute window

Results

Metric Zilla Plus
Throughput 60,085 msg/s
Produce p50 7.1 ms
Produce p95 22.7 ms
Produce p99 41.7 ms
End-to-end p50 8 ms
End-to-end p95 26 ms
End-to-end p99 54 ms
single topic encryption png

Zilla Plus sustained the 60,000 msg/s target with zero publish errors.

How Zilla Achieves This Performance

Zilla Plus keeps encryption overhead low through a streaming-native architecture designed to minimize data movement, memory allocation, and contention on the critical path.

  • Zero-copy, in-place processing. Kafka frames are parsed using flyweights over pooled buffers, avoiding unnecessary copies and object allocations. Encrypted records are rewritten in place, with affected length fields and the CRC updated rather than rebuilding the entire Kafka frame.
  • Pass-through for unchanged traffic. Topics and frames that require no transformation are forwarded directly, avoiding unnecessary processing.
  • Envelope encryption with cached keys. AES-GCM encryption runs locally. With KMS-backed key management, only the small data keys interact with the KMS, not the record payloads. Keys are cached per worker, avoiding per-record KMS calls during steady-state operation. In this benchmark, keys came from a filesystem vault and were cached, with no external KMS calls on the measured path.
  • Shared-nothing workers. Each worker owns its buffers, ciphers, and key cache, confined to a single thread. This eliminates locking and synchronization overhead on the hot path.

Together, these optimizations allow Zilla Plus to enforce encryption at the gateway while sustaining high throughput and keeping added latency low.

Choosing an Encryption Mode

  • Whole-payload encryption fits values that have no schema or are sensitive throughout, such as secrets and binary blobs. It has the lower added latency of the two modes.
  • Structured field encryption fits records that mix sensitive and non-sensitive fields, where downstream consumers need the non-sensitive ones. It also validates every record against its schema, so malformed records are rejected at the gateway.
  • Both modes can run side by side on the same Zilla Plus instance, on separate listeners or topics.

These results are for 1 KiB records at about 24 MB/s across three m5.xlarge gateways. Larger records, higher rates, or more encrypted fields per record will change the numbers and are worth measuring for a specific workload.

Reproducing the Results

The benchmark tooling, Terraform and Ansible deployment, and Zilla Plus configurations are in the Aklivity OpenMessaging Benchmark fork. The deployment guide covers each scenario.

The four configurations map to these run-workloads.sh scenarios:

./confluent-bin/run-workloads.sh ak workloads/confluent-blog-workloads-2cku-1p-1c-1Kb-45topic-200part-24MBps.yaml

./confluent-bin/run-workloads.sh zpak workloads/confluent-blog-workloads-2cku-1p-1c-1Kb-45topic-200part-24MBps.yaml

./confluent-bin/run-workloads.sh zpak-encrypt workloads/confluent-blog-workloads-2cku-1p-1c-1Kb-45topic-200part-24MBps.yaml

./confluent-bin/run-workloads.sh zpak-structured-field-encrypt workloads/confluent-blog-workloads-2cku-1p-1c-1Kb-45topic-200part-24MBps.yaml

Resources

Related Resources

Case Studies

How Baader Bank Uses Zilla Plus to Securely Connect Amazon MSK with External Banking Partners

Announcements

Introducing Zilla Plus 2.0: Enterprise Infrastructure for Real-Time Data and AI

Engineering

Kafka, Kafka Connect, and Schema Registry as Native MCP Tools

Ready to Get Started?

Get started on your own or request a demo with one of our data management experts.

Explore pricing

Straightforward, usage-based pricing with no per-connection surprises — start free and scale when you are ready.

Pricing details

Join the Community

Trade notes with the engineers running Zilla in production, and get help from the team in Slack or Discord.