When Your Events Arrive Like a Firehose: Streaming Architectures That Don’t Lose (or Lie About) Data

Designing high-velocity streaming systems is less about picking Kafka vs Kinesis and more about building reliability and quality guarantees you can explain to customers, auditors, and investors.

High-velocity streaming isn’t hard because Kafka is hard. It’s hard because reliability and truth are hard—and your business runs on both.
Back to all posts

The incident you don’t forget: “Why are dashboards flat?”

I’ve watched teams ship a shiny streaming pipeline, celebrate “real-time analytics,” and then get blindsided two weeks later: dashboards go flat during peak traffic, nobody gets paged, and the VP Sales is making decisions off stale numbers. The postmortem usually reads the same:

  • A high-velocity source (mobile events, CDC from Postgres, or payment webhooks) spiked.
  • Consumers fell behind (lag climbed), then someone “fixed it” by redeploying.
  • Offsets got reset, duplicates poured in, and the data team quietly patched numbers in a notebook.

High-velocity streaming is easy to demo and brutally hard to operate. The goal isn’t “streaming.” The goal is reliable, high-quality data that drives business decisions—with behavior you can predict under load and during failure.

A reference architecture that survives high velocity

At high level, you want a design that assumes things will break and makes recovery boring:

  • Producers: apps, devices, CDC (Debezium), third-party webhooks
  • Durable log: Kafka / Kinesis (this is your replay buffer)
  • Stream processing: Flink / Spark Structured Streaming (state + windows + enrichment)
  • Quality gates: schema registry + contract checks + quarantine/DLQ
  • Sinks: lakehouse (Iceberg/Delta Lake/Hudi) + OLAP (ClickHouse/Druid) when needed
  • Observability: lag, throughput, drop/duplicate rates, DLQ volume, freshness SLOs

The key design choice is treating the log as the system of record for events (within a retention window). That replay capability is what turns “we lost data” into “we’re behind, but recoverable.”

Here’s a concrete Kafka topic setup that’s friendly to high velocity and recovery (tune to your workload, but don’t leave this to defaults):

# Example: create a topic for high-velocity clickstream
kafka-topics \
  --bootstrap-server kafka-1:9092 \
  --create \
  --topic clickstream.v1 \
  --partitions 48 \
  --replication-factor 3 \
  --config retention.ms=604800000 \
  --config min.insync.replicas=2 \
  --config cleanup.policy=delete

Measurable outcome targets (what “good” looks like):

  • P95 end-to-end freshness < 60s during peak (or whatever the business needs)
  • Data loss rate = 0 (enforced by design + monitoring)
  • Duplicate rate < 0.1% (and decreasing)
  • MTTR for pipeline incidents < 30 minutes with replay-based recovery

Reliability mechanics: backpressure, replay, idempotency (the holy trinity)

Most streaming failures aren’t exotic. They’re basic physics: producers can outpace consumers, and sinks slow down at the worst time.

1) Backpressure is a feature, not a bug

If your sink (S3, Iceberg, warehouse) slows down, your processing layer must apply backpressure instead of dropping messages or OOM-ing.

In Flink, you can design for this by keeping state bounded (windows + TTL), and by sizing parallelism with realistic sink throughput.

2) Replay changes the whole game

Set log retention based on how long it realistically takes you to detect and fix issues.

  • If your on-call coverage is thin, 7–14 days retention is often cheaper than rebuilding trust after a silent drop.
  • For regulated domains, retention also supports auditability (within reason—talk to legal).

3) Idempotency prevents “double counting” during recovery

Exactly-once is a loaded term. In practice, you want effectively-once outcomes:

  • Every event has an immutable event_id
  • Your sink supports upsert/merge keyed by event_id (or a deterministic composite key)
  • Your processing job can be restarted without changing the final result

Example: Spark Structured Streaming with watermarking + dedup (common for mobile events):

from pyspark.sql.functions import col

events = (
  spark.readStream.format("kafka")
    .option("kafka.bootstrap.servers", "kafka:9092")
    .option("subscribe", "clickstream.v1")
    .load()
)

parsed = events.selectExpr("CAST(value AS STRING) as json")
# assume you parse into columns: event_id, event_time, user_id, ...

deduped = (
  parsed
    .withWatermark("event_time", "10 minutes")
    .dropDuplicates(["event_id"])
)

# write to a sink that supports upserts/merge (e.g., Delta)
(
  deduped.writeStream
    .format("delta")
    .option("checkpointLocation", "s3://checkpoints/clickstream/")
    .outputMode("append")
    .start("s3://lake/clickstream/")
)

