最近更换了办公地点。部署在本地docker环境里的mongo数据库不能使用了。原因是本地的ip地址变更。以前的mongo副本集的配置需要更新。处理完后,索性重新记录一下mongo副本集在docker中的部署流程。
mongo的事务及副本集
我们先了解一下什么是事务,事务是一组对数据库执行的操作,这些操作作为一个不可分割的工作单元。在MongoDB中,一个事务可以涉及多个文档和多个集合。例如一个订单的下单过程,涉及到订单的生成,商品库存变化等多个文档的变化。在服务端执行过程中,如果某一段代码产生了错误。不使用事务的话,可能会导致订单生成来,商品库存却不变的情况发生。而使用事务后,整个下单将会作为一个整体,所有数据变化成功后,才会被最终写入数据库中。
在MongoDB中使用事务需要满足一些前提条件。以下是使用MongoDB事务的主要前提:
-
MongoDB版本:
- 事务功能是在MongoDB 4.0版本中引入的。因此,要使用MongoDB事务,必须使用4.0版本或更高版本。
-
副本集:
- 事务功能通常需要在副本集环境中运行。虽然在4.0版本中引入了单节点事务支持,但在实际生产环境中,建议在副本集中使用事务,以提供更好的高可用性和故障容忍性。
-
写操作:
- 事务只能用于读写操作,包括插入、更新和删除。只有在进行写操作时,才能在事务中使用。
-
支持的存储引擎:
- MongoDB事务支持WiredTiger存储引擎。确保你的MongoDB实例使用的是WiredTiger存储引擎。
我们主要来了解一下副本集。
MongoDB的副本集(Replica Set)是一种用于提供数据冗余和高可用性的数据库架构。副本集包含多个MongoDB实例,其中一个是主节点,其余是从节点。以下是副本集的一些关键概念和目的:
-
主节点(Primary):
- 主节点是副本集的核心,负责处理所有写操作和客户端的读操作。只有主节点才能执行写操作,而且它会将这些写操作的结果同步到所有从节点。
-
从节点(Secondary):
- 从节点是主节点的副本,用于提供数据冗余和高可用性。从节点接收主节点的写操作,并在本地执行这些写操作,从而保持与主节点的数据同步。从节点可以用于读操作,但不处理写操作。
-
数据冗余和高可用性:
- 副本集的一个主要目的是提供数据冗余,确保数据不会因硬件故障或其他问题而丢失。同时,通过将读操作分发到从节点,副本集提供了更好的读取性能和高可用性。
-
自动故障转移:
- 如果主节点发生故障,副本集会自动选择一个从节点作为新的主节点,确保系统的可用性。这种自动故障转移是副本集的一个重要特性。
-
部署多个节点:
- MongoDB副本集可以包含多个节点,从而提供更强大的数据冗余和可用性。节点可以部署在不同的物理位置,以提高系统的容错性。
副本集部署
参考:windows下搭建mongo副本集
-
- 首先需要在docker中启用3个mongo实例,并设置他们为同一个副本集。我这里是直接配置的docker-compose.yml文件来启用实例。
# 创建3个实例,并设置他们副本集为 --replSet mongos,并创建每个实例的数据存储文件
mongodb1:
image: mongo:4.2.1
volumes:
- ./data/mongo1:/data/db
- ./MongoDB/copy:/copy
user: root
container_name: mongodb1
ports:
- 27018:27017
command: mongod --replSet mongos
restart: always
mongodb2:
image: mongo:4.2.1
volumes:
- ./data/mongo2:/data/db
- ./MongoDB/copy2:/copy
user: root
container_name: mongodb2
ports:
- 27019:27017
command: mongod --replSet mongos
restart: always
mongodb3:
image: mongo:4.2.1
volumes:
- ./data/mongo3:/data/db
- ./MongoDB/copy3:/copy
user: root
container_name: mongodb3
ports:
- 27020:27017
command: mongod --replSet mongos
restart: always
-
- 进入任意mongo实例中,初始化副本集,使副本集生效。
1. docker exec -it mongodb1 /bin/sh
2. 进入mongo,初始化副本集。
rs.initiate({
_id: "mongos",
members: [
{ _id : 0, host : "192.168.1.35:27017" },
{ _id : 1, host : "192.168.1.35:27018" },
{ _id : 2, host : "192.168.1.35:27019" }
]
});
# 因为我是本地环境的副本集,所以设置host为本地IP。
# 执行后的结果
{
"ok" : 1,
"operationTime" : Timestamp(1562140190, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1562140190, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
-
- 校验正确性
#使用 rs.status()检查副本集是否被正确设置
{
"set" : "mongos",
"date" : ISODate("2024-01-17T06:58:59.456Z"),
"myState" : 2,
"term" : NumberLong(7873),
"syncingTo" : "192.168.1.35:27019",
"syncSourceHost" : "192.168.1.35:27019",
"syncSourceId" : 1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"lastCommittedWallTime" : ISODate("2024-01-17T06:58:53.638Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"readConcernMajorityWallTime" : ISODate("2024-01-17T06:58:53.638Z"),
"appliedOpTime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"durableOpTime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"lastAppliedWallTime" : ISODate("2024-01-17T06:58:53.638Z"),
"lastDurableWallTime" : ISODate("2024-01-17T06:58:53.638Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1705474703, 1),
"lastStableCheckpointTimestamp" : Timestamp(1705474703, 1),
"members" : [
{
"_id" : 0,
"name" : "192.168.1.35:27018",
"ip" : "192.168.1.35",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 20000,
"optime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"optimeDate" : ISODate("2024-01-17T06:58:53Z"),
"syncingTo" : "192.168.1.35:27019",
"syncSourceHost" : "192.168.1.35:27019",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 100459,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.1.35:27019",
"ip" : "192.168.1.35",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 19965,
"optime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"optimeDurable" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"optimeDate" : ISODate("2024-01-17T06:58:53Z"),
"optimeDurableDate" : ISODate("2024-01-17T06:58:53Z"),
"lastHeartbeat" : ISODate("2024-01-17T06:58:58.811Z"),
"lastHeartbeatRecv" : ISODate("2024-01-17T06:58:58.809Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1705454782, 1),
"electionDate" : ISODate("2024-01-17T01:26:22Z"),
"configVersion" : 100459
},
{
"_id" : 2,
"name" : "192.168.1.35:27020",
"ip" : "192.168.1.35",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 19965,
"optime" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"optimeDurable" : {
"ts" : Timestamp(1705474733, 1),
"t" : NumberLong(7873)
},
"optimeDate" : ISODate("2024-01-17T06:58:53Z"),
"optimeDurableDate" : ISODate("2024-01-17T06:58:53Z"),
"lastHeartbeat" : ISODate("2024-01-17T06:58:58.810Z"),
"lastHeartbeatRecv" : ISODate("2024-01-17T06:58:58.810Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "",
"syncingTo" : "192.168.1.35:27019",
"syncSourceHost" : "192.168.1.35:27019",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 100459
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1705474733, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1705474733, 1)
}
配置成功后,我们的mongo命令行会显示当前实例是主节点(PRIMARY)or子节点(SECONDARY)
更新配置
当我的ip变化后,之前的配置就无效了,mongo的命令行也会显示当前的mongo节点为OTHER
rs.initiate({
_id: "mongos",
members: [
{ _id : 0, host : "192.168.1.35:27017" },
{ _id : 1, host : "192.168.1.35:27018" },
{ _id : 2, host : "192.168.1.35:27019" }
]
});
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
mongos:OTHER>
此时3个mongo实例都是宕机的OTHER状态,既非主节点也非子节点。需要我们更新members成员的IP信息。
#进入任意mongo实例
#获取配置信息
mongos:OTHER>cfg = rs.conf()
#更新配置信息
mongos:OTHER>cfg.members[0].host="192.168.6.3:27018"
mongos:OTHER>cfg.members[1].host="192.168.6.3:27018"
mongos:OTHER>cfg.members[2].host="192.168.6.3:27018"
# 使用rs.reconfig(cfg)重设配置,此时会抛错
mongos:OTHER>rs.reconfig(cfg)
{
"operationTime" : Timestamp(1705368470, 1),
"ok" : 0,
"errmsg" : "replSetReconfig should only be run on PRIMARY, but my state is REMOVED; use the \"force\" argument to override",
"code" : 10107,
"codeName" : "NotMaster",
"$clusterTime" : {
"clusterTime" : Timestamp(1705368470, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
#添加force,强制执行
mongos:OTHER> rs.reconfig(cfg,{force:true})
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1705368470, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1705368470, 1)
}
成功后,副本集就又可以正常使用了。