导读:本期聚焦于小伙伴创作的《MongoDB 主从读写分离:基于副本集的高并发读写方案实现与代码示例》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《MongoDB 主从读写分离:基于副本集的高并发读写方案实现与代码示例》有用,将其分享出去将是对创作者最好的鼓励。

MongoDB 主从读写分离实现示例

在高并发业务场景中,数据库读写压力往往不均衡,读操作占比通常远高于写操作。通过 MongoDB 主从读写分离架构,可以将写请求路由到主节点,读请求分发到从节点,有效提升数据库整体吞吐量,降低单节点负载。本文将介绍基于 MongoDB 副本集实现读写分离的核心原理与代码示例。

一、核心原理说明

MongoDB 副本集(Replica Set)由多个节点组成,包含 1 个主节点(Primary)和多个从节点(Secondary)。主节点负责处理所有写操作,从节点通过复制主节点的 oplog 同步数据,默认从节点不处理读请求,需要显式配置读偏好(Read Preference)才能将读请求路由到从节点。

常用的读偏好模式包括:

  • primary:默认模式,所有读请求都发送到主节点,数据一致性最高

  • primaryPreferred:优先主节点读取,主节点不可用时才从从节点读取

  • secondary:所有读请求都发送到从节点,主节点不处理读请求

  • :优先从节点读取,从节点不可用时才从主节点读取

  • nearest:从网络延迟最低的节点(主从都可能)读取

实现读写分离的核心就是为不同的操作指定合适的读偏好,写操作默认走主节点,读操作根据需求选择从节点相关的读偏好模式。

二、环境准备

假设已经搭建好一个包含 3 个节点的 MongoDB 副本集,节点信息如下:

节点角色连接地址
主节点(Primary)mongodb://192.168.1.10:27017
从节点1(Secondary)mongodb://192.168.1.11:27017
从节点2(Secondary)mongodb://192.168.1.12:27017

副本集名称为 rs0,测试数据库为 test_db,测试集合为 user

三、Node.js 实现读写分离示例

以下示例使用 MongoDB 官方 Node.js 驱动 mongodb 实现读写分离,需要确保已经安装依赖:npm install mongodb

3.1 基础连接与配置

首先建立副本集连接,指定副本集名称,后续操作根据类型设置不同的读偏好。

const { MongoClient } = require('mongodb');

// 副本集连接字符串,包含所有节点地址和副本集名称
const uri = 'mongodb://192.168.1.10:27017,192.168.1.11:27017,192.168.1.12:27017/test_db?replicaSet=rs0';
const client = new MongoClient(uri);

async function main() {
  try {
    // 建立数据库连接
    await client.connect();
    console.log('MongoDB 副本集连接成功');
    const db = client.db('test_db');
    const userCollection = db.collection('user');

    // 后续读写操作在此处编写
  } catch (err) {
    console.error('操作异常:', err);
  } finally {
    // 实际业务中可根据需求决定是否关闭连接,长连接场景可保持连接不关闭
    // await client.close();
  }
}

main();

3.2 写操作实现

写操作默认会路由到主节点,无需额外配置读偏好,直接执行插入、更新、删除等操作即可。

async function writeData(collection) {
  try {
    // 插入单条数据,写操作自动路由到主节点
    const insertResult = await collection.insertOne name: '张三',
      age: 25,
      createTime: new Date()
    });
    console.log('写操作成功,插入数据ID:', insertResult.insertedId);

    // 更新数据
    const updateResult = await collection.updateOne(
      { name: '张三' },
      { $set: { age: 26 } }
    );
    console.log('更新操作影响条数:', updateResult.modifiedCount);
  } catch (err) {
    console.error('写操作异常:', err);
  }
}

3.3 读操作实现(路由到从节点)

读操作需要显式指定读偏好为 secondarysecondaryPreferred,实现读请求分发到从节点。

async function readDataFromSecondary(collection) {
  try {
    // 指定读偏好为 secondary,读请求路由到从节点
    const readResult = await collection.find(
      { name: '张三' },
      { readPreference: 'secondary' } // 设置读偏好
    ).toArray();
    console.log('从从节点读取到的数据:', readResult);
  } catch (err) {
    console.error('从从节点读操作异常:', err);
  }
}

