MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MongoDB副本集创建流程详解

2024-04-191.7k 阅读

1. 环境准备

在开始创建 MongoDB 副本集之前,首先要确保拥有合适的运行环境。这包括安装 MongoDB 软件以及配置相关的系统参数。

1.1 安装 MongoDB

MongoDB 的安装过程会因操作系统的不同而有所差异。以下以常见的 Linux 系统(Ubuntu 为例)和 Windows 系统来说明。

Ubuntu 系统安装

  1. 导入 MongoDB 的 GPG 密钥,确保下载的软件包来源可靠。在终端中执行以下命令:
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
  1. 创建 MongoDB 的软件源列表文件。在 /etc/apt/sources.list.d/ 目录下创建 mongodb-org-6.0.list 文件,并添加以下内容:
deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse
  1. 更新软件包列表并安装 MongoDB:
sudo apt-get update
sudo apt-get install -y mongodb-org

Windows 系统安装

  1. 从 MongoDB 官方网站(https://www.mongodb.com/try/download/community)下载适合 Windows 系统的安装包。
  2. 运行安装包,在安装过程中可以选择自定义安装路径等选项。安装完成后,需要配置 MongoDB 的环境变量。将 MongoDB 的 bin 目录路径添加到系统的 PATH 环境变量中,例如 C:\Program Files\MongoDB\Server\6.0\bin

1.2 配置系统参数

为了确保 MongoDB 能够稳定运行并充分发挥性能,一些系统参数的配置是必要的。

Linux 系统

  1. 文件描述符限制:MongoDB 在运行过程中可能需要打开大量的文件,因此需要适当调整文件描述符的限制。可以通过编辑 /etc/security/limits.conf 文件,添加以下内容:
mongodb soft nofile 64000
mongodb hard nofile 64000

这里假设 MongoDB 运行的用户名为 mongodb,你可以根据实际情况修改。修改完成后,重新登录用户使配置生效。 2. 虚拟内存:MongoDB 依赖虚拟内存来管理数据,确保系统有足够的虚拟内存空间。可以通过 sysctl 命令来调整虚拟内存参数,例如:

sudo sysctl -w vm.max_map_count=262144

这将把 vm.max_map_count 设置为 262144,该值可以根据系统的实际情况进行调整。同时,为了使配置在系统重启后仍然生效,可以将上述命令添加到 /etc/sysctl.conf 文件中。

Windows 系统

  1. 内存设置:在 Windows 系统中,可以通过 MongoDB 的配置文件来调整内存使用。打开 MongoDB 安装目录下的 mongod.cfg 文件(如果没有,可以创建一个),添加或修改以下配置项:
storage:
  engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1

这里将 WiredTiger 引擎的缓存大小设置为 1GB,你可以根据服务器的内存情况进行调整。

2. 规划副本集架构

在创建 MongoDB 副本集之前,需要对副本集的架构进行合理规划,这包括确定节点的数量、角色以及它们的部署位置等。

2.1 节点数量与角色

MongoDB 副本集通常由多个节点组成,常见的节点角色有主节点(Primary)、从节点(Secondary)和仲裁节点(Arbiter)。

  • 主节点:负责处理所有的写操作以及大部分的读操作。在一个副本集中,同一时间只有一个主节点。
  • 从节点:从主节点复制数据,保持与主节点的数据同步。从节点可以分担读操作的负载,提高系统的读取性能。
  • 仲裁节点:仲裁节点不存储数据,它的主要作用是参与选举过程,帮助确定主节点。仲裁节点的存在可以保证在部分节点故障的情况下,仍然能够正常进行选举并维持副本集的可用性。

一般来说,为了保证副本集的高可用性和容错能力,建议副本集至少包含三个节点,其中可以是两个数据节点(一个主节点和一个从节点)和一个仲裁节点。对于生产环境,更推荐使用奇数个节点,例如三个或五个数据节点,这样可以在节点故障时更容易进行选举。

2.2 部署位置

节点的部署位置也非常重要,特别是在考虑高可用性和容灾能力时。如果可能的话,应该将节点分布在不同的物理服务器、机架甚至数据中心。这样可以避免因为单个物理位置的故障(如停电、网络故障等)导致整个副本集不可用。

例如,可以将一个副本集的三个节点分别部署在三个不同的机架上,每个机架有独立的电源和网络连接。这样即使其中一个机架出现故障,其他两个节点仍然可以继续工作,保证副本集的可用性。

3. 配置副本集节点

在完成环境准备和架构规划后,接下来需要对每个副本集节点进行配置。

3.1 创建数据目录和日志目录

每个 MongoDB 节点都需要有自己的数据目录和日志目录。以 Linux 系统为例,假设我们在 /var/lib/mongodb 目录下创建数据目录和日志目录。

  1. 创建数据目录:
sudo mkdir -p /var/lib/mongodb/data1
sudo mkdir -p /var/lib/mongodb/data2
sudo mkdir -p /var/lib/mongodb/data3

这里创建了三个数据目录,分别用于三个节点的数据存储。 2. 创建日志目录:

sudo mkdir -p /var/lib/mongodb/logs1
sudo mkdir -p /var/lib/mongodb/logs2
sudo mkdir -p /var/lib/mongodb/logs3

同样创建了三个日志目录,分别用于记录三个节点的日志信息。

3.2 配置 MongoDB 节点

每个 MongoDB 节点都需要通过配置文件进行配置。以下是一个典型的 MongoDB 节点配置文件示例(以节点 1 为例),保存为 /etc/mongod1.conf

systemLog:
  destination: file
  path: /var/lib/mongodb/logs1/mongod.log
  logAppend: true
storage:
  dbPath: /var/lib/mongodb/data1
  journal:
    enabled: true
processManagement:
  fork: true
net:
  bindIp: 192.168.1.101
  port: 27017
replication:
  oplogSizeMB: 1024
  replSetName: rs0

在这个配置文件中:

  • systemLog 部分配置了日志的输出方式,包括输出到文件、日志文件路径以及是否追加日志。
  • storage 部分指定了数据存储的路径以及是否启用日志。
  • processManagement 部分设置 MongoDB 以守护进程方式运行。
  • net 部分配置了绑定的 IP 地址和端口号。这里的 192.168.1.101 是节点 1 的实际 IP 地址,你需要根据实际情况进行修改。
  • replication 部分设置了 oplog 的大小(这里设置为 1024MB)以及副本集的名称 rs0。副本集名称在整个副本集中必须保持一致。

类似地,为节点 2 和节点 3 创建配置文件 /etc/mongod2.conf/etc/mongod3.conf,只需修改 bindIp 为对应节点的 IP 地址以及 dbPathpath 为相应的数据目录和日志目录路径。例如,节点 2 的配置文件 /etc/mongod2.conf 如下:

systemLog:
  destination: file
  path: /var/lib/mongodb/logs2/mongod.log
  logAppend: true
storage:
  dbPath: /var/lib/mongodb/data2
  journal:
    enabled: true
processManagement:
  fork: true
net:
  bindIp: 192.168.1.102
  port: 27017
replication:
  oplogSizeMB: 1024
  replSetName: rs0

节点 3 的配置文件 /etc/mongod3.conf 如下:

systemLog:
  destination: file
  path: /var/lib/mongodb/logs3/mongod.log
  logAppend: true
storage:
  dbPath: /var/lib/mongodb/data3
  journal:
    enabled: true
processManagement:
  fork: true
net:
  bindIp: 192.168.1.103
  port: 27017
replication:
  oplogSizeMB: 1024
  replSetName: rs0

4. 启动副本集节点

在完成节点配置后,接下来可以启动各个副本集节点。

4.1 启动 MongoDB 节点

在 Linux 系统中,可以使用以下命令启动 MongoDB 节点:

  1. 启动节点 1:
sudo mongod -f /etc/mongod1.conf
  1. 启动节点 2:
sudo mongod -f /etc/mongod2.conf
  1. 启动节点 3:
sudo mongod -f /etc/mongod3.conf

在 Windows 系统中,可以在命令提示符或 PowerShell 中使用以下命令启动 MongoDB 节点(假设配置文件位于 C:\mongodb\conf 目录下):

  1. 启动节点 1:
mongod --config C:\mongodb\conf\mongod1.conf
  1. 启动节点 2:
mongod --config C:\mongodb\conf\mongod2.conf
  1. 启动节点 3:
mongod --config C:\mongodb\conf\mongod3.conf

4.2 检查节点状态

启动节点后,可以通过 MongoDB 的日志文件或者使用 mongo 客户端连接到节点来检查节点的状态。

通过日志文件检查节点状态:可以查看每个节点的日志文件,例如对于节点 1,查看 /var/lib/mongodb/logs1/mongod.log 文件。如果节点启动成功,会看到类似以下的日志信息:

[initandlisten] waiting for connections on port 27017

这表明节点正在监听指定的端口,等待客户端连接。

使用 mongo 客户端检查节点状态:可以使用 mongo 客户端连接到每个节点,例如连接到节点 1:

mongo 192.168.1.101:27017

连接成功后,可以在 mongo 命令行中执行 db.serverStatus() 命令来查看节点的状态信息。如果节点状态正常,会看到一系列关于节点的信息,包括内存使用、连接数等。

5. 初始化副本集

在所有节点都成功启动并检查状态正常后,接下来需要初始化副本集。

5.1 连接到其中一个节点

首先,使用 mongo 客户端连接到副本集中的任意一个节点,例如连接到节点 1:

mongo 192.168.1.101:27017

5.2 初始化副本集配置

mongo 命令行中,执行以下命令来初始化副本集配置:

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "192.168.1.101:27017" },
    { _id: 1, host: "192.168.1.102:27017" },
    { _id: 2, host: "192.168.1.103:27017" }
  ]
})

在这个命令中:

  • _id 字段指定了副本集的名称,必须与每个节点配置文件中的 replSetName 一致。
  • members 数组列出了副本集中所有节点的 host 信息,格式为 IP 地址:端口号

执行上述命令后,如果初始化成功,会看到类似以下的输出:

{
  "ok" : 1,
  "operationTime" : Timestamp(1652345678, 1),
  "$clusterTime" : {
    "clusterTime" : Timestamp(1652345678, 1),
    "signature" : {
      "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
      "keyId" : NumberLong(0)
    }
  }
}

5.3 查看副本集状态

初始化副本集后,可以使用 rs.status() 命令来查看副本集的状态。在 mongo 命令行中执行该命令,会得到如下类似的输出:

{
  "set" : "rs0",
  "date" : ISODate("2023-05-10T12:34:56Z"),
  "myState" : 1,
  "members" : [
    {
      "_id" : 0,
      "name" : "192.168.1.101:27017",
      "health" : 1,
      "state" : 1,
      "stateStr" : "PRIMARY",
      "uptime" : 3600,
      "optime" : {
        "ts" : Timestamp(1652345678, 1),
        "t" : 1
      },
      "optimeDate" : ISODate("2023-05-10T12:34:56Z"),
      "syncSourceHost" : "",
      "syncSourceId" : -1,
      "infoMessage" : "",
      "electionTime" : Timestamp(1652345678, 1),
      "electionDate" : ISODate("2023-05-10T12:34:56Z"),
      "configVersion" : 1
    },
    {
      "_id" : 1,
      "name" : "192.168.1.102:27017",
      "health" : 1,
      "state" : 2,
      "stateStr" : "SECONDARY",
      "uptime" : 3598,
      "optime" : {
        "ts" : Timestamp(1652345678, 1),
        "t" : 1
      },
      "optimeDate" : ISODate("2023-05-10T12:34:56Z"),
      "syncSourceHost" : "192.168.1.101:27017",
      "syncSourceId" : 0,
      "infoMessage" : "",
      "configVersion" : 1
    },
    {
      "_id" : 2,
      "name" : "192.168.1.103:27017",
      "health" : 1,
      "state" : 7,
      "stateStr" : "ARBITER",
      "uptime" : 3596,
      "lastHeartbeat" : ISODate("2023-05-10T12:34:56Z"),
      "lastHeartbeatRecv" : ISODate("2023-05-10T12:34:56Z"),
      "pingMs" : NumberLong(0),
      "configVersion" : 1
    }
  ],
  "ok" : 1,
  "operationTime" : Timestamp(1652345678, 1),
  "$clusterTime" : {
    "clusterTime" : Timestamp(1652345678, 1),
    "signature" : {
      "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
      "keyId" : NumberLong(0)
    }
  }
}

在这个输出中,可以看到每个节点的状态信息,包括节点的 _id、名称、健康状态(health)、当前状态(stateStr)等。例如,在上述输出中,节点 1 是主节点(PRIMARY),节点 2 是从节点(SECONDARY),节点 3 是仲裁节点(ARBITER)。

6. 副本集的常用操作与管理

在副本集创建完成并正常运行后,还需要了解一些常用的操作与管理方法,以确保副本集的稳定运行和性能优化。

6.1 添加和删除节点

添加节点:如果需要向副本集中添加新的节点,首先要在新节点上安装和配置 MongoDB,确保其 replSetName 与现有副本集一致。然后,在主节点上使用 rs.add() 命令添加节点。例如,要添加一个新的数据节点 192.168.1.104:27017,在主节点的 mongo 命令行中执行:

rs.add("192.168.1.104:27017")

如果添加成功,会看到类似以下的输出:

{ "ok" : 1, "operationTime" : Timestamp(1652345678, 2), "$clusterTime" : { "clusterTime" : Timestamp(1652345678, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }

添加节点后,可以使用 rs.status() 命令查看副本集状态,确认新节点已成功加入。

删除节点:要从副本集中删除节点,可以在主节点上使用 rs.remove() 命令。例如,要删除节点 192.168.1.104:27017,在主节点的 mongo 命令行中执行:

rs.remove("192.168.1.104:27017")

执行该命令后,副本集会自动进行调整,被删除节点的数据会被重新分布到其他节点。同样,可以使用 rs.status() 命令确认节点已被成功删除。

6.2 故障处理与恢复

在副本集运行过程中,可能会遇到节点故障的情况。MongoDB 的副本集机制可以在一定程度上自动处理节点故障。

主节点故障:当主节点发生故障时,副本集中的从节点会发起选举,选出一个新的主节点。在选举过程中,仲裁节点会参与投票,以确保选举的公正性。一旦新的主节点选举产生,副本集就可以继续正常工作。例如,假设主节点 192.168.1.101 发生故障,从节点 192.168.1.102192.168.1.103 会发起选举,最终其中一个从节点会成为新的主节点。可以通过 rs.status() 命令查看选举结果和新主节点的信息。

从节点故障:如果从节点发生故障,副本集仍然可以正常工作,因为主节点仍然可以处理写操作和读操作。但是,从节点故障会导致副本集的冗余度降低,容错能力减弱。当从节点恢复后,它会自动与主节点进行数据同步,重新成为副本集的有效节点。可以通过查看从节点的日志文件来了解其数据同步的进度。

6.3 性能优化

为了提高副本集的性能,可以采取以下一些优化措施:

  1. 调整 oplog 大小:oplog 是 MongoDB 用于记录写操作的日志,合理调整 oplog 的大小可以影响副本集的数据同步性能。如果 oplog 太小,可能会导致从节点跟不上主节点的写操作速度;如果 oplog 太大,会占用过多的磁盘空间。可以根据实际的写操作负载来调整 oplog 的大小。例如,在初始化副本集时,可以通过 oplogSizeMB 参数设置 oplog 的大小,如 rs.initiate({ _id: "rs0", members: [ { _id: 0, host: "192.168.1.101:27017" }, { _id: 1, host: "192.168.1.102:27017" }, { _id: 2, host: "192.168.1.103:27017" } ], oplogSizeMB: 2048 }),这里将 oplog 大小设置为 2048MB。
  2. 负载均衡:合理分配读操作到从节点可以减轻主节点的负载,提高系统的整体性能。可以在应用程序中配置读偏好(Read Preference),将读操作导向从节点。例如,在 Node.js 应用程序中,可以使用以下代码设置读偏好为 secondaryPreferred
const { MongoClient } = require('mongodb');
const uri = "mongodb://192.168.1.101:27017,192.168.1.102:27017,192.168.1.103:27017/?replicaSet=rs0";
const client = new MongoClient(uri, { readPreference: "secondaryPreferred" });
async function run() {
  try {
    await client.connect();
    const database = client.db('test');
    const collection = database.collection('documents');
    const result = await collection.find({}).toArray();
    console.log(result);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

这样,读操作会优先选择从节点执行,如果从节点不可用,才会选择主节点。

  1. 索引优化:在副本集中,索引的使用对于查询性能至关重要。确保在经常查询的字段上创建合适的索引,可以大大提高查询效率。例如,在 mongo 命令行中,可以使用以下命令为集合 usersname 字段创建索引:
use mydb;
db.users.createIndex({ name: 1 });

这里 { name: 1 } 表示创建一个升序索引,如果要创建降序索引,可以使用 { name: -1 }

通过以上步骤和操作,就可以成功创建并管理 MongoDB 副本集,确保数据的高可用性和系统的高性能运行。在实际应用中,还需要根据业务需求和系统规模不断优化副本集的配置和性能。