Skip to content

Widhian Bramantya

coding is an art form

Menu
  • About Me
Menu
debezium

Production-Grade Debezium Connector with Kafka (Postgres Outbox Example – E-Commerce Orders)

Posted on September 27, 2025September 27, 2025 by admin

Introduction

Running Debezium in production is very different from running it locally. In production, the pipeline must be:

  • Reliable: no lost or duplicated events.
  • Ordered: events for the same entity must arrive in sequence.
  • Observable: operators must know if the system is alive.
  • Scalable: handle high throughput with multiple consumers.

This article shows how to build a production-grade Debezium + Kafka connector using the Outbox Pattern with PostgreSQL in an e-commerce order system.

The Outbox Pattern in E-Commerce

In an online shop:

  • A new order (ORD-20250927-123) is created in the orders table.
  • At the same time, the app inserts a record into the order_outbox table.

This guarantees:

  • If the order exists, the event also exists.
  • No “dual write” problem between DB and Kafka.
  • Debezium can safely capture outbox records and publish them to Kafka.

Production-Grade Connector Config

{
  "name": "ecommerce-order-outbox-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "ecom-prod-db.example.com",
    "database.port": "5432",
    "database.user": "cdc_user",
    "database.password": "******",
    "database.dbname": "ecommerce_production",
    "database.server.name": "ecommerce",
    "publication.name": "prd_order_outbox_cdc",
    "slot.name": "cdc_order_outbox",
    "plugin.name": "pgoutput",

    "table.include.list": "public.order_outbox(.*)", // assume table is partitioned
    "message.key.columns": "public.order_outbox(.*):order_id",

    "transforms": "Reroute, unwrap",
    "transforms.Reroute.type": "io.debezium.transforms.ByLogicalTableRouter",
    "transforms.Reroute.topic.regex": "(.*)order_outbox(.*)",
    "transforms.Reroute.topic.replacement": "ecommerce.public.order_outbox",
    "transforms.Reroute.key.enforce.uniqueness": false,
    "transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState",

    "key.converter": "org.apache.kafka.connect.json.JsonConverter",
    "key.converter.schemas.enable": false,
    "value.converter": "org.apache.kafka.connect.json.JsonConverter",
    "value.converter.schemas.enable": false,

    "tasks.max": "3",
    "topic.creation.enable": "true",
    "topic.creation.default.partitions": "12",
    "topic.creation.default.replication.factor": "3",
    "topic.creation.default.retention.ms": "604800000",

    "exactly.once.support": "required",
    "exactly.once.source.support": "enabled",

    "errors.log.enable": "true",
    "errors.log.include.messages": "true",
    "errors.deadletterqueue.topic.name": "dead-letter-queue",
    "errors.deadletterqueue.context.headers.enable": "true",

    "heartbeat.interval.ms": "10000",
    "heartbeat.topics.prefix": "heartbeat_order_outbox",
    "heartbeat.action.query": "INSERT INTO public.\"_heartbeat_apps\" (name, heartbeat)\nVALUES ('order_outbox', NOW())\nON CONFLICT (name)\nDO UPDATE SET heartbeat = NOW();"
  }
}

Key Features

Partitioning by Order ID

Ensures that all events for the same order_id go to the same partition: correct order for shipping, billing, and fraud detection.

See also  Delivery Semantics in Kafka: At Most Once, At Least Once, Exactly Once

Why Ordering Key Matters

  • The ordering key (partition key) decides event order in Kafka.
  • Wrong key → lost ordering → events like Shipped may arrive before Created.
  • This causes:
    • Out-of-order processing.
    • Broken business logic.
    • Race conditions.
    • Expensive recovery.
  • Solution: choose the key that matches the business entity needing strict sequence (e.g., order_id for order lifecycle, customer_id for customer-level workflows).

Topic Routing with Logical Table Router

Normalizes all order_outbox changes into one Kafka topic:

ecommerce.public.order_outbox

Clean Event Payload

ExtractNewRecordState transform unwraps the Debezium envelope: produces simple JSON.

Exactly-Once Semantics

Avoids duplicates and ensures at-least-once delivery is upgraded to exactly-once when combined with Kafka transactional producers.

Publisher (Debezium / Producer):

  • Uses idempotence → avoids duplicate sends.
  • Uses transactions → all events in batch are written atomically.
  • Commits WAL position + offsets inside the same transaction.

