Skip to content

Ingestion Pattern Comparison and Decision Framework

Ingestion Pattern Comparison and Decision Framework

Section titled “Ingestion Pattern Comparison and Decision Framework”

This document provides a structured comparison of event ingestion architectures evaluated for bxb’s usage-based billing platform. It includes a multi-dimensional comparison matrix, total cost of ownership (TCO) analysis at multiple throughput tiers, and a decision framework for guiding future architectural choices.


IDPatternData Flow
P1API → PostgreSQLAPI → PostgreSQL
P2API → PostgreSQL + ETL → ClickHouseAPI → PostgreSQL → CDC/ETL → ClickHouse
P3API → Kafka → ClickHouse (chosen)API → Kafka → Batch Consumer → ClickHouse
P4API → ClickHouse directAPI → ClickHouse (HTTP/native)
P5API → Kafka → Flink → ClickHouseAPI → Kafka → Flink → ClickHouse

DimensionP1: PostgreSQLP2: PG + ETL → CHP3: Kafka → CH (chosen)P4: CH DirectP5: Kafka → Flink → CH
Throughput capacity5-10k/sec5-10k/sec (PG-limited)50-100k/sec100-500k/sec100k-1M+/sec
Ingestion-to-query latency<10ms1-30s (CDC lag)5-30s (batch window)<1s (async insert)10-100ms
Infrastructure cost (10k/sec)LowMediumMediumLowHigh
Development complexityLowMediumMediumLow-MediumHigh
Operational complexityLowMediumMediumMediumVery High
Horizontal scalabilityHardHard (PG side)EasyMediumEasy
Data durabilityExcellentExcellentVery GoodGoodVery Good
Event replay capabilityPoorPoorExcellentNoneExcellent
Multi-consumer supportPoorPoorExcellentPoorExcellent
Analytical query speedPoorGood (CH side)GoodGoodGood
DimensionWeightP1P2P3P4P5
Throughput capacity20%22455
Latency10%53455
Cost (10k/sec)20%53351
Development complexity15%53341
Operational complexity15%53331
Scalability10%12535
Durability5%55434
Replay capability5%11515
Weighted Score100%3.602.703.603.852.60
Weighted Score (50k/sec)1.802.103.803.353.60

At 10k/sec, P4 (ClickHouse direct) and P3 (Kafka → ClickHouse) tie on weighted score. P3 is chosen because bxb requires event replay capability and multi-consumer support, which P4 cannot provide.

At 50k/sec, P3 and P5 lead as PostgreSQL-based patterns hit their write ceiling.


