01. The Problem: Exactly-Once Delivery in Data Catalog Search
Building a scalable data catalog search engine that guarantees exactly-once delivery is a non-trivial challenge. Exactly-once delivery means every search result must be delivered to the user exactly once, with no duplicates or omissions. This requirement is critical for enterprise data governance, where users rely on accurate metadata to make decisions about data usage, lineage, and compliance.
The problem arises from the distributed nature of modern data catalogs. When search queries are processed across multiple nodes or services, ensuring consistency becomes difficult. For example, if a user searches for a dataset, the system must return the same results every time, regardless of how many times the query is executed. If duplicates or missing results occur, it can lead to operational inefficiencies, compliance violations, or even business-critical errors.
Traditional search engines like Elasticsearch or Solr handle high-scale queries, but they don’t natively support exactly-once delivery guarantees. These systems are optimized for low-latency, high-throughput search, but they lack the transactional semantics required for enterprise-grade data governance. For instance, if a metadata update is indexed but not yet visible to all nodes, a user might see stale or inconsistent results.
To achieve exactly-once delivery, the system must ensure that every search result is derived from a consistent, immutable snapshot of the data catalog. This requires careful coordination between indexing, querying, and result delivery. Without such guarantees, users may encounter duplicate results (e.g., the same dataset appearing multiple times in a search) or missing results (e.g., a newly indexed dataset not appearing in a query).
Additionally, the system must handle high concurrency. In large enterprises, thousands of users may query the catalog simultaneously, with some updates happening in real time. Ensuring that every query reflects the latest state without duplicates or omissions requires a robust synchronization mechanism. For example, if a dataset is updated while a search is in progress, the system must ensure the update is reflected in subsequent queries without causing inconsistencies.
The challenge is further compounded by the need for fault tolerance. If a node fails during a search operation, the system must recover without delivering duplicate or partial results. This requires mechanisms like checkpointing or idempotent operations, but these add complexity and latency. The tradeoff is clear: stronger guarantees increase system overhead, potentially degrading performance at scale.
In summary, the problem is not just about building a fast search engine, but about ensuring that every search result is accurate, consistent, and delivered exactly once—even in the face of high concurrency, failures, and real-time updates. The solution requires a combination of distributed systems techniques, careful synchronization, and a deep understanding of the tradeoffs between consistency, availability, and performance.
02. Architectural Solutions for Exactly-Once Delivery
Event sourcing with idempotent writes
We start by persisting every catalog mutation as an immutable event in a durable log such as Amazon Kinesis Data Streams. The stream assigns a monotonically increasing sequence number, which lets downstream components detect gaps and replay missing events. By making the write path idempotent—using a composite key of object ID and event type—duplicate submissions are filtered without sacrificing latency. This pattern works well when write volume is under 10 k events per second, but the overhead of deduplication can grow if the same object is updated hundreds of times per minute.
Exactly‑once processing with Flink or Spark Structured Streaming
We evaluated Apache Flink on Amazon EMR and Spark Structured Streaming on AWS Glue. Both frameworks support checkpoint‑based state management that guarantees each record is processed once when checkpoints are stored in Amazon S3 with versioning. Flink’s two‑phase commit sink integrates natively with Amazon OpenSearch Service, allowing atomic index updates. Spark’s micro‑batch model incurs a 5‑10 ms latency penalty per batch, which is acceptable for catalog queries but may be noticeable in interactive UI scenarios.
Transactional index updates
We selected Amazon OpenSearch Service because it offers a bulk API that can be wrapped in a transaction‑like workflow using the OpenSearch Write-Ahead Log. Each bulk request includes a client‑generated correlation ID; the service returns success only when all documents are persisted, otherwise the operation is rolled back. This approach eliminates partial index states but increases write cost by roughly 15 % due to the extra round‑trip.
Exactly‑once delivery via DynamoDB streams
DynamoDB Streams provide a change data capture mechanism that emits a record for every insert, update, or delete. By configuring the stream as a Lambda trigger with a reserved concurrency of 200, we guarantee that each change invokes a single processing function. The Lambda function records the stream’s sequence number in a DynamoDB “offset” table, ensuring that on a retry it can resume without re‑processing already‑handled items. The tradeoff is that Lambda cold starts add up to 200 ms latency for spikes beyond the reserved concurrency.
Consistency verification with checksum comparison
To validate that the search index mirrors the source catalog, we compute an MD5 checksum of the serialized record set every hour and store it in Amazon S3. A scheduled Step Functions state machine compares the new checksum with the prior value; a mismatch triggers an automated replay of the affected Kinesis shards. This adds a modest cost—approximately $0.02 per hour for S3 PUT operations—but catches rare drift that could otherwise break exactly‑once guarantees.
Observability and alerting
We instrument every component with Datadog custom metrics: “catalog.events.ingested”, “catalog.index.success”, and “catalog.replay.count”. Alerts fire when the replay count exceeds 0.5 % of total events in a 15‑minute window, indicating a systemic delivery issue. While Datadog licensing adds $15 per host per month, the early detection of delivery gaps outweighs the expense in a production catalog serving millions of queries.