If you can’t do deterministic dedup, you don’t have a streaming system—you have a duplicate generator with a dashboard.

Quality at speed: schemas, contracts, and quarantine lanes

“Data quality” usually gets hand-waved until the CFO asks why revenue numbers changed.

Plain-English definition: data quality is whether the data is fit for its intended use (correct types, valid ranges, consistent meaning). In streaming, quality problems multiply because bad events arrive continuously.

Schema registry + compatibility rules

Don’t let producers ship whatever JSON they feel like today. Use Schema Registry (Avro/Protobuf/JSON Schema) and enforce compatibility.

Example: Confluent Schema Registry compatibility config (backward is a common default):

curl -X PUT \
  -H "Content-Type: application/vnd.schemaregistry.v1+json" \
  --data '{"compatibility":"BACKWARD"}' \
  http://schema-registry:8081/config/clickstream-value

Data contracts that engineering can actually follow

A practical contract includes:

  • Required fields: event_id, event_time, producer, schema_version
  • Allowed nullability + ranges (e.g., price >= 0)
  • Semantic meaning (what does user_id represent? hashed? stable?)

Enforce contracts in CI for producers (yes, even if the producer is a “quick” microservice). If your events are partially AI-generated code, I’ve seen schemas drift weekly because nobody owns the contract.

Quarantine / DLQ to keep the pipeline flowing

If you hard-fail on every malformed event, you’ll page yourself into oblivion. If you accept everything, you’ll corrupt downstream truth.

Use a DLQ (dead-letter queue) or quarantine table:

  • Route invalid events (schema violation, impossible timestamps) to clickstream.dlq
  • Alert on DLQ rate spikes
  • Build a fast remediation loop (top error types, top producers)

Measurable outcomes:

  • DLQ rate < 0.5% steady-state
  • Time-to-fix for top DLQ cause < 1 day
  • Schema break incidents drop to near-zero after compatibility enforcement

Serving business value: stop overbuilding, start landing trustworthy data

A common failure mode is building a complicated real-time serving layer before you’ve stabilized ingestion + quality. The fastest path to business value for many teams is:

  1. Land curated streaming data into a lakehouse table (Iceberg/Delta/Hudi).
  2. Provide “near real-time” analytics via Trino, Databricks SQL, or Snowflake external tables.
  3. Add OLAP (ClickHouse, Druid) only when you can prove query latency or concurrency needs.

Example: Flink SQL writing to an Iceberg table (common pattern for scalable append + compaction workflows):

CREATE TABLE clickstream_iceberg (
  event_id STRING,
  event_time TIMESTAMP(3),
  user_id STRING,
  page STRING,
  producer STRING,
  schema_version STRING,
  WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
  'connector'='iceberg',
  'catalog-name'='prod',
  'catalog-type'='hadoop',
  'warehouse'='s3://lake/warehouse',
  'format-version'='2'
);

Business framing that founders and execs care about:

  • Faster feedback loops: product experiments measured in minutes, not days
  • Lower churn risk: fewer “your numbers are wrong” customer escalations
  • Lower diligence risk: you can explain lineage, retention, and recovery to investors
  • Lower hiring drag: new data engineers aren’t spending their first month firefighting

Operability: define data SLOs, then page the right humans

Plain-English definition: an SLO (Service Level Objective) is a measurable reliability target. For data, it’s usually about freshness and completeness—not “the job ran.”

Data SLO examples that work in the real world:

  • Freshness SLO: P95 event_time → available_in_table < 120 seconds
  • Completeness SLO: ≥ 99.9% of expected partitions arrive within 15 minutes
  • Correctness SLO: ≥ 99.99% events conform to schema (DLQ < 0.01%)

Instrument the pipeline end-to-end:

  • Broker: partition throughput, ISR count (min.insync.replicas violations)
  • Consumers: consumer lag by group + partition
  • Processor: checkpoint duration, backpressure time, restart count
  • Sink: commit latency, small-file count (lakehouse), compaction backlog

Example: Prometheus alert on Kafka consumer lag (illustrative):

groups:
  - name: streaming-alerts
    rules:
      - alert: KafkaConsumerLagHigh
        expr: kafka_consumergroup_lag{group="clickstream-processor"} > 500000
        for: 10m
        labels:
          severity: page
        annotations:
          summary: "High consumer lag for clickstream-processor"
          description: "Lag > 500k messages for 10m. Risk of freshness SLO breach."

