Docker快速部署Mongodb主副本集实践指南

 更新时间:2025年09月05日 09:02:43   作者:瑞瑞绮绮  
本文主要介绍了MongoDB主副本集的基本概念及其应用场景,MongoDB适合处理数据不固定且不支持事务的业务需求,通过主副本集实现高可用性和数据一致性,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧

系列文章目录

第一章 Mongodb的主副本集

前言

公司有项目需要满足数据内容不固定,Mongodb更适合此业务,但是不支持事务,于是了解到主副本集可以满足。

一、Mongodb基础介绍

数据库(Database)

Mongodb 中的数据库是一组集合(Collection)的容器,每个数据库在文件系统中有独立的文件存储。数据库名称区分大小写,通常用于逻辑隔离不同应用或模块的数据。

集合(Collection)

集合是 Mongodb 中存储文档(Document)的容器,类似于关系型数据库中的表。集合不需要预先定义结构,可以动态存储不同格式的文档。集合名称同样区分大小写。

文档(Document)

文档是 Mongodb 中的数据基本单元,采用 BSON(Binary JSON)格式存储。文档由键值对组成,键是字符串,值可以是多种数据类型(如字符串、数字、数组、嵌套文档等)。例如:

{
  "name": "Alice",
  "age": 30,
  "address": {
    "city": "New York",
    "zip": "10001"
  }
}

BSON(Binary JSON)

BSON 是 JSON 的二进制编码格式,扩展了 JSON 的数据类型(如日期、二进制数据等)。Mongodb 使用 BSON 在内部存储和传输数据,支持高效查询和索引。

_id(主键)

每个文档必须包含一个唯一的 _id 字段作为主键。如果插入文档时未指定 _id,Mongodb 会自动生成一个 ObjectId 类型的值。_id 字段默认建立索引。

索引(Index)

索引用于加速查询性能,类似于关系型数据库的索引。Mongodb 支持单字段索引、复合索引、多键索引(数组字段)、全文索引等。例如创建索引的命令:

db.collection.createIndex({ "name": 1 }) // 1表示升序,-1表示降序

分片(Sharding)

分片是 Mongodb 的横向扩展机制,将数据分散到多个分片(Shard)上。每个分片是独立的数据库实例,共同组成一个逻辑数据库。分片通过分片键(Shard Key)路由数据。

副本集(Replica Set)

副本集是一组维护相同数据的 Mongodb 实例,提供高可用性。包含一个主节点(Primary)和多个从节点(Secondary)。主节点处理写操作,从节点同步数据并支持读操作。

聚合管道(Aggregation Pipeline)

聚合管道是数据处理框架,通过多个阶段(Stage)对文档进行转换和计算。每个阶段处理输入文档并输出结果到下一阶段。常见阶段包括 $match$group$sort 等。

CRUD 操作

CRUD 指 Mongodb 的基本数据操作:

  • CreateinsertOne()insertMany()
  • Readfind()findOne()
  • UpdateupdateOne()updateMany()
  • DeletedeleteOne()deleteMany()

写关注(Write Concern)

写关注定义写操作的确认级别,控制数据持久化的可靠性。例如:

db.collection.insertOne(
  { "key": "value" },
  { writeConcern: { w: "majority", j: true } } // w: 写入节点数,j: 日志持久化
)

读偏好(Read Preference)

读偏好指定查询请求的路由规则,允许从主节点或从节点读取数据。选项包括 primarysecondarynearest 等,适用于读写分离场景。

二、Mongodb事务

事务的基本概念

MongoDB 从 4.0 版本开始支持多文档事务,适用于副本集;从 4.2 版本开始支持分片集群的事务。事务提供 ACID 特性,确保数据操作的原子性、一致性、隔离性和持久性。

启用事务的前提条件

MongoDB 事务需要运行在副本集或分片集群上,单机模式不支持事务。确保 MongoDB 实例已正确配置为副本集或分片集群。

事务的使用方法

在 MongoDB 中使用事务需要通过会话(Session)来管理。以下是一个基本的事务操作示例:

const session = db.getMongo().startSession();
session.startTransaction({
    readConcern: { level: "snapshot" },
    writeConcern: { w: "majority" }
});
try {
    const collection1 = session.getDatabase("db1").collection1;
    const collection2 = session.getDatabase("db2").collection2;
    collection1.insertOne({ name: "Alice" }, { session });
    collection2.updateOne({ name: "Bob" }, { $set: { age: 30 } }, { session });
    session.commitTransaction();
} catch (error) {
    session.abortTransaction();
    throw error;
} finally {
    session.endSession();
}