Consumer (Service):

  • Reads partition in order (one consumer per partition).
  • Commits offsets after successful processing.
  • Must be idempotent (e.g., UPSERT, unique keys, track processed events).

Dead Letter Queue

Failed records are pushed into dead-letter-queue for later inspection. Pipeline never blocks.

flowchart LR
  A[Debezium Connector] -->|Valid event| K[Kafka Topic]
  A -->|Error: bad record, schema, serialization| DLQ[Dead Letter Queue Topic]

  K --> C1[Consumer Service]
  DLQ --> OP[Ops Team / Monitoring]

Flow Explanation

  1. Debezium reads a DB change.
  2. If the event is valid: it is published to the normal Kafka topic.
  3. If the event fails (schema error, invalid payload, serialization issue): it is redirected to the DLQ topic.
  4. Consumers continue reading from the normal topic without interruption.
  5. Ops/Monitoring team inspects the DLQ, fixes root cause, and optionally reprocesses the events.
See also  Partitions, Replication, and Fault Tolerance in Kafka

Heartbeats for Monitoring

Debezium supports two types of heartbeat:

Database Heartbeat (configured in connector):

  • Inserts or updates a row in the DB (_heartbeat_apps table).Confirms Debezium is actively reading and writing.Useful for DBAs to check connector health from the database side.

    nameheartbeat
    order_outbox2025-09-27 13:45:00.123

    Kafka Heartbeat Topic (heartbeat_order_outbox):

    • Debezium publishes a heartbeat event into Kafka.Consumers can subscribe to this topic to check pipeline liveness.

    Example Kafka heartbeat event: { "status": "alive", "ts_ms": 1758967500123 }

    Consumer Metrics (additional best practice):

    • Consumer services (e.g., billing or shipping service) emit their own metrics:
      • Lag between event timestamp and processing time.
      • Last processed order_id.
    • Sent to Prometheus/Grafana for monitoring end-to-end latency.

    Related posts:

    Connecting Debezium with Kafka for Real-Time Streaming

    Debezium Architecture – How It Works and Core Components

    Getting Started with Apache Kafka: Core Concepts and Use Cases

    Pages: 1 2
    Category: Debezium, Kafka

    Leave a Reply Cancel reply

    Your email address will not be published. Required fields are marked *

    Linkedin

    Widhian Bramantya

    Recent Posts

    • Smart Automation in PostgreSQL: Managing Time-Based Data with pg_partman and pg_cron
    • Understanding PostgreSQL WAL, Slot, Publication, LSN, and Replication Lag
    • PostgreSQL Write-Ahead Log (WAL): Durability, Performance Tuning, and Recovery Explained
    • PostgreSQL Replication Deep Dive: From High Availability to Multi-Master Clusters
    • Finding Nearby Merchants in a Ride-Hailing App Using Elasticsearch Polygon Search
    • Advanced Text Search in Elasticsearch: N-Gram, Reverse, Fuzzy, and Search-as-you-type
    • Understanding and Customizing Analyzers in Elasticsearch
    • Log Management at Scale: Integrating Elasticsearch with Beats, Logstash, and Kibana
    • Index Lifecycle Management (ILM) in Elasticsearch: Automatic Data Control Made Simple
    • Blue-Green Deployment in Elasticsearch: Safe Reindexing and Zero-Downtime Upgrades
    • Maintaining Super Large Datasets in Elasticsearch
    • Elasticsearch Best Practices for Beginners
    • Implementing the Outbox Pattern with Debezium
    • Production-Grade Debezium Connector with Kafka (Postgres Outbox Example – E-Commerce Orders)
    • Connecting Debezium with Kafka for Real-Time Streaming
    • Debezium Architecture – How It Works and Core Components
    • What is Debezium? – An Introduction to Change Data Capture
    • Offset Management and Consumer Groups in Kafka
    • Partitions, Replication, and Fault Tolerance in Kafka
    • Delivery Semantics in Kafka: At Most Once, At Least Once, Exactly Once

    Recent Comments

    No comments to show.

    Archives

    • October 2025
    • September 2025
    • August 2025
    • November 2021
    • October 2021
    • August 2021
    • July 2021
    • June 2021
    • March 2021
    • January 2021

    Categories

    • Debezium
    • Devops
    • ElasticSearch
    • Golang
    • Kafka
    • Lua
    • NATS
    • PostgreSQL
    • Programming
    • RabbitMQ
    • Redis
    • VPC
    © 2026 Widhian Bramantya | Powered by Minimalist Blog WordPress Theme