Module A-11·27 min read

Protocol Buffers vs JSON-over-HTTP, Kafka consumer group mechanics for 500K msg/sec, and event sourcing for UPI transaction ledgers.

Module 10 — High-Performance IPC: gRPC, Kafka & Event Streams

What this module covers: When your blockchain indexer needs to stream 500K events/second to a downstream analytics service, JSON-over-HTTP REST adds measurable overhead at every layer: HTTP/1.1 per-request connection overhead, JSON serialization CPU cost, and protocol parsing latency. gRPC over HTTP/2 with Protocol Buffers eliminates most of this. Kafka adds persistence, replay, and fault tolerance. This module covers the exact performance differences, the implementation of streaming gRPC endpoints in Node.js, Kafka consumer group mechanics for high-throughput consumption, and event sourcing for payment ledgers that need full state replay.


The Baseline: JSON-over-HTTP REST Overhead

Before measuring alternatives, establish what REST actually costs at high throughput:

Per-request overhead:

  1. TCP connection (or TLS handshake if not keep-alive) — 1–3ms
  2. HTTP/1.1 header parsing — variable, grows with header count
  3. JSON.parse() on request body — ~1ms per 100KB
  4. Business logic
  5. JSON.stringify() on response — ~0.5ms per 100KB
  6. HTTP response headers serialization

For a payment gateway doing 10,000 inter-service calls/second:

  • JSON serialization at 5KB average payload: ~50ms total per second
  • HTTP header parsing: ~30ms total per second
  • TCP connection overhead (without keep-alive): 1,000–3,000ms per second

With HTTP keep-alive: TCP overhead drops. JSON overhead remains. At 500K calls/second, JSON becomes the dominant cost.


Protocol Buffers: Binary Serialization

Protocol Buffers (protobuf) is a binary serialization format. You define a schema in a .proto file, and a code generator produces type-safe encoder/decoder functions.

protobuf

Generating Node.js code:

bash

Size comparison for a typical transaction:

FormatEncoded sizeParse time (1K messages)
JSON (human-readable)340 bytes18ms
JSON (minified)220 bytes12ms
Protobuf binary82 bytes2ms

Protobuf is 4–5x smaller and 6–9x faster to parse. At 500K messages/second, this difference is:

  • JSON: 110MB/sec serialization + 6,000ms CPU/sec for parsing
  • Protobuf: 41MB/sec serialization + 1,000ms CPU/sec for parsing

The bandwidth reduction matters for inter-datacenter links. The CPU reduction matters for everything.


gRPC: HTTP/2 + Protocol Buffers

gRPC is an RPC framework that uses HTTP/2 for transport and Protocol Buffers for serialization. It provides:

  • HTTP/2 multiplexing: multiple streams over a single TCP connection
  • Bidirectional streaming: client and server can both stream data simultaneously
  • Type safety: generated stub code handles serialization
  • Load balancing: built-in support for multiple backends

The Four gRPC Call Types

protobuf

Implementing a Streaming gRPC Server in Node.js

javascript

gRPC Client with Retry and Deadline

javascript

gRPC vs REST: Throughput Comparison

MetricREST + JSONgRPC + Protobuf
Payload size (5KB object)5,000 bytes~850 bytes
Serialization (100K msg/sec)~500ms CPU~85ms CPU
Connections (1K clients)1K TCP sockets1 TCP socket (mux)
Latency (p99, same network)8ms2ms
StreamingWorkarounds (SSE, WebSocket)Native (all 4 types)

gRPC is the correct choice for inter-service communication at > 10K calls/second or when bidirectional streaming is required.


Kafka: Distributed Event Ledger

Kafka is a distributed log. Unlike a message queue (which deletes messages after consumption), Kafka retains messages for a configurable retention period. Every consumer reads from its own offset in the log — Kafka does not push messages to consumers; consumers pull.

Core Concepts

Topic: a named log. transactions, blocks, payment-events.

Partition: a topic is split into partitions for parallelism. Each partition is an ordered, immutable log. Within a partition, messages are ordered by offset. Across partitions, there is no ordering guarantee.

Consumer group: a set of consumers that collectively read a topic. Kafka assigns partitions to consumers — each partition is consumed by exactly one consumer in the group. If you have 8 partitions and 8 consumers: each consumer reads one partition. If you have 8 partitions and 4 consumers: each consumer reads two partitions.

javascript

Producer: Batching and Compression

javascript

Compression at 500K messages/second:

  • LZ4: 2–3x compression, minimal CPU cost. Best for throughput.
  • Snappy: 1.5–2x compression, very fast. Good default.
  • GZIP: 3–5x compression, high CPU. Use for storage efficiency, not throughput.

Consumer Group: Partition Assignment and Rebalancing

javascript

Consumer Lag: The Critical Operational Metric

Consumer lag = (latest offset in topic) - (consumer's current offset).

Lag = 0: consumer is caught up. Lag > 0: consumer is falling behind. Lag growing: consumer cannot keep up with producer rate.

javascript

Event Sourcing for Payment Ledgers

Event sourcing stores every state change as an immutable event, instead of storing current state. The current state is derived by replaying all events.

text

Why event sourcing for payment ledgers:

  1. Audit trail: every transaction is immutable. You can prove the exact sequence of operations that led to any balance.

  2. Replay: if you discover a bug in your balance calculation logic, replay all events with the fixed logic to get correct current balances.

  3. Temporal queries: what was account X's balance on March 15th? Replay events up to March 15th.

  4. Kafka as the event store: Kafka's log retention makes it a natural event store.

javascript

Snapshots: Avoiding Full Replay

For accounts with millions of historical events, replaying from the beginning is impractical. Snapshots cache the balance at a point in time:

javascript

RabbitMQ vs Kafka: When Each Is Correct

KafkaRabbitMQ
ModelPull-based logPush-based queue
Message retentionConfigurable (days/weeks)Deleted after consumption
ReplayYes — replay from any offsetNo — consumed messages are gone
Throughput1M+ messages/sec~50K messages/sec
OrderingWithin partitionPer-queue (with single consumer)
Consumer groupsBuilt-inVia competing consumers
Use caseEvent sourcing, audit logs, stream processingTask queues, RPC, work distribution

For a blockchain indexer: Kafka. You need replay capability (debug consumer bugs), high throughput (500K tx/sec), and consumer groups for parallel processing.

For payment notification emails: RabbitMQ. You need exactly-once delivery, message acknowledgement, dead letter queues, and retry logic. Kafka can do this but the configuration is more complex.


Production Incident: Kafka Partition Imbalance Causing Consumer Hotspot

Context: A payment event stream with 12 partitions, 12 consumer instances. Partition key was senderId. One major payment aggregator (a large e-commerce platform) sent 40% of all payment events. All events from this sender went to one partition.

What happened:

One consumer instance was processing 40% of total volume. Its consumer lag grew continuously. The other 11 instances were at 5% each. Rebalancing couldn't help — the problem was the partition key, not the number of consumers.

The fix — composite partition key:

javascript

Also added consumer lag alerting per partition (not just total lag) to detect hotspots early:

javascript

Summary

ConceptKey Takeaway
Protobuf vs JSON4–5x smaller, 6–9x faster parse. Critical at > 100K msg/sec.
gRPC over HTTP/2Multiplexed streams, 4 call types. Native streaming support. 4x lower latency than REST.
gRPC server streamingcall.write() pushes to client. call.on('cancelled') for cleanup.
Kafka retentionMessages persist after consumption. Replay from any offset.
Consumer groupsPartitions assigned to consumers. One partition → one consumer per group.
Consumer lagGrowing lag = consumer can't keep up. Scale consumers or optimize processing.
Partition keyHigh-cardinality composite keys prevent hotspots. Never use a skewed key.
acks: -1Wait for all replicas before confirming publish. Required for durability.
LZ4 compressionBest throughput/CPU ratio. Use for high-volume streams.
Event sourcingImmutable event log. Full history. Replay to any point in time.
SnapshotsCache balance at N events to avoid full replay on every query.
Kafka vs RabbitMQKafka for event streams/replay. RabbitMQ for task queues with ACK semantics.

You now have the communication backbone. Module 11 covers how to keep the code clean as these systems grow — DDD applied to banking ledgers, dependency injection that lets you swap transports, and CQRS that separates the write model from the read model.

Next: Module 11 — Enterprise Architecture for State-Heavy Systems: DDD & Clean Architecture →


Knowledge Check

In high-throughput inter-service communication, what is the primary advantage of using Protocol Buffers over JSON?


When using Kafka as a message broker, what is the relationship between partitions and consumer groups?


Which of the following best describes the core philosophy behind "Event Sourcing" for a payment ledger?

Test your knowledge with more question sets

Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.