Consistency Models
Consistency Spectrum
Strong ←──────────────────────────→ Weak
│ │ │ │
Linearizable Sequential Causal Eventual1. Strong Consistency (Linearizable)
// All reads see most recent write
// Example: MongoDB with majority read/write concern
const session = client.startSession();
await db.collection('accounts').updateOne(
{ _id: 'account1' },
{ $set: { balance: 1000 } },
{ session, writeConcern: { w: 'majority' } }
);
// Immediately visible to all readers
const account = await db.collection('accounts').findOne(
{ _id: 'account1' },
{ session, readConcern: { level: 'majority' } }
);
// balance === 1000 (guaranteed)2. Sequential Consistency
// All operations appear in same order to all nodes
// But may not reflect real-time ordering
// Node A writes: x = 1, y = 2
// Node B writes: x = 3, y = 4
// All nodes see either:
// x=1, y=2, x=3, y=4 OR x=3, y=4, x=1, y=2
// But NOT: x=1, y=4 or x=3, y=23. Causal Consistency
// Causally related operations seen in order
// Concurrent operations may be seen differently
// User posts comment
await db.posts.insertOne({
id: 'post1',
content: 'Hello',
timestamp: Date.now()
});
// User edits comment (causally related)
await db.posts.updateOne(
{ id: 'post1' },
{ $set: { content: 'Hello World' } }
);
// All readers see: Hello → Hello World
// Never see: Hello World → Hello4. Eventual Consistency
// All replicas eventually converge
// Temporary inconsistencies allowed
// Cassandra with eventual consistency
await client.execute(
'INSERT INTO users (id, name) VALUES (?, ?)',
[userId, 'John'],
{ consistency: cassandra.types.consistencies.one }
);
// Immediately after, different nodes may return:
// Node 1: { id: userId, name: 'John' }
// Node 2: null (not yet replicated)
// Eventually: All nodes return { id: userId, name: 'John' }MongoDB Consistency Levels
Read Concerns
const readConcerns = {
local: {
description: 'Return latest data from node',
consistency: 'May read uncommitted data',
use: 'Fastest reads, eventual consistency'
},
available: {
description: 'Same as local for replica sets',
consistency: 'May read stale data',
use: 'Sharded clusters, fastest'
},
majority: {
description: 'Data acknowledged by majority',
consistency: 'Strong consistency',
use: 'Critical reads'
},
linearizable: {
description: 'Read reflects all writes before read',
consistency: 'Strongest consistency',
use: 'Single document reads only'
},
snapshot: {
description: 'Consistent snapshot across shards',
consistency: 'Point-in-time consistency',
use: 'Multi-document transactions'
}
};
// Example usage
const user = await db.collection('users').findOne(
{ _id: userId },
{ readConcern: { level: 'majority' } }
);Write Concerns
const writeConcerns = {
w1: {
value: { w: 1 },
description: 'Acknowledged by primary',
durability: 'Low',
speed: 'Fastest'
},
wMajority: {
value: { w: 'majority' },
description: 'Acknowledged by majority',
durability: 'High',
speed: 'Slower'
},
wAll: {
value: { w: 3 },
description: 'Acknowledged by all nodes',
durability: 'Highest',
speed: 'Slowest'
},
journal: {
value: { w: 1, j: true },
description: 'Written to journal',
durability: 'Survives restart',
speed: 'Moderate'
}
};
// Example
await db.collection('users').insertOne(
{ name: 'John' },
{ writeConcern: { w: 'majority', j: true, wtimeout: 5000 } }
);Cassandra Consistency Levels
const cassandraConsistency = {
ONE: {
reads: 'One replica responds',
writes: 'One replica acknowledges',
consistency: 'Weak',
availability: 'High'
},
QUORUM: {
reads: 'Majority responds',
writes: 'Majority acknowledges',
consistency: 'Strong (with QUORUM writes)',
availability: 'Medium'
},
ALL: {
reads: 'All replicas respond',
writes: 'All replicas acknowledge',
consistency: 'Strongest',
availability: 'Low'
},
LOCAL_QUORUM: {
reads: 'Quorum in local datacenter',
writes: 'Quorum in local datacenter',
consistency: 'Strong locally',
availability: 'High'
},
EACH_QUORUM: {
reads: 'N/A',
writes: 'Quorum in each datacenter',
consistency: 'Strong globally',
availability: 'Medium'
}
};
// Example
await client.execute(
'SELECT * FROM users WHERE id = ?',
[userId],
{ consistency: cassandra.types.consistencies.quorum }
);DynamoDB Consistency
// Eventually consistent read (default)
const command = new GetCommand({
TableName: 'Users',
Key: { userId: '123' }
});
// Strongly consistent read
const strongCommand = new GetCommand({
TableName: 'Users',
Key: { userId: '123' },
ConsistentRead: true
});
// Transactions (always strongly consistent)
const transactCommand = new TransactWriteCommand({
TransactItems: [
{
Put: {
TableName: 'Users',
Item: { userId: '123', name: 'John' }
}
}
]
});Redis Consistency
// Master-slave replication (eventual consistency)
const redis = new Redis({
sentinels: [
{ host: 'sentinel1', port: 26379 },
{ host: 'sentinel2', port: 26379 }
],
name: 'mymaster'
});
// Write to master
await redis.set('key', 'value');
// Read from slave (may be stale)
await redis.get('key');
// WAIT command for synchronous replication
await redis.set('key', 'value');
await redis.wait(2, 1000); // Wait for 2 replicas, timeout 1sTunable Consistency
// Adjust per operation based on requirements
class UserService {
// Critical operation - strong consistency
async updateBalance(userId, amount) {
return await db.collection('users').updateOne(
{ _id: userId },
{ $inc: { balance: amount } },
{
writeConcern: { w: 'majority', j: true },
readConcern: { level: 'majority' }
}
);
}
// Non-critical operation - eventual consistency
async updateLastLogin(userId) {
return await db.collection('users').updateOne(
{ _id: userId },
{ $set: { lastLogin: new Date() } },
{ writeConcern: { w: 1 } }
);
}
// Analytics query - eventual consistency OK
async getUserStats() {
return await db.collection('users').aggregate([
{ $group: { _id: null, total: { $sum: 1 } } }
], {
readConcern: { level: 'local' }
}).toArray();
}
}Consistency vs Availability Trade-off
const tradeoffs = {
strongConsistency: {
pros: ['Always see latest data', 'Easier to reason about'],
cons: ['Lower availability', 'Higher latency', 'May reject requests'],
use: 'Banking, inventory, critical data'
},
eventualConsistency: {
pros: ['High availability', 'Low latency', 'Always accepts requests'],
cons: ['Temporary inconsistencies', 'Complex conflict resolution'],
use: 'Social media, analytics, caching'
}
};Conflict Resolution
// Last-Write-Wins (LWW)
class LWWService {
async update(key, value) {
await db.collection('data').updateOne(
{ _id: key },
{
$set: {
value,
timestamp: Date.now()
}
},
{ upsert: true }
);
}
async resolve(key) {
// Latest timestamp wins
const doc = await db.collection('data')
.find({ _id: key })
.sort({ timestamp: -1 })
.limit(1)
.toArray();
return doc[0];
}
}
// Application-level merge
class MergeService {
async mergeUserPreferences(userId, newPrefs) {
const current = await db.collection('users').findOne({ _id: userId });
const merged = {
...current.preferences,
...newPrefs,
_mergedAt: Date.now()
};
await db.collection('users').updateOne(
{ _id: userId },
{ $set: { preferences: merged } }
);
}
}.NET Consistency Configuration
using MongoDB.Driver;
public class ConsistencyService
{
private readonly IMongoClient _client;
public async Task<User> GetUserStrong(string userId)
{
var db = _client.GetDatabase("myapp");
var collection = db.GetCollection<User>("users")
.WithReadConcern(ReadConcern.Majority)
.WithReadPreference(ReadPreference.Primary);
return await collection.Find(u => u.Id == userId).FirstOrDefaultAsync();
}
public async Task<User> GetUserEventual(string userId)
{
var db = _client.GetDatabase("myapp");
var collection = db.GetCollection<User>("users")
.WithReadConcern(ReadConcern.Local)
.WithReadPreference(ReadPreference.SecondaryPreferred);
return await collection.Find(u => u.Id == userId).FirstOrDefaultAsync();
}
public async Task UpdateUserStrong(string userId, User user)
{
var db = _client.GetDatabase("myapp");
var collection = db.GetCollection<User>("users");
await collection.ReplaceOneAsync(
u => u.Id == userId,
user,
new ReplaceOptions
{
WriteConcern = WriteConcern.WMajority
}
);
}
}Monitoring Consistency
// Check replication lag
const status = rs.status();
const primary = status.members.find(m => m.state === 1);
const secondaries = status.members.filter(m => m.state === 2);
secondaries.forEach(secondary => {
const lag = primary.optimeDate - secondary.optimeDate;
console.log(`${secondary.name} lag: ${lag}ms`);
if (lag > 1000) {
console.warn('High replication lag detected');
}
});Interview Tips
- Explain spectrum: Strong to eventual consistency
- Show MongoDB: Read/write concerns
- Demonstrate Cassandra: Tunable consistency levels
- Discuss trade-offs: Consistency vs availability
- Mention CAP: Consistency, availability, partition tolerance
- Show examples: When to use each level
Summary
Consistency models range from strong (linearizable) to weak (eventual). MongoDB offers tunable read/write concerns: local, majority, linearizable. Cassandra provides ONE, QUORUM, ALL consistency levels. DynamoDB supports eventual and strong consistent reads. Choose based on requirements: strong for critical data, eventual for high availability. Trade-off between consistency and availability. Monitor replication lag. Implement conflict resolution for eventual consistency. Essential for distributed NoSQL systems.
Test Your Knowledge
Take a quick quiz to test your understanding of this topic.