事务的隔离级别

MongoDB 提供 snapshot 隔离级别,确保事务内读取的数据来自同一快照。可以通过 readConcern 设置:

readConcern: { level: "snapshot" }

事务的写关注

事务中的写操作可以通过 writeConcern 指定确认级别,通常设置为 majority 以确保数据持久性:

writeConcern: { w: "majority" }

事务的注意事项

事务中的操作必须显式指定会话(Session),否则操作不会包含在事务中。事务的执行时间不宜过长,避免锁竞争和性能问题。事务支持的文档操作包括插入、更新、删除和查询。

事务的性能优化

为了减少事务对性能的影响,尽量缩小事务范围,减少事务内的操作数量。避免在事务中执行耗时操作,如大规模数据扫描。合理设置事务超时时间,防止长时间占用资源。

事务的错误处理

事务执行过程中如果发生错误,必须捕获异常并显式调用 abortTransaction 回滚事务。确保事务结束后调用 endSession 释放会话资源。

事务的限制

MongoDB 事务不支持某些操作,如创建或删除集合、创建或删除索引。事务内的写操作不能影响分片键的值。单个事务的文档修改量默认限制为 16MB,超过会导致错误。

三、Docker部署MongoDB主副本集

环境准备

  • linux服务器,内存不少于8G,cpu至少I5,磁盘500G起步,这里我用的是CentOS7,架构是x86_64,通过如下命令确认