PatternSustainable ThroughputBottleneckScaling Path
P15-10k/secPostgreSQL single-node write limit; index maintenance overheadRead replicas for reads only; Citus for writes (complex)
P25-10k/sec (PG-limited)PostgreSQL write path; CDC adds no write throughputSame as P1; ClickHouse side scales easily
P350-100k/secKafka partition count × consumer parallelismAdd partitions + consumers; Kafka scales linearly
P4100-500k/secClickHouse merge rate; batch size managementDistributed tables + sharding (requires re-sharding)
P5100k-1M+/secFlink parallelism × TaskManager resourcesAdd TaskManagers; Flink auto-scales on Kubernetes
PatternBest CaseTypicalWorst CaseNotes
P1<5ms<10ms50-100ms (under load)Immediate after INSERT commit
P21s5-15s30-60sCDC replication lag; depends on tool (PeerDB: sub-second; Debezium: seconds)
P35s10-30s1-2 minBatch window (5s) + consumer processing; higher under spike
P4<100ms<1s5-10sAsync insert flush window; immediate if sync
P510ms50-100ms1-5sFlink processing + checkpoint overhead
PatternComponentsEstimated Monthly Cost
P1PostgreSQL (1 primary + 1 replica)~$400-600
P2PostgreSQL + CDC tool + ClickHouse~$800-1,200
P3Kafka (3 brokers) + Consumer + ClickHouse~$900-1,300
P4ClickHouse (1 node, async inserts)~$300-500
P5Kafka + Flink cluster + ClickHouse~$1,500-2,300
PatternLanguages/SkillsNew ComponentsSchema ManagementDebugging
P1Python + SQLNone (existing stack)Alembic migrations onlySimple — single DB
P2Python + SQL + CDC configCDC tool (PeerDB/Debezium)Alembic + ClickHouse DDL syncModerate — trace through CDC
P3Python + Kafka clientKafka, consumer processAlembic + Kafka schema + CH DDLModerate — trace through broker
P4Python + ClickHouse clientApplication-level batcherClickHouse DDL onlySimple — direct write path
P5Python + Java/Scala (Flink)Kafka + Flink clusterAlembic + Kafka + Flink + CH DDLHard — distributed stateful system
PatternMonitoring PointsFailure ModesUpgrade DifficultyOn-Call Burden
P1PostgreSQL metricsPG down, replication lagLow (single component)Low
P2PG + CDC + CH metricsCDC lag, schema drift, PG bottleneckMedium (coordinate CDC)Medium
P3Kafka + consumer + CHConsumer lag, broker failure, partition skewMedium (rolling Kafka upgrades)Medium
P4ClickHouse metricsCH overload, too-many-parts, data loss (no buffer)Low (single component)Medium (backpressure handling)
P5Kafka + Flink + CHCheckpoint failures, state corruption, rebalancingHigh (Flink version upgrades)High
PatternWrite ScalingRead ScalingData Rebalancing
P1Very hard (Citus, app-level sharding)Easy (read replicas)Manual with Citus
P2Hard (PG side); Easy (CH side)Easy (CH replicas)Manual on PG, automatic-ish on CH
P3Easy (add Kafka partitions + consumers)Easy (CH replicas)Kafka rebalances automatically
P4Medium (ClickHouse sharding, Distributed tables)Easy (CH replicas)Manual re-sharding required
P5Easy (Flink parallelism + Kafka partitions)Easy (CH replicas)Flink rescales automatically
PatternWrite GuaranteeData Loss WindowRecovery Method
P1ACID (fsync per commit)None (synchronous commit)pg_basebackup + WAL replay
P2ACID (PG) + at-least-once (CDC)CDC lag window (seconds)PG backup + re-sync CDC
P3Kafka replication (acks=all)Consumer lag (seconds-minutes)Kafka replay from offset
P4At-least-once (async insert flush)Async insert buffer (1-2s); Buffer table (configurable)Re-ingest from source
P5Flink checkpoint + KafkaCheckpoint interval (seconds)Restore from checkpoint + replay

bxb’s target architecture must satisfy these requirements at 10,000 events/sec:

RequirementP1P2P3P4P5
Handle 10k events/sec sustainedMarginalMarginalYesYesYes
1-2 minute ingestion-to-query latency acceptableYesYesYesYesYes
Event replay capability (rebuild materialized views)NoNoYesNoYes
Headroom to scale to 50k/secNoNoYesYesYes
Cost-effective for bulk write-through (no transformations)YesModerateYesYesNo
ClickHouse-powered analytical queriesNoYesYesYesYes

Result: Only P3 and P5 satisfy all must-have requirements. P5 is eliminated on cost — Flink adds ~$500-1,000/month with no benefit for simple write-through ingestion.

RequirementP3 (chosen)Notes
Multi-consumer support for future processorsYesKafka consumer groups; add fraud detection, alerting, etc.
Decoupled API from storage layerYesKafka buffers events; ClickHouse downtime doesn’t affect API
At-least-once delivery with dedupYesKafka acks=all + ReplacingMergeTree
Operational simplicity for small teamModerateKafka requires learning but is well-documented
Standard tooling and ecosystemYesKafka Connect, schema registry, extensive monitoring

Why P3 (Kafka → ClickHouse) Over Alternatives

