How to Handle Distributed Data Consistency?
Asked by Ratul Sikder · · 9 answers · Solved
Handling distributed data consistency involves ensuring accurate, reliable synchronization across microservices with independent databases, despite network delays, failures, or eventual consistency challenges.
9 answers
Accepted answer · Answered by Mynul Islam ·
Outbox Pattern (Transactional Messaging)
Ensure that events are only published if local transaction succeeds.
✅ Process:
- Store event in
outboxtable in the same DB transaction - A separate worker reads and emits the event
await db.transaction(async (tx) => {
await tx.insert('orders', order);
await tx.insert('outbox', orderCreatedEvent);
});
Outbox worker then emits these to Kafka/NATS.
Answered by Sahin Khan ·
Eventual Consistency via Event-Driven Architecture
Instead of tight synchronization, services publish events and react to them asynchronously.
Example (Order + Inventory):
[Order Service]
Order Created ➜ emits ➜ OrderCreatedEvent
⬇
[Inventory Service]
Reserve Inventory
Code (Kafka + Node.js):
// Order Service
eventBus.publish('OrderCreated', { orderId, items });
// Inventory Service
eventBus.subscribe('OrderCreated', async ({ items }) => {
reserveStock(items);
});
🧠 Pros: Decoupled, scalable
❌ Cons: Hard to debug, eventual delays
Answered by Ratul Sikder ·
Read Models via CQRS (Command Query Responsibility Segregation)
Separate write models (DB) from read models (cached/denormalized views).
Order Service ➜ emits ➜ events ➜ Projected to:
- OrderReadDB
- AdminDashboardDB
Fast, flexible reads while maintaining strict write consistency.
Answered by Dipa Saha ·
The Saga Pattern (Choreography & Orchestration)
Handle long-running transactions by breaking them into local transactions with compensating steps.
🔁 Two Types:
Type How It Works Choreography Services listen and react to events Orchestration One service (saga orchestrator) tells others what to do 📘 Choreography Example:
[Order Service] → emits → OrderCreated
⬇ ⬇
[Inventory Service] [Payment Service]
emits InventoryReserved emits PaymentProcessed
⬇
[Shipping Service]
Code (Choreography in Node.js):
// Inventory Service
on('OrderCreated', reserveInventory);
// Payment Service
on('InventoryReserved', processPayment);
🧑✈️ Orchestration Example:
// Orchestrator
await call(orderService.createOrder)
await call(inventoryService.reserveStock)
await call(paymentService.chargeCard)
await call(shippingService.shipOrder)
🧠 Use choreography for simpler systems, orchestration for more control and rollback.
Answered by Shaykot Hossain Selim ·
Distributed Locking (when needed)
If operations must not overlap, use distributed locks with Redis, etcd, or ZooKeeper.
// Using Redlock (Redis)
const lock = await redlock.acquire(['locks:order:123'], 2000);
try {
await processOrder();
} finally {
await lock.release();
}
Use rarely. Overused locks reduce scalability.
Answered by Md Sharifuzzaman Shajib ·
Idempotency and Message Deduplication
Network retries and message duplication can cause duplicate operations.
Solution:
- Use idempotency keys or deduplication IDs
// Before updating DB
if (await hasProcessed(event.id)) return;
process(event);
markAsProcessed(event.id);
Use with:
- Kafka message keys
- Outbox patterns
- Redis set for seen IDs
Answered by Ratul Sikder ·
HiAnswered by Fozle Rabbi ·
Use Versioning for Conflict Resolution (Optimistic Locking)
Let services resolve update conflicts using version numbers.
// User has version 3
UPDATE users SET name='New Name', version=4 WHERE id=1 AND version=3;
❌ Fails if version mismatch, preventing overwrites.
Answered by John Errik ·
Helpful