[root@host ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
[root@host ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                16
On-line CPU(s) list:   0-15
Thread(s) per core:    2
Core(s) per socket:    8
座:                 1
NUMA 节点:         1
厂商 ID:           GenuineIntel
CPU 系列:          6
型号:              165
型号名称:        Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
步进:              5
CPU MHz:             800.048
CPU max MHz:           4800.0000
CPU min MHz:           800.0000
BogoMIPS:            5800.00
虚拟化:           VT-x
L1d 缓存:          32K
L1i 缓存:          32K
L2 缓存:           256K
L3 缓存:           16384K
NUMA 节点0 CPU:    0-15

Docker安装

欧拉系统部署Docker实践指南, 参考前面部分就行。

具体安装

  • 镜像用的是mongo最新版,可以直接拉取,也可以docker run时拉取
  • 这里配置3个,做1主两从
  • 新建目录,用于挂载存放配置文件
mkdir -p /home/mongodb  && chown -R 200 /home/mongodb
  • 确定主端口:27017,2个从分别是27018、27019
  • 命令列表
#自定义网络
docker network create --subnet=172.18.0.0/16 my-network
# 查看已存在网络
docker network ls
# mongo容器认证启动方式
docker run --restart=always --privileged -p 27017:27017 --name mongodbMaster --network my-network --ip 172.18.0.1 -v /home/mongo/mongoMaster/config:/data/configdb -v /home/mongo/mongoMaster/db:/data/db -v /home/mongo/mongoMaster/logs:/data/log -d mongo --replSet rs
docker run --restart=always --privileged -p 27018:27017 --name mongodbSlave1 --network my-network --ip 172.18.0.2 -v /home/mongo/mongoSlave1/config:/data/configdb -v /home/mongo/mongoSlave1/db:/data/db -v /home/mongo/mongoSlave1/logs:/data/log -d mongo --replSet rs
docker run --restart=always --privileged -p 27019:27017 --name mongodbSlave2 --network my-network --ip 172.18.0.3 -v /home/mongo/mongoSlave2/config:/data/configdb -v /home/mongo/mongoSlave2/db:/data/db -v /home/mongo/mongoSlave2/logs:/data/log -d mongo --replSet rs
  • 执行docker images | grep mongo, 发现3个容器已经创建并运行
  • 进入容器,创建账号、授权
docker exec -it mongodbMaster /bin/bash
进入MongoDB交互式命令行并切换到admin数据库
mongo
use admin
//管理员 
db.createUser({ user: 'rwuser', pwd: 'xxxxx', roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] });
db.auth('rwuser', 'xxxxx') //返回1表示认证成功
db.getCollectionNames() //所有创建的用户都会存储在system.users集合中
//factory-dev
use factory-dev //切换到目标数据库
db.createUser({ user: 'test', pwd: 'xxxxx', roles: [ { role: "readWrite", db: "db1" } ] });
db.auth('test', 'xxxxx') //返回1表示认证成功
# 查看主节点,找到members[].stateStr:主节点应为 "PRIMARY",说明ok。
rs:PRIMARY> rs.status()
{
        "set" : "rs",
        "date" : ISODate("2025-09-04T00:32:31.156Z"),
        "myState" : 1,
        "term" : NumberLong(335),
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "majorityVoteCount" : 2,
        "writeMajorityCount" : 2,
        "votingMembersCount" : 3,
        "writableVotingMembersCount" : 3,
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1756945945, 1),
                        "t" : NumberLong(335)
                },
                "lastCommittedWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1756945945, 1),
                        "t" : NumberLong(335)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1756945945, 1),
                        "t" : NumberLong(335)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1756945945, 1),
                        "t" : NumberLong(335)
                },
                "lastAppliedWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                "lastDurableWallTime" : ISODate("2025-09-04T00:32:25.880Z")
        },
        "lastStableRecoveryTimestamp" : Timestamp(1756945915, 1),
        "electionCandidateMetrics" : {
                "lastElectionReason" : "electionTimeout",
                "lastElectionDate" : ISODate("2025-09-03T06:59:13.712Z"),
                "electionTerm" : NumberLong(335),
                "lastCommittedOpTimeAtElection" : {
                        "ts" : Timestamp(1756882537, 1),
                        "t" : NumberLong(334)
                },
                "lastSeenOpTimeAtElection" : {
                        "ts" : Timestamp(1756882547, 1),
                        "t" : NumberLong(334)
                },
                "numVotesNeeded" : 2,
                "priorityAtElection" : 1,
                "electionTimeoutMillis" : NumberLong(10000),
                "numCatchUpOps" : NumberLong(0),
                "newTermStartDate" : ISODate("2025-09-03T06:59:13.799Z"),
                "wMajorityWriteAvailabilityDate" : ISODate("2025-09-03T06:59:14.450Z")
        },
        "electionParticipantMetrics" : {
                "votedForCandidate" : true,
                "electionTerm" : NumberLong(333),
                "lastVoteDate" : ISODate("2025-09-03T06:54:18.247Z"),
                "electionCandidateMemberId" : 2,
                "voteReason" : "",
                "lastAppliedOpTimeAtElection" : {
                        "ts" : Timestamp(1756882339, 1),
                        "t" : NumberLong(331)
                },
                "maxAppliedOpTimeInSet" : {
                        "ts" : Timestamp(1756882339, 1),
                        "t" : NumberLong(331)
                },
                "priorityAtElection" : 1
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "f1737b1cbbc5:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 63539,
                        "optime" : {
                                "ts" : Timestamp(1756945945, 1),
                                "t" : NumberLong(335)
                        },
                        "optimeDate" : ISODate("2025-09-04T00:32:25Z"),
                        "lastAppliedWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                        "lastDurableWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "electionTime" : Timestamp(1756882753, 1),
                        "electionDate" : ISODate("2025-09-03T06:59:13Z"),
                        "configVersion" : 5,
                        "configTerm" : 335,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "172.18.0.1:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 63207,
                        "optime" : {
                                "ts" : Timestamp(1756945945, 1),
                                "t" : NumberLong(335)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1756945945, 1),
                                "t" : NumberLong(335)
                        },
                        "optimeDate" : ISODate("2025-09-04T00:32:25Z"),
                        "optimeDurableDate" : ISODate("2025-09-04T00:32:25Z"),
                        "lastAppliedWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                        "lastDurableWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                        "lastHeartbeat" : ISODate("2025-09-04T00:32:31.006Z"),
                        "lastHeartbeatRecv" : ISODate("2025-09-04T00:32:31.009Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "f1737b1cbbc5:27017",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 5,
                        "configTerm" : 335
                },
                {
                        "_id" : 2,
                        "name" : "172.18.0.2:27017",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 63206,
                        "optime" : {
                                "ts" : Timestamp(1756945945, 1),
                                "t" : NumberLong(335)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1756945945, 1),
                                "t" : NumberLong(335)
                        },
                        "optimeDate" : ISODate("2025-09-04T00:32:25Z"),
                        "optimeDurableDate" : ISODate("2025-09-04T00:32:25Z"),
                        "lastAppliedWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                        "lastDurableWallTime" : ISODate("2025-09-04T00:32:25.880Z"),
                        "lastHeartbeat" : ISODate("2025-09-04T00:32:31.009Z"),
                        "lastHeartbeatRecv" : ISODate("2025-09-04T00:32:31.006Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "f1737b1cbbc5:27017",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 5,
                        "configTerm" : 335
                }
        ],
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1756945945, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1756945945, 1)
}
  • 一定要注意mongoDB重启顺序:docker start mongodbMaster,docker start mongodbSlave1,docker start mongodbSlave2
    先启动mongodbMaster那个就会成为PRIMARY,也是可以读写的,其他的都是副本集,属于SECONDARY,只能读

