System Design
Eventual Consistency
Eventual Consistency — distributed systemda ma’lumot darhol emas, balki vaqt o’tishi bilan bir xil bo’ladi.
Strong vs Eventual Consistency
Strong Consistency
Write → Node 1
Wait for all nodes sync
Return success
→ All reads see new value immediately
Latency: Yuqori (sync kutish)
Availability: Past (node down = write fail)
Eventual Consistency
Write → Node 1
Return success (immediately)
Background sync → Node 2, Node 3
→ Eventually all nodes have new value
Latency: Past (no wait)
Availability: Yuqori (single node yetarli)
Real-world Misol
DNS
1. Domain yangilanadi: example.com → 1.2.3.4
2. Immediately qaytadi
3. DNS servers dunyo bo'ylab 24-48 soat ichida yangilanadi
Eventual consistency: 48 soat.
Social Media
Ali posts → "Hello world"
Time 0s: Post saved
Time 0.5s: Vali refresh → post yo'q
Time 2s: Vali refresh → post ko'rinadi
Eventual consistency: 2 sekund.
Conflict Resolution
Muammo: Ikki node bir vaqtda o’zgartiradi.
Node 1: profile.bio = "Backend dev"
Node 2: profile.bio = "Frontend dev"
(same time, concurrent writes)
Conflict!
1. Last Write Wins (LWW)
// Timestamp-based
{
value: "Backend dev",
timestamp: 1704067200000
}
{
value: "Frontend dev",
timestamp: 1704067201000 // 1s later
}
// Winner: "Frontend dev"
Oddiy
Data loss (birinchi write yo’qoladi)
2. Version Vectors
// Har bir node o'z versionini track qiladi
Node1: { v1: 1, v2: 0 } → "Backend dev"
Node2: { v1: 0, v2: 1 } → "Frontend dev"
// Merge qilishda ikkalasi ham ko'rinadi
Conflict detected → Manual resolution
3. CRDTs (Conflict-free Replicated Data Types)
// Mathematical merge
const set1 = new Set(['redis', 'postgres']);
const set2 = new Set(['postgres', 'mongo']);
// Union (automatic merge)
const merged = union(set1, set2);
// → ['redis', 'postgres', 'mongo']
Automatic merge
Limited data types
4. Application-level Resolution
// Store both versions, user chooses
{
conflicts: [
{ value: "Backend dev", source: "node1" },
{ value: "Frontend dev", source: "node2" }
]
}
// UI: "Which one to keep?"
Quorum Consensus
Distributed systemda ko’pchilik (majority) yetarli:
N = 3 nodes
W = 2 (write quorum)
R = 2 (read quorum)
W + R > N → Strong consistency
W + R ≤ N → Eventual consistency
Example: Cassandra
-- Strong consistency
CONSISTENCY QUORUM; -- 2/3 nodes
-- Eventual consistency
CONSISTENCY ONE; -- 1/3 nodes
Read Repair
Eventual consistency’ni tezlashtirish:
Read request → Node 1, Node 2, Node 3
Node 1: value = 100 (latest)
Node 2: value = 50 (stale)
Node 3: value = 50 (stale)
Return 100 to client
Background: Update Node 2 & 3 → 100
Anti-entropy
Background process ma’lumotlarni sync qiladi:
Every 10 minutes:
- Compare hashes
- Identify differences
- Sync stale data
Merkle Trees:
Root hash represents entire dataset
Compare roots → fast check
Different? → Drill down to find differences
Vector Clocks
// Track causality
{
value: "Hello",
vectorClock: {
node1: 5,
node2: 3,
node3: 2
}
}
// Next write on node1:
{
value: "Hello world",
vectorClock: {
node1: 6, // Incremented
node2: 3,
node3: 2
}
}
Detect:
- Concurrent writes (conflict)
- Causal order (A happened before B)
Practical Examples
DynamoDB
// Eventual consistency (default)
const item = await dynamodb.get({
TableName: 'Users',
Key: { id: 123 },
ConsistentRead: false // May be stale
});
// Strong consistency
const item = await dynamodb.get({
TableName: 'Users',
Key: { id: 123 },
ConsistentRead: true // Always fresh
});
Cassandra
-- Eventual
SELECT * FROM users WHERE id = 123;
-- CONSISTENCY ONE (default)
-- Strong
CONSISTENCY QUORUM;
SELECT * FROM users WHERE id = 123;
MongoDB
// Eventual (read from secondary)
db.users.find({ id: 123 }).readPref('secondary');
// Strong (read from primary)
db.users.find({ id: 123 }).readPref('primary');
Best Practices
1. Tolerate staleness
// Good: Social feed (stale OK)
const posts = await cache.get('feed');
// Bad: Bank balance (stale = problem)
const balance = await cache.get('balance'); // NO!
2. Idempotent operations
// Idempotent (safe to retry)
UPDATE users SET status = 'active' WHERE id = 123;
// Not idempotent
UPDATE users SET balance = balance + 100 WHERE id = 123;
// Retry = double credit!
3. Conflict-free design
// Conflict-prone
profile.bio = "Backend dev"
profile.bio = "Frontend dev"
// Append-only (no conflict)
skills.add("Backend")
skills.add("Frontend")
4. Monitor lag
const lag = Date.now() - lastSyncTime;
if (lag > 5000) {
console.warn('Replication lag > 5s');
}
Trade-offs
| Strong Consistency | Eventual Consistency | |
|---|---|---|
| Latency | High | Low |
| Availability | Lower | Higher |
| Complexity | Lower | Higher |
| Use case | Banking, inventory | Social, analytics |
Xulosa
Eventual Consistency:
- Writes immediately return
- Reads may be stale
- Eventually all nodes sync
Conflict Resolution:
- LWW (last write wins) - simple
- Version vectors - track causality
- CRDTs - automatic merge
- Application-level - user chooses
When to use:
- Social media
- Analytics
- Caching
- Banking
- Inventory
Keyingi dars: Message Queues asoslari.