Section titled “Why P3 (Kafka → ClickHouse) Over Alternatives”
  1. Over P1 (PostgreSQL-only): PostgreSQL hits its write ceiling at 10k/sec, leaving no headroom for spikes. No event replay capability. Aggregation queries are 10-100x slower than ClickHouse.

  2. Over P2 (PostgreSQL + ETL): PostgreSQL remains the write bottleneck. CDC adds complexity without removing the fundamental limitation. Two databases to maintain with a fragile sync pipeline.

  3. Over P4 (ClickHouse direct): No event replay capability — once events are in ClickHouse, there is no “replay from offset.” API becomes tightly coupled to ClickHouse availability. Adding downstream consumers (fraud detection, alerting) requires restructuring the write path.

  4. Over P5 (Kafka → Flink → ClickHouse): Flink adds $500-1,000/month in infrastructure cost and significant operational complexity. bxb’s current use case is simple write-through ingestion — no transformations, no windowed aggregations, no stream-stream joins. Flink can be added later if real-time processing requirements emerge.


Total Cost of Ownership across three throughput tiers, including infrastructure, operations, and development costs.

ComponentP1P2P3 (chosen)P4P5
PostgreSQL (primary)$200$200
PostgreSQL (replica)$150$150
CDC tool (PeerDB/Debezium)$100
Kafka (3 brokers)$600$600
Kafka consumer process$50$50
Flink (JobManager + TaskManagers)$700
ClickHouse (1 node)$300$300$300$300
ClickHouse storage (1 TB/mo compressed)$50$50$50$50
Checkpoint/state storage (S3)$10
Total infrastructure$350$800$1,000$350$1,710
ComponentP1P2P3 (chosen)P4P5
PostgreSQL (primary, scaled)$800$800
PostgreSQL (2 replicas)$600$600
Citus/sharding overhead$500$500
CDC tool (scaled)$300
Kafka (5 brokers)$1,000$1,000
Kafka consumers (3 instances)$150$150
Flink cluster (scaled)$1,200
ClickHouse (2-node cluster)$600$600$600$600
ClickHouse storage (5 TB/mo)$250$250$250$250
Total infrastructure$1,900$3,050$2,000$850$3,200

Note: P1 at 50k/sec requires Citus or application-level sharding, adding significant development cost not reflected in infrastructure alone.

ComponentP1P2P3 (chosen)P4P5
PostgreSQL (sharded cluster)N/AN/A
Kafka (8 brokers)$1,600$1,600
Kafka consumers (6 instances)$300$300
Flink cluster (scaled)$2,000
ClickHouse (3-node cluster)$900$900$900
ClickHouse storage (10 TB/mo)$500$500$500
Total infrastructureN/AN/A$3,300$1,400$5,300

P1 and P2 are not viable at 100k/sec — PostgreSQL cannot sustain this write rate without extreme sharding complexity.

Estimated additional engineering time for operations and maintenance:

PatternFTE Overhead (10k/sec)FTE Overhead (50k/sec)FTE Overhead (100k/sec)
P10.1 FTE0.3 FTEN/A
P20.2 FTE0.5 FTEN/A
P30.2 FTE0.3 FTE0.5 FTE
P40.1 FTE0.2 FTE0.3 FTE
P50.5 FTE0.7 FTE1.0 FTE

TCO Summary (Infrastructure + Operations at $150k/FTE)

Section titled “TCO Summary (Infrastructure + Operations at $150k/FTE)”
ThroughputP1P2P3 (chosen)P4P5
10k/sec (annual)$22,200$39,600$41,700$19,200$111,120
50k/sec (annual)$67,800$126,600$61,500$40,200$143,400
100k/sec (annual)N/AN/A$129,600$73,800$213,600

Key insight: P3’s cost scales linearly and predictably. P4 is cheapest at every tier but lacks replay and decoupling. P5 is 2-3x more expensive than P3 with no throughput benefit for write-through ingestion.


Use this decision tree to guide architectural choices as bxb’s requirements evolve.