验证

使用Navicat数据库连接工具,点击连接,选择monogb

输入ip 端口,账号、密码、数据库名,这里端口填写主端口27017,最后点击一下"测试连接",返回OK说明配置连接成功。

右键新一个数据库test

选择集合,新建一个集合demo1

建表SQL,我这里用的是脚本执行的

// ----------------------------
// Collection structure for autoId
// ----------------------------
db.getCollection("demo1").drop();
db.createCollection("demo1");
// ----------------------------
// Documents of autoId
// ----------------------------
db.getCollection("demo1").insert([ {
    _id: "6394049da732a862951f5a62",    
    autoId: NumberInt("1288641"),
    collectionName: "product"
} ]);

插入成功后,效果如下

事务验证这块,因为使用的代码验证的,你们只能自行用代码验证了,方法很简单,开启事务后,先执行一个插入,再制造一个异常,比如 1/0, 看数据是否回滚。

小结

  • 遇到无法写入数据时,先进入任何一个容器
    比如 docker exec -it mongodbMaster /bin/bash
    mongo
    rs.status();
    查看
    members[].stateStr:主节点应为 “PRIMARY”。
    members[].health:健康节点值为 1。
    若都为SECONDARY,说明还没有确定谁是PRIMARY,先等一会再执行看看是否有PRIMARY,有的那个就是可以连接和读写的容器
    若一直都是SECONDARY,就要检查容器情况了。

到此这篇关于Docker快速部署Mongodb主副本集实践的文章就介绍到这了,更多相关Docker部署Mongodb内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • .netcore 使用surging框架发布到docker

    .netcore 使用surging框架发布到docker

    这篇文章主要介绍了netcore 使用surging框架发布到docker,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • docker容器启动设置固定IP的实现

    docker容器启动设置固定IP的实现

    本文主要介绍了docker容器启动设置固定IP的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • docker-compose部署etcd集群的实现步骤

    docker-compose部署etcd集群的实现步骤

    本文主要介绍了docker-compose部署etcd集群的实现步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • 设置docker的定时关闭和启动方式

    设置docker的定时关闭和启动方式

    文章介绍了在Docker中设置容器定时关闭和启动的两种方法:使用系统级定时任务(如cron)和使用Docker特定的解决方案,通过配置CronJob、DockerCompose或DockerSwarm,可以实现容器的定时启动和关闭
    2024-12-12
  • docker实践之docker-compose部署mysql方式

    docker实践之docker-compose部署mysql方式

    这篇文章主要介绍了docker实践之docker-compose部署mysql方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Docker-compose部署ELK的示例代码

    Docker-compose部署ELK的示例代码

    这篇文章主要介绍了Docker-compose部署ELK的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 解决docker images 镜像消失的问题

    解决docker images 镜像消失的问题

    这篇文章主要介绍了解决docker images 镜像消失的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Logshark调试Logstash及Filebeat pipelines使用详解

    Logshark调试Logstash及Filebeat pipelines使用详解

    这篇文章主要为大家介绍了Logshark调试Logstash及Filebeat pipelines使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Docker volume 挂载卷的实现方法

    Docker volume 挂载卷的实现方法

    这篇文章主要介绍了Docker volume 挂载卷的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • Dockerfile与.gitlab-ci.yml的关系以及构建自动化镜像方式

    Dockerfile与.gitlab-ci.yml的关系以及构建自动化镜像方式

    GitLabCI/CDPipeline中构建Docker镜像的步骤如下:1.了解Dockerfile和.gitlab-ci.yml之间的关系;2.定义构建Docker镜像的阶段;3.在阶段中调用Dockerfile来构建镜像
    2024-11-11

最新评论