阿里云主机折上折
  • 微信号
Current Site:Index > Write Concern and Read Preference

Write Concern and Read Preference

Author:Chuan Chen 阅读数:14778人阅读 分类: MongoDB

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

  1. 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
  2. j Option:

    • true: Wait for the write operation to be persisted to the journal
    • false: Do not wait for journal persistence (default)
  3. 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

  1. primary (default): Read only from the primary node
  2. primaryPreferred: Read from the primary node if available, otherwise from secondary nodes
  3. secondary: Read only from secondary nodes
  4. secondaryPreferred: Read from secondary nodes if available, otherwise from the primary node
  5. 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:

  1. Stricter Write Concern increases write latency but enhances data safety.
  2. 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

  1. Critical data: Use w: "majority" and j: true.
  2. Non-critical data: Reduce Write Concern requirements to improve throughput.
  3. Read scaling: Route analytical queries to secondary nodes.
  4. Geographic distribution: Use tag sets to optimize regional reads.

Troubleshooting

Common issues and solutions:

  1. Write timeouts:

    // Increase wtimeout or check replica set health
    await collection.insertOne(doc, {
      writeConcern: { w: 3, wtimeout: 10000 }
    });
    
  2. Reading stale data:

    // Use primary node for critical data reads
    const criticalData = await collection.findOne(
      { _id: 'important' },
      { readPreference: 'primary' }
    );
    
  3. Driver compatibility:

    // Check if the driver version supports required features
    console.log(require('mongodb').version);
    

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.