03. Worked Example: Cost Implications of Exactly-Once Search
Consider a team of 50 engineers maintaining a $10M data catalog. Each engineer performs 100 search queries per day, totaling 50,000 queries/day. If 1% of these queries fail due to duplicate processing, the cost of reprocessing becomes significant. For example, if each failed query costs $0.05 to reprocess (including developer time and infrastructure overhead), the annual cost is $1.125M (50,000 × 0.01 × $0.05 × 365).
To mitigate this, we evaluated two approaches: (1) using AWS Step Functions for orchestration with DynamoDB for deduplication, and (2) leveraging Apache Kafka with idempotent producers. The first approach requires AWS Step Functions Standard Workflow pricing at $0.000025 per task execution. With 50,000 queries/day, this costs $11.25/month ($0.000025 × 50,000 × 30). DynamoDB On-Demand pricing adds $0.25 per 100,000 writes, totaling $1.50/month for 50,000 writes/day. The total monthly cost is $12.75, or $153 annually.
The Kafka-based solution uses a dedicated Kafka cluster on AWS MSK. A 3-broker cluster with 100 GB storage costs $1,200/month. Idempotent producers add no additional cost, but consumer-side deduplication requires a separate Redis cluster at $0.10/hour. For 50,000 queries/day, this costs $1,440/month. The total monthly cost is $2,640, or $31,680 annually.
The tradeoff is clear: AWS Step Functions is cheaper ($153 vs. $31,680) but has higher latency due to Lambda invocations. Kafka is more expensive but offers lower latency and better scalability. For teams with strict SLAs, Kafka may be justified; for cost-sensitive teams, Step Functions provides a balance.
| Solution | Monthly Cost | Annual Cost | Key Limitation |
|---|---|---|---|
| AWS Step Functions + DynamoDB | $12.75 | $153 | Higher latency due to Lambda |
| Apache Kafka + Redis | $2,640 | $31,680 | Requires dedicated infrastructure |
For the $10M catalog, the cost of failures ($1.125M) far exceeds the cost of either solution. The decision should prioritize reliability over cost unless the team can tolerate occasional duplicates. Monitoring tools like Datadog APM can further reduce costs by identifying bottlenecks before they escalate.
04. Decision Table: Trade-offs Between Consistency and Performance
Implementing exactly-once delivery in a data catalog search engine requires balancing consistency guarantees with operational constraints. The decision framework below compares three real-world strategies—each with distinct trade-offs—across five key criteria. I evaluated these options because they represent common patterns in distributed systems, and their outcomes directly impact search accuracy, cost, and operational complexity.
| Criteria | Option A: DynamoDB Streams + Lambda | Option B: Apache Kafka + Debezium | Option C: AWS Kinesis + Application-Level Deduplication |
|---|---|---|---|
| Latency | Low (milliseconds). DynamoDB Streams trigger Lambda functions with minimal delay, but Lambda cold starts can introduce variability. | Medium (seconds). Kafka’s end-to-end latency depends on batching and consumer processing time, but tuning can reduce it. | Medium (seconds). Kinesis has inherent latency due to shard processing, and application-level deduplication adds overhead. |
| Cost | High. DynamoDB Streams and Lambda pricing scale with request volume, and Lambda’s per-invocation costs add up at scale. | Low. Kafka (self-managed or MSK) and Debezium are open-source, and AWS MSK pricing is competitive for high-throughput workloads. | Medium. Kinesis pricing is predictable but expensive for large-scale data pipelines, and deduplication logic increases compute costs. |
| Reliability | High. DynamoDB Streams guarantee exactly-once processing for Lambda, but failures during Lambda execution may require manual intervention. | High. Kafka’s transactional API and Debezium’s CDC guarantees ensure end-to-end reliability, but misconfigured consumers can break this. | Medium. Kinesis provides at-least-once delivery, and application-level deduplication is error-prone if not implemented correctly. |
| Operational Complexity | Low. Managed services reduce operational overhead, but debugging Lambda timeouts or cold starts can be challenging. | High. Kafka and Debezium require expertise in distributed systems, and monitoring (e.g., Datadog or Confluent Control Center) is essential. | Medium. Kinesis is simpler than Kafka but lacks built-in CDC or exactly-once semantics, requiring custom logic. |
| Scalability | High. DynamoDB Streams and Lambda scale horizontally, but Lambda concurrency limits may require provisioned concurrency. | High. Kafka and Debezium are designed for high-throughput scenarios, but partitioning and consumer groups must be tuned. | Medium. Kinesis scales with shard provisioning, but deduplication logic becomes a bottleneck at extreme scale. |
| Recommendation | Best for teams prioritizing simplicity and low-latency processing. However, Lambda’s execution model may not suit long-running or stateful workloads. | Best for teams with expertise in Kafka and requiring end-to-end reliability. The operational overhead is justified for mission-critical pipelines. | Best for teams using Kinesis for other workloads and needing a lightweight deduplication layer. Avoid for high-reliability requirements. |
This framework highlights that no single solution is universally optimal. For example, DynamoDB Streams + Lambda is ideal for teams leveraging AWS’s managed services, while Kafka + Debezium is better suited for organizations with existing Kafka infrastructure. Kinesis is a middle ground but requires careful implementation to avoid deduplication gaps. The choice depends on team expertise, existing tooling, and workload characteristics.


05. Action Step: Implementing Exactly-Once Search in Your Catalog
Implementing exactly-once search in your data catalog requires careful planning and execution. Start by auditing your current architecture. Identify where your system loses or duplicates data—common culprits include asynchronous processing, retries, and distributed transactions. I evaluated Kafka for event streaming because it natively supports idempotent producers, but only if you configure it correctly. The default settings can still lead to duplicates if you don’t enable enable.idempotence=true and set acks=all.
Next, design your search pipeline with deduplication in mind. Use a combination of deterministic keys and sequence numbers. For example, assign a unique event_id to each record and store it in a database table alongside the search index. Before indexing, check if the event_id exists. This works well for batch processing but may introduce latency. I chose this approach over probabilistic methods like Bloom filters because it guarantees correctness without false positives.
For real-time systems, consider using AWS Kinesis or Apache Pulsar. Both support exactly-once processing with their own tradeoffs. Kinesis is simpler to integrate with AWS services, but Pulsar offers more flexibility for custom deployments. I recommend testing both in your staging environment before committing to one. Measure end-to-end latency and throughput to ensure they meet your SLAs.
Monitor your implementation rigorously. Use Datadog or Prometheus to track duplicate events. Set up alerts for any anomalies in your deduplication logic. I once saw a team ignore duplicate alerts for weeks, only to discover a silent failure in their retry logic. Proactive monitoring prevents this. Also, log every step of the pipeline—from ingestion to indexing—so you can trace any issues back to their source.
Finally, validate your solution with a controlled experiment. Inject known duplicates into your system and verify they’re filtered out. This is the only way to confirm your implementation works as intended. I recommend starting with a small subset of your data to avoid disrupting production.
Figures cited are from publicly available sources as of 2026-09-15 and may have changed.