This is where teams win or lose credibility: not whether the pipeline is “real-time,” but whether it’s predictable and explainable when it isn’t.

The pragmatic build plan (and where GitPlumbers fits)

Here’s what actually works when you’re moving fast and don’t want to rebuild later:

  1. Stabilize ingestion: durable log, retention, partitioning, producer acks, DLQ.
  2. Make correctness cheap: schema registry + compatibility + producer CI checks.
  3. Design for replay: idempotent processing + deterministic keys + checkpointing.
  4. Deliver value early: land to lakehouse + a small set of trusted metrics.
  5. Operationalize: data SLOs + alerting + on-call runbooks + game days.

If your current streaming stack is a mix of legacy glue plus AI-assisted “looks right” code, don’t guess where the cracks are.

  • Run GitPlumbers Automated Insights (GitHub-integrated analysis) to quickly surface structural risks: unsafe retry loops, missing idempotency, schema drift hazards, insecure connectors, and observability gaps.
  • Or book a GitPlumbers code audit for a deeper read: we’ll map your event contracts, replay story, state management, and failure modes—and give you a remediation plan with ROI (what to fix now vs later).
  • If you need to execute fast without a risky hiring spree, we can assemble a fractional team for remediation (streaming + platform + data modeling specialists) matched to what the audit finds.

The honest truth: high-velocity streaming isn’t “set and forget.” But with replay, idempotency, and contracts, it becomes “boring and bankable.”

Related Resources

Key takeaways

  • High-velocity streaming systems fail in predictable ways: silent drops, duplicates, schema drift, and unbounded lag—design for replay, idempotency, and backpressure from day one.
  • Reliability isn’t a vibe: define **data SLOs** (freshness, completeness, correctness) and instrument lag, drop rate, and DLQ volume like you would error budgets.
  • Quality at speed requires **contracts** (schemas + compatibility), **quarantine paths** (DLQ), and **deterministic dedup** (event keys + watermarks).
  • A lakehouse sink (Iceberg/Delta/Hudi) with partitioning + compaction is the fastest route to analytics value without building a bespoke serving layer too early.
  • If your pipeline was stitched together from “helpful” AI suggestions, run GitPlumbers **Automated Insights** or book a **code audit** before it becomes investor diligence material.

Implementation checklist

  • Define data SLOs: freshness (P95), completeness (%), correctness (schema conformance).
  • Choose an ingestion contract: `event_id`, `event_time`, `producer`, `schema_version`, and a partition key you can defend.
  • Enable replay: durable log (Kafka/Kinesis), retention aligned to incident response (>= 7 days for most teams).
  • Implement idempotent processing: dedup keys + sink upserts/merge semantics.
  • Add a DLQ/quarantine path and alert on it (volume + top error types).
  • Enforce schema compatibility in CI/CD (backward/forward rules).
  • Instrument lag and throughput end-to-end; set paging thresholds tied to SLO breach risk.
  • Load-test peak velocity and failure modes (broker restart, consumer rebalance, sink slowdown).

Questions we hear from teams

Kafka vs Kinesis: which is better for high-velocity streaming?
Either can work. The deciding factors are operational model and ecosystem. Kafka often wins when you need rich consumer patterns, on-prem/hybrid flexibility, and mature tooling (Schema Registry, Connect, Flink). Kinesis can be great when you want a managed AWS-native path. In both cases, reliability comes from replay retention, idempotent processing, and observability—not the logo on the box.
Do I really need a schema registry if we use JSON?
Yes, if you care about quality and stability. JSON without enforced schemas is how you get silent breaking changes (“string” becomes “object”), dashboard drift, and incident archaeology. A registry + compatibility rules turns schema evolution into an intentional process.
What’s the minimum viable set of guarantees for a startup?
Replay (retention + offsets), idempotency (event IDs + dedup/upserts), and a DLQ/quarantine path. Add data SLOs and lag alerting before you scale usage of the metrics across the company.
How do we know if we should fix our pipeline or rebuild it?
Fix when the core model (events + contracts + sinks) is sound but implementation is brittle (missing idempotency, poor alerting, bad partitioning). Rebuild when you can’t define a stable event contract, you can’t replay, or you’re locked into a sink/processor that can’t meet SLOs without heroic effort. A code audit makes this decision explicit and defensible.

Ready to modernize your codebase?

Let GitPlumbers help you transform AI-generated chaos into clean, scalable applications.

Run Automated Insights on your streaming repo Book a streaming-focused code audit

Related resources