async function readDataFromSecondaryPreferred(collection) {
  try {
    // 指定读偏好为 secondaryPreferred,优先从从节点读取,从节点不可用时走主节点
    const readResult = await collection.find(
      { age: { $gt: 20 } },
      { readPreference: 'secondaryPreferred' } // 设置读偏好
    ).toArray();
    console.log('优先从从节点读取到的数据:', readResult);
  } catch (err) {
    console.error('secondaryPreferred 读操作异常:', err);
  }
}

3.4 完整调用示例

const { MongoClient } = require('mongodb');

const uri = 'mongodb://192.168.1.10:27017,192.168.1.11:27017,192.168.1.12:27017/test_db?replicaSet=rs0';
const client = new MongoClient(uri);

async function main() {
  try {
    await client.connect();
    console.log('MongoDB 副本集连接成功');
    const db = client.db('test_db');
    const userCollection = db.collection('user');

    // 执行写操作(主节点)
    await writeData(userCollection);

    // 等待从节点同步数据,实际业务中可根据需求调整等待逻辑或使用写关注保证同步
    await new Promise(resolve => setTimeout(resolve, 1000));

    // 执行读操作(从节点)
    await readDataFromSecondary(userCollection);

    // 执行优先从从节点读取的操作
    await readDataFromSecondaryPreferred(userCollection);
  } catch (err) {
    console.error('操作异常:', err);
  } finally {
    await client.close();
  }
}

async function writeData(collection) {
  try {
    const insertResult = await collection.insertOne({
      name: '张三',
      age: 25,
      createTime: new Date()
    });
    console.log('写操作成功,插入数据ID:', insertResult.insertedId);
  } catch (err) {
    console.error('写操作异常:', err);
  }
}

async function readDataFromSecondary(collection) {
  try {
    const readResult = await collection.find(
      { name: '张三' },
      { readPreference: 'secondary' }
    ).toArray();
    console.log('从从节点读取到的数据:', readResult);
  } catch (err) {
    console.error('从从节点读操作异常:', err);
  }
}

async function readDataFromSecondaryPreferred(collection) {
  try {
    const readResult = await collection.find(
      { age: { $gt: 20 } },
      { readPreference: 'secondaryPreferred' }
    ).toArray();
    console.log('优先从从节点读取到的数据:', readResult);
  } catch (err) {
    console.error('secondaryPreferred 读操作异常:', err);
  }
}

main();

四、Python 实现读写分离示例

如果使用 Python 开发,可以使用 pymongo 驱动实现,先安装依赖:pip install pymongo

from pymongo import MongoClient, ReadPreference

# 副本集连接,指定副本集名称
client = MongoClient(
    'mongodb://192.168.1.10:27017,192.168.1.11:27017,192.168.1.12:27017/test_db?replicaSet=rs0'
)
db = client['test_db']
user_collection = db['user']

# 写操作,默认路由到主节点
insert_result = user_collection.insert_one({
    'name': '李四',
    'age': 30,
    'createTime': '2024-01-01'
})
print(f'写操作成功,插入数据ID: {insert_result.inserted_id}')

# 读操作,指定读偏好为从节点
read_result = user_collection.find(
    {'name': '李四'},
    read_preference=ReadPreference.SECONDARY
).to_list(length=None)
print(f'从从节点读取到的数据: {read_result}')

# 优先从从节点读取的读操作
read_result2 = user_collection.find(
    {'age': {'$gt': 20}},
    read_preference=ReadPreference.SECONDARY_PREFERRED
).to_list(length=None)
print(f'优先从从节点读取到的数据: {read_result2}')

client.close()

五、注意事项

1. 从节点数据存在同步延迟,如果业务需要强一致性读,不要使用从节点读偏好,应使用默认的 primary 模式。

2. 副本集节点故障时,MongoDB 会自动触发主节点选举,驱动会自动感知拓扑变化,无需手动调整连接配置。

3. 生产环境中建议根据实际情况选择合适的读偏好,比如对实时性要求不高的查询(如统计数据、历史记录查询)可以使用从节点读,核心交易类查询建议使用主节点读。

4. 连接字符串中可以配置更多参数,如连接超时时间、socket 超时时间等,可根据业务需求调整,参考官方文档 https://www.ipipp.com 查看完整的连接参数说明。

MongoDB 读写分离 副本集 主从复制 高并发

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。