前言
相信很多前端同学在开发 Web 应用的过程中都会使用 MongoDB 数据库,而随着 Docker 技术的不断发展,使用 Docker 部署 MongoDB 也成为了一种趋势。本文旨在提供一个完整的 MongoDB 副本集在 Docker 容器中的部署过程,并带领大家完成 MongoDB 副本集的实践。
准备工作
在开始实践前,我们需要先准备一下环境:
- 安装 Docker 工具箱
- 安装 Docker Compose 工具
MongoDB 副本集简介
MongoDB 副本集是一个拥有多个副本节点的 MongoDB 部署,其中有一个节点为主节点(Primary),其他节点则为从节点(Secondary)。所有写操作均在主节点上执行,而读操作则可以在主节点和从节点都执行。在主节点发生宕机或者不可用的情况下,系统会自动将从节点中选举出一个作为新的主节点。
MongoDB 副本集的优点
- 支持容错和高可用
- 支持读写集群,提升读写性能
- 支持数据备份和恢复
MongoDB 副本集的不足之处
- 无法保证完全的实时性
- 部分写操作需要大量资源
- MongoDB 副本集配置较为复杂
MongoDB 副本集在 Docker 中的部署
MongoDB 在 Docker 中的部署方式有很多种,本文采用了 Docker Compose 来管理容器。在本次实践中,我们将使用一个 3 节点的 MongoDB 副本集,包括一个 Primary 节点和两个 Secondary 节点。
Docker Compose 文件
下面是 MongoDB 副本集在 Docker 中的部署配置文件,名为 docker-compose.yml。
// javascriptcn.com 代码示例 version: '3' services: mongo-primary: image: mongo volumes: - ./primary/mongo.conf:/etc/mongo/mongo.conf - ./primary/data:/data/db command: mongod --config /etc/mongo/mongo.conf --replSet "rs0" ports: - 27017:27017 networks: - mongo-network mongo-secondary-1: image: mongo volumes: - ./secondary-1/mongo.conf:/etc/mongo/mongo.conf - ./secondary-1/data:/data/db command: mongod --config /etc/mongo/mongo.conf --replSet "rs0" ports: - 27018:27017 networks: - mongo-network mongo-secondary-2: image: mongo volumes: - ./secondary-2/mongo.conf:/etc/mongo/mongo.conf - ./secondary-2/data:/data/db command: mongod --config /etc/mongo/mongo.conf --replSet "rs0" ports: - 27019:27017 networks: - mongo-network networks: mongo-network:
上述配置文件一共定义了三个服务,即 mongo-primary、mongo-secondary-1 和 mongo-secondary-2,分别对应了三个 MongoDB 副本集节点。下面我们就逐一来解释一下三个服务的配置:
- mongo-primary:该服务是 MongoDB 副本集的主节点,使用的镜像为官方的 mongo 镜像。该服务挂载了一个配置文件和一个数据卷,其中配置文件 mongo.conf 配置了 MongoDB 副本集的相关参数,数据卷 data 则用于存储 MongoDB 数据库的数据。
- mongo-secondary-1 和 mongo-secondary-2:这两个服务是 MongoDB 副本集的从节点,使用的镜像同样为官方的 mongo 镜像。这两个服务和 mongo-primary 同样挂载了配置文件和数据卷,并且都在命令中指定了 --replSet "rs0" 参数,用于建立副本集。
配置文件
下面是上述所提到的 MongoDB 配置文件 mongo.conf 的内容:
// javascriptcn.com 代码示例 systemLog: destination: file path: "/data/log/mongod.log" logAppend: true storage: dbPath: "/data/db" journal: enabled: true processManagement: fork: true pidFilePath: "/tmp/mongod.pid" net: bindIp: 0.0.0.0 port: 27017 replication: replSetName: "rs0"
该配置文件的作用是为 MongoDB 副本集提供相关参数的配置信息。在配置文件中,我们指定了 MongoDB 数据库的 log 和 pid 文件存储路径,以及数据库 bindIp、port 等信息,并且在最后指定了副本集的名称。
构建 MongoDB 副本集
在服务配置文件和配置文件都已经准备好的情况下,我们就可以开始构建 MongoDB 副本集了。打开终端,进入到 docker-compose.yml 所在的文件夹下,运行以下命令:
docker-compose up -d
该命令会启动我们之前在 Docker Compose 文件中定义的三个服务,并且以后台模式运行。当所有服务都启动成功后,我们可以在命令行中输入以下命令,进入 mongo-primary 服务的容器中查看 MongoDB 副本集的状态:
docker-compose exec mongo-primary bash mongo rs.status()
如果所有节点都成功建立,输出结果如下:
// javascriptcn.com 代码示例 { "set" : "rs0", "date" : ISODate("2021-12-12T10:55:31.007Z"), "myState" : 1, "term" : NumberLong(7), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "lastCommittedOpTimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "readConcernMajorityOpTimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "appliedOpTime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "appliedOpTimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "durableOpTime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "durableOpTimeDate" : ISODate("2022-04-12T11:08:54.000Z") }, "lastStableCheckpointTimestamp" : Timestamp(1649849700, 1), "electionCandidateMetrics" : { "lastElectionReason" : "newTerm", "lastElectionDate" : ISODate("2022-04-12T11:07:13.136Z"), "termAtElection" : NumberLong(7), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(1649849396, 1), "t" : NumberLong(6) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1649849396, 1), "t" : NumberLong(6) }, "candidacyDeclarationDate" : ISODate("2022-04-12T11:07:09.139Z"), "promotionDate" : ISODate("2022-04-12T11:07:13.201Z"), "electionReason" : "newTerm", "term" : NumberLong(7), "lastCommittedOpTime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "lastCommittedOpTimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "lastSeenOpTime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "lastSeenOpTimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "electionTimeoutMillis" : NumberLong(10000), "newTermStartDate" : ISODate("2022-04-12T11:07:13.156Z"), "wMajorityWriteAvailabilityDate" : ISODate("2022-04-12T11:07:13.201Z") }, "members" : [ { "_id" : 0, "name" : "mongo-primary:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 298, "uptimeMillis" : NumberLong(298404), "optime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "optimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1649849233, 2), "electionDate" : ISODate("2022-04-12T11:00:33.000Z"), "configVersion" : 2, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "mongo-secondary-1:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 294, "uptimeMillis" : NumberLong(294019), "optime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "optimeDurable" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "optimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "optimeDurableDate" : ISODate("2022-04-12T11:08:54.000Z"), "lastHeartbeat" : ISODate("2022-04-12T11:09:02.153Z"), "lastHeartbeatRecv" : ISODate("2022-04-12T11:09:02.661Z"), "pingMs" : NumberLong(0), "syncingTo" : "mongo-primary:27017", "syncSourceHost" : "mongo-primary:27017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 2 }, { "_id" : 2, "name" : "mongo-secondary-2:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 290, "uptimeMillis" : NumberLong(290455), "optime" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "optimeDurable" : { "ts" : Timestamp(1649849734, 1), "t" : NumberLong(7) }, "optimeDate" : ISODate("2022-04-12T11:08:54.000Z"), "optimeDurableDate" : ISODate("2022-04-12T11:08:54.000Z"), "lastHeartbeat" : ISODate("2022-04-12T11:09:03.275Z"), "lastHeartbeatRecv" : ISODate("2022-04-12T11:09:03.164Z"), "pingMs" : NumberLong(0), "syncingTo" : "mongo-primary:27017", "syncSourceHost" : "mongo-primary:27017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 2 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1649849734, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1649849734, 1) }
在输出结果中,我们可以看到副本集的名称为 rs0,而且三个节点的状态均为 SECONDARY 或 PRIMARY,表示我们已经成功的部署了 MongoDB 副本集。
测试 MongoDB 副本集
在成功构建 MongoDB 副本集后,我们需要测试一下集群的读写性能。
MongoDB 副本集的读写操作测试
在 mongo-primary 节点所在的容器内,可以通过以下命令打开 MongoDB Shell:
docker-compose exec mongo-primary mongo
我们可以在 MongoDB Shell 中先插入一些数据:
> db.test.insert({name: 'John', age: 18, gender: 'male'}) > db.test.insert({name: 'Mike', age: 22, gender: 'male'}) > db.test.insert({name: 'Lucy', age: 25, gender: 'female'})
接着,在容器内打开另一个终端,分别在 mongo-secondary-1 和 mongo-secondary-2 节点所在的容器中使用以下命令进入 MongoDB Shell:
docker-compose exec mongo-secondary-1 mongo rs0/mongo-secondary-1:27017 docker-compose exec mongo-secondary-2 mongo rs0/mongo-secondary-2:27017
接下来,我们在三个容器的 MongoDB Shell 中分别执行下面的命令,验证读写操作是否生效。
在 mongo-primary 节点中:
> db.test.find() { "_id" : ObjectId("620a919a36fafaa422d2dbd1"), "name" : "John", "age" : 18, "gender" : "male" } { "_id" : ObjectId("620a919a36fafaa422d2dbd2"), "name" : "Mike", "age" : 22, "gender" : "male" } { "_id" : ObjectId("620a919a36fafaa422d2dbd3"), "name" : "Lucy", "age" : 25, "gender" : "female" }
在 mongo-secondary-1 和 mongo-secondary-2 节点中:
> db.test.find() { "_id" : ObjectId("620a919a36fafaa422d2dbd1"), "name" : "John", "age" : 18, "gender" : "male" } { "_id" : ObjectId("620a919a36fafaa422d2dbd2"), "name" : "Mike", "age" : 22, "gender" : "male" } { "_id" : ObjectId("620a919a36fafaa422d2dbd3"), "name" : "Lucy", "age" : 25, "gender" : "female" }
接下来,我们在 mongo-primary 节点中进行写操作,然后在另外两个节点中读取刚刚写入的数据,验证 MongoDB 副本集是否生效。
在 mongo-primary 节点中:
> db.test.insert({name: 'Tom', age: 28, gender: 'male'})
在 mongo-secondary-1 和 mongo-secondary-2 节点中:
> db.test.find() { "_id" : ObjectId("620a919a36fafaa422d2dbd1"), "name" : "John", "age" : 18, "gender" : "male" } { "_id" : ObjectId("620a919a36fafaa422d2dbd2"), "name" : "Mike", "age" : 22, "gender" : "male" } { "_id" : ObjectId("620a919a36fafaa422d2dbd3"), "name" : "Lucy", "age" : 25, "gender" : "female" } { "_id" : ObjectId("620a92bd36fafaa422d2dbd4"), "name" : "Tom", "age" : 28, "gender" : "male" }
可以看到,在 mongo-primary 节点中写入的数据已经成功同步到了其他节点。
总结
本文详细介绍了如何通过 Docker Compose 部署 MongoDB 副本集,并提供了配置文件和部署过程的详细说明。MongoDB 副本集在 Web 应用开发中起着重要的作用,通过学习本文,我们可以更加深入地理解和应用 MongoDB 数据库和 Docker 技术。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6535c8be7d4982a6ebd5c52d