Is the event volume > 10k/sec?
├── NO (< 10k/sec):
│ │
│ ├── Need analytical queries on events?
│ │ ├── NO → P1: PostgreSQL-only (simplest, cheapest)
│ │ └── YES → Do you need ClickHouse-speed aggregations?
│ │ ├── NO → P1 with TimescaleDB (compression + continuous aggregates)
│ │ └── YES → P2: PostgreSQL + CDC → ClickHouse
│ │
│ └── Need event replay capability?
│ ├── NO → Stay with current pattern (above)
│ └── YES → P3: Kafka → ClickHouse (chosen architecture)
└── YES (> 10k/sec):
├── Is volume < 50k/sec?
│ │
│ └── Need real-time stream processing (< 1 sec latency)?
│ ├── NO → P3: Kafka → ClickHouse (add partitions + consumers)
│ └── YES → Is processing simple (filter, enrich)?
│ ├── YES → P3 + Kafka Streams (library in consumer)
│ └── NO → P5: Kafka → Flink → ClickHouse
└── Is volume > 50k/sec?
├── Is the write path simple (no transformations)?
│ ├── YES → P3: Kafka → ClickHouse (scale consumers)
│ └── NO → P5: Kafka → Flink → ClickHouse
└── Need pre-aggregation to reduce ClickHouse write load?
├── NO → P3 with more partitions
└── YES → P5: Flink for windowed pre-aggregation
TriggerCurrent StateAction
Sustained write rate > 8k/sec on PostgreSQLP1 or P2Begin migration to P3 (add Kafka)
Aggregation queries > 5 secondsP1Add ClickHouse (move to P2 or P3)
Need event replay or rebuild capabilityP1, P2, or P4Introduce Kafka (move to P3)
Need 3+ independent event consumersAny without KafkaMove to P3
Real-time processing < 1s requiredP3Add Kafka Streams (simple) or Flink (complex) → P5
Volume approaching 50k/secP3Scale Kafka partitions + consumers; evaluate pre-aggregation
ClickHouse write pressure at 100k+/secP3Add Flink pre-aggregation → P5
PostgreSQL no longer needed for transactional subsetP3Simplify: remove PG from write path, keep for metadata only

Chosen Architecture: P3 (API → Kafka → ClickHouse)

Section titled “Chosen Architecture: P3 (API → Kafka → ClickHouse)”

For bxb at 10k events/sec, P3 provides the best balance of:

  • Sufficient throughput with clear headroom to 50-100k/sec
  • Event replay capability for rebuilding materialized views and fixing processing bugs
  • Decoupled architecture where Kafka absorbs spikes and ClickHouse downtime doesn’t affect the API
  • Multi-consumer support for adding future processors (fraud detection, alerting, webhooks) without modifying the ingestion API
  • Reasonable cost (~$1,000/month infrastructure) that scales linearly
  • Moderate complexity manageable by a small Python-based team with Kafka’s well-documented ecosystem
CapabilityAvailable InWhy We Deferred
Sub-second analyticsP4 (direct CH), P5 (Flink)1-2 min latency is acceptable for billing
Real-time stream processingP5 (Flink)No current need; adds $700+/month and JVM ops burden
Simplest possible architectureP1 (PG-only)Doesn’t meet replay requirement; PG hits ceiling at 10k/sec
Cheapest infrastructureP4 (direct CH)No replay; API couples to CH availability
ACID per-event guaranteesP1, P2At-least-once + ReplacingMergeTree dedup is sufficient for billing
  1. Now (10k/sec): P3 — Kafka → simple batch consumer → ClickHouse
  2. Growth (20-50k/sec): P3 scaled — more Kafka partitions, more consumer instances, ClickHouse cluster
  3. Real-time needs: P3 + Kafka Streams — add lightweight stream processing in the consumer for enrichment or filtering
  4. Complex processing (50k+/sec): P5 — add Flink for windowed aggregation, multi-stream joins, or CEP
  5. Extreme scale (100k+/sec): P5 scaled — multi-cluster Kafka, Flink pre-aggregation, ClickHouse sharded cluster

  • [[Direct-Clickhouse-Ingestion]] — Detailed analysis of ClickHouse HTTP interface, Buffer tables, Distributed tables, and insert benchmarks
  • [[API-Direct-Write]] — PostgreSQL-only architecture, ETL/CDC patterns, TimescaleDB, read replica strategies
  • [[Streaming-Ingestion]] — Apache Flink, Kafka Streams, AWS Kinesis, Apache Pulsar analysis
  • [[Kafka-Event-Pipeline]] — bxb’s chosen Kafka → ClickHouse pipeline design