Write Concern and Read Preference
In MongoDB, Write Concern and Read Preference are core mechanisms for controlling data consistency and availability. Write Concern defines the conditions that must be met for a write operation to be considered successful, while Read Preference determines how query requests are routed to members of a replica set. Understanding the configuration of these two mechanisms is crucial for optimizing application performance and ensuring data reliability.
Write Concern
Write Concern is used to specify the conditions that MongoDB must satisfy before acknowledging a write operation as successful. By adjusting the Write Concern level, you can balance between data durability and write performance.
Basic Syntax
In MongoDB drivers, Write Concern can be set as follows:
// Node.js example
const { MongoClient } = require('mongodb');
async function main() {
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('test');
const collection = db.collection('users');
// Set Write Concern to "majority"
await collection.insertOne(
{ name: 'Alice', age: 30 },
{ writeConcern: { w: 'majority', j: true } }
);
}
Common Configuration Options
-
w Value:
0
: No acknowledgment (fire-and-forget)1
: Wait for acknowledgment from the primary (default)majority
: Wait for acknowledgment from a majority of nodes<number>
: Wait for acknowledgment from a specified number of nodes
-
j Option:
true
: Wait for the write operation to be persisted to the journalfalse
: Do not wait for journal persistence (default)
-
wtimeout:
- Specifies a timeout period (in milliseconds) after which an error is returned instead of waiting indefinitely
Practical Use Cases
Financial transaction systems typically require the highest level of data security:
await collection.updateOne(
{ account: '12345' },
{ $inc: { balance: -100 } },
{
writeConcern: {
w: 'majority',
j: true,
wtimeout: 5000
}
}
);
Log collection systems may prioritize performance over immediate durability:
await logsCollection.insertOne(
{ message: 'User logged in', timestamp: new Date() },
{ writeConcern: { w: 0 } }
);
Read Preference
Read Preference determines how query requests are routed to members of a replica set, allowing you to choose between consistency and availability.
Five Primary Modes
- primary (default): Read only from the primary node
- primaryPreferred: Read from the primary node if available, otherwise from secondary nodes
- secondary: Read only from secondary nodes
- secondaryPreferred: Read from secondary nodes if available, otherwise from the primary node
- nearest: Read from the node with the lowest network latency
Code Examples
// Set Read Preference to secondaryPreferred
const collection = db.collection('products', {
readPreference: 'secondaryPreferred'
});
// Or specify via options
const cursor = collection.find({ category: 'electronics' })
.readPreference('secondary');
Advanced Configuration
You can combine tag sets for more granular control:
const readPref = new ReadPreference(
'secondary',
[
{ region: 'east', disk: 'ssd' },
{ region: 'west' }
]
);
const cursor = collection.find({}).readPreference(readPref);
Use Case Analysis
Reporting and analytics are suitable for secondary nodes:
// Large data queries use secondary nodes
const reportData = await analyticsCollection.find({})
.readPreference('secondary')
.toArray();
Globally distributed applications may choose the nearest mode:
// Provide low-latency reads for global users
const userProfile = await usersCollection.findOne(
{ _id: userId },
{ readPreference: 'nearest' }
);
Considerations When Combining Both
When combining Write Concern and Read Preference, special attention is needed to avoid potential read-write inconsistencies:
// Potential inconsistency scenario
await collection.insertOne(
{ _id: '123', status: 'active' },
{ writeConcern: { w: 1 } }
);
// Immediate reads may not see the newly written data
const doc = await collection.findOne(
{ _id: '123' },
{ readPreference: 'secondary' }
);
Solution: Use the "read-after-write" pattern:
// Ensure subsequent reads can see the write
await collection.insertOne(
{ _id: '123', status: 'active' },
{ writeConcern: { w: 'majority' } }
);
// Read from the primary node
const doc = await collection.findOne(
{ _id: '123' },
{ readPreference: 'primary' }
);
Performance Impact and Monitoring
The choice of Write Concern and Read Preference significantly affects system performance:
- Stricter Write Concern increases write latency but enhances data safety.
- Reading from secondary nodes can distribute load but may result in stale data.
Monitor relevant metrics:
// Get Write Concern statistics
const serverStatus = await db.admin().serverStatus();
console.log(serverStatus.writeConcern);
// Check replica set status
const replStatus = await db.admin().replSetGetStatus();
Special Considerations in Transactions
In MongoDB transactions, Read Preference and Write Concern have special restrictions:
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
// Operations within a transaction automatically use the primary node
await collection.updateOne(
{ _id: 'doc1' },
{ $inc: { value: 10 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
session.endSession();
}
Driver Version Differences
Different MongoDB drivers may have subtle implementation differences:
// Python example
from pymongo import MongoClient, ReadPreference
client = MongoClient(replicaSet='myReplicaSet')
db = client.get_database(
'test',
read_preference=ReadPreference.SECONDARY_PREFERRED
)
Best Practice Recommendations
- Critical data: Use
w: "majority"
andj: true
. - Non-critical data: Reduce Write Concern requirements to improve throughput.
- Read scaling: Route analytical queries to secondary nodes.
- Geographic distribution: Use tag sets to optimize regional reads.
Troubleshooting
Common issues and solutions:
-
Write timeouts:
// Increase wtimeout or check replica set health await collection.insertOne(doc, { writeConcern: { w: 3, wtimeout: 10000 } });
-
Reading stale data:
// Use primary node for critical data reads const criticalData = await collection.findOne( { _id: 'important' }, { readPreference: 'primary' } );
-
Driver compatibility:
// Check if the driver version supports required features console.log(require('mongodb').version);
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn