如何在没有 mongodump/mongorestore 的情况下以最少的停机时间从 MMAPv1 迁移到 WiredTiger
How to migrate from MMAPv1 to WiredTiger with minimal downtime without mongodump/mongorestore
大多数指南建议使用 mongodump/mongorestore,但对于大型产品数据库,停机时间可能会很长
如果负载允许,您可以为此服务器或同一服务器使用复制和附加服务器。
您需要3个运行宁MongoDB实例:
- 您要更新的服务器(提醒 WiredTiger 从 3.0 开始支持)。
- MongoDB 的第二个实例,可以是 运行 在另一台服务器上。数据库将通过复制临时复制到它。
- 而MongoDB的第三个实例是arbiter,不存储数据,只参与主服务器的选举。仲裁器可以 运行 在单独端口上的附加服务器上。
无论如何你需要备份你的数据库。您可以 运行 “mongodump” 不带参数和目录 “./dump” 将与数据库一起创建倾倒。您可以使用“--gzip”参数来压缩结果大小。
mongodump --gzip
以防万一,恢复命令:
mongorestore --gzip
应该是运行在“./dump”目录和“--gzip”所在的同一目录如果在“mongodump”中使用,则应添加参数。
从附加服务器开始配置。我的目标系统是没有互联网的 Linux RedHat,所以我通过 RPM 手动下载并安装 MongoDB。将部分添加到 /etc/mongod.conf:
replication:
oplogSizeMB: 10240
replSetName: REPLICA
检查网络部分是否像这样以允许从其他服务器访问:
net:
bindIp: 0.0.0.0
port: 27017
和运行:
service mongod start
运行 第三个 MongoDB 实例 - 仲裁者。它可以在不同端口上的附加服务器上工作。为仲裁数据库创建一个临时目录:
mkdir /tmp/mongo
chmod 777 -R /tmp/mongo
和运行:
mongod --dbpath /tmp/mongo --port 27001 --replSet REPLICA \
--fork --logpath /tmp/mongo/db1.log
现在配置主服务器。编辑 /etc/mongod.conf
replication:
oplogSizeMB: 10240
replSetName: REPLICA
并在主服务器上重新启动 MongoDB:
service mongod restart
很重要!重新启动主服务器后,读取操作可能不可用。我收到以下错误:
{ "ok" : 0, "errmsg" : "node is recovering", "code" : 13436 }
因此,您需要尽快通过“mongo”控制台和 运行 连接到主服务器上的 MongoDB以下命令配置复制:
rs.initiate(
{
_id: "REPLICA",
members: [
{ _id: 0, host : "<IP address of main server>:27017",
priority: 1.0 },
{ _id: 1, host : "<IP address of additional server>:27017",
priority: 0.5 },
{ _id: 2, host : "<IP address of additional server(the arbiter)>:27001",
arbiterOnly : true, priority: 0.5 }
]
}
)
执行此操作后,MongoDB 的所有操作都将可用,并开始数据同步。
我不建议像大多数教程一样在主服务器上使用 rs.initiate(),因为主服务器的名称将由默认为 /etc/hostname 中的 DNS-name。这对我来说不是很方便,因为我在项目中使用 IP-addresses 进行通信。
要检查同步进度,您可以从“mongo”控制台调用:
rs.status()
结果示例:
{
"set" : "REPLICA",
"date" : ISODate("2017-01-19T14:30:34.292Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "<IP address of main server>:27017",
"health" : 1.0,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 165,
"optime" : {
"ts" : Timestamp(6377323060650835, 3),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-01-19T14:30:33.000Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(6377322974751490, 1),
"electionDate" : ISODate("2017-01-19T14:30:13.000Z"),
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "<IP address of additional server>:27017",
"health" : 1.0,
"state" : 5,
"stateStr" : "STARTUP2",
"uptime" : 30,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00.000Z"),
"lastHeartbeat" : ISODate("2017-01-19T14:30:33.892Z"),
"lastHeartbeatRecv" : ISODate("2017-01-19T14:30:34.168Z"),
"pingMs" : NumberLong(3),
"syncingTo" : "<IP address of main server>:27017",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "<IP address of additional server (the arbiter)>:27001",
"health" : 1.0,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 30,
"lastHeartbeat" : ISODate("2017-01-19T14:30:33.841Z"),
"lastHeartbeatRecv" : ISODate("2017-01-19T14:30:30.158Z"),
"pingMs" : NumberLong(0),
"configVersion" : 1
}
],
"ok" : 1.0
}
附加服务器的“stateStr”之后将从“STARTUP2”替换为“SECONDARY”,我们的服务器同步了。
在我们等待同步结束的过程中,有必要稍微修改客户端应用程序,使其可以与副本中的所有服务器一起工作。
如果您使用 ConnectionString,则应将其替换为:
mongodb://<IP address of main server>:27017,<IP address of additional server>:27017,<IP address of additional server (the arbiter)>:27001/?replicaSet=REPLICA
如果你像我一样使用 C++ mongo-cxx-driver legacy,你应该使用 mongo::DBClientReplicaSet 而不是 mongo::DBClientConnection 并在连接参数中列出所有三个服务器,包括仲裁器。
还有第三种选择——你可以简单地在客户端切换PRIMARY-SECONDARY后更改MongoDB服务器的IP ,但不太公平
在同步结束并且附加服务器状态建立为SECONDARY后,我们需要切换PRIMARY 和 SECONDARY 通过在主服务器上的“mongo”控制台中执行命令。这很重要,因为命令将无法在其他服务器上运行。
cfg = rs.conf()
cfg.members[0].priority = 0.5
cfg.members[1].priority = 1
cfg.members[2].priority = 0.5
rs.reconfig(cfg)
然后通过执行检查服务器状态:
rs.status()
停止主服务器上的MongoDB
service mongod stop
并简单地删除包含数据库的目录的全部内容。这是安全的,因为我们在附加服务器上有一个工作副本,并且一开始我们已经做了备份。当心。 MongoDB 不创建数据库目录本身。如果你删除了它,你不仅需要恢复
mkdir /var/lib/mongo
和设置所有者:
chown -R mongod:mongod /var/lib/mongo
检查存储引擎wiredTiger是否配置在/etc/mongod.conf中。从 3.2 开始默认使用:
storage:
...
engine: wiredTiger
...
和运行 MongoDB:
service mongod start
主服务器会自动从副服务器获取配置数据同步回WiredTiger sto年龄.
同步完成后切换回PRIMARY服务器。此操作应在其他服务器上执行,因为它现在是 PRIMARY。
cfg = rs.conf()
cfg.members[0].priority = 1
cfg.members[1].priority = 0.5
cfg.members[2].priority = 0.5
rs.reconfig(cfg)
Return旧版本的数据库客户端或者改ConnectionString回来。
如果需要,现在关闭复制。从主服务器中删除 2 个复制服务器:
rs.remove("<IP address of additional server>:27017")
rs.remove("<IP address of additional server (the arbiter)>:27001")
从 /etc/mongod.conf 中删除所有“replication”部分并重新启动 MongoDB:
service mongod restart
在这些之后,我们在通过“mongo”控制台连接时收到警告:
2017-01-19T12:26:51.948+0300 I STORAGE [initandlisten] ** WARNING: mongod started without --replSet yet 1 documents are present in local.system.replset
2017-01-19T12:26:51.948+0300 I STORAGE [initandlisten] ** Restart with --replSet unless you are doing maintenance and no other clients are connected.
2017-01-19T12:26:51.948+0300 I STORAGE [initandlisten] ** The TTL collection monitor will not start because of this.
要摆脱它,您需要删除数据库“local”。这个数据库默认状态下只有一个集合“startup_log”,所以你可以放心地通过“mongo”控制台
use local
db.dropDatabase()
并重启 MongoDB:
service mongod restart
如果您要从 /etc/mongod 中删除“replication”部分之前的“local”数据库.conf,立即恢复。所以我不能只做一次 MongoDB 重启。
在附加服务器上执行相同的操作:
- 从 /etc/mongod.conf
中删除“replication”部分
- 重启MongoDB
- 删除“本地“数据库
- 再次重启
仲裁程序停止并删除:
pkill -f /tmp/mongo
rm -r /tmp/mongo
大多数指南建议使用 mongodump/mongorestore,但对于大型产品数据库,停机时间可能会很长
如果负载允许,您可以为此服务器或同一服务器使用复制和附加服务器。
您需要3个运行宁MongoDB实例:
- 您要更新的服务器(提醒 WiredTiger 从 3.0 开始支持)。
- MongoDB 的第二个实例,可以是 运行 在另一台服务器上。数据库将通过复制临时复制到它。
- 而MongoDB的第三个实例是arbiter,不存储数据,只参与主服务器的选举。仲裁器可以 运行 在单独端口上的附加服务器上。
无论如何你需要备份你的数据库。您可以 运行 “mongodump” 不带参数和目录 “./dump” 将与数据库一起创建倾倒。您可以使用“--gzip”参数来压缩结果大小。
mongodump --gzip
以防万一,恢复命令:
mongorestore --gzip
应该是运行在“./dump”目录和“--gzip”所在的同一目录如果在“mongodump”中使用,则应添加参数。
从附加服务器开始配置。我的目标系统是没有互联网的 Linux RedHat,所以我通过 RPM 手动下载并安装 MongoDB。将部分添加到 /etc/mongod.conf:
replication: oplogSizeMB: 10240 replSetName: REPLICA
检查网络部分是否像这样以允许从其他服务器访问:
net: bindIp: 0.0.0.0 port: 27017
和运行:
service mongod start
运行 第三个 MongoDB 实例 - 仲裁者。它可以在不同端口上的附加服务器上工作。为仲裁数据库创建一个临时目录:
mkdir /tmp/mongo chmod 777 -R /tmp/mongo
和运行:
mongod --dbpath /tmp/mongo --port 27001 --replSet REPLICA \ --fork --logpath /tmp/mongo/db1.log
现在配置主服务器。编辑 /etc/mongod.conf
replication: oplogSizeMB: 10240 replSetName: REPLICA
并在主服务器上重新启动 MongoDB:
service mongod restart
很重要!重新启动主服务器后,读取操作可能不可用。我收到以下错误:
{ "ok" : 0, "errmsg" : "node is recovering", "code" : 13436 }
因此,您需要尽快通过“mongo”控制台和 运行 连接到主服务器上的 MongoDB以下命令配置复制:
rs.initiate( { _id: "REPLICA", members: [ { _id: 0, host : "<IP address of main server>:27017", priority: 1.0 }, { _id: 1, host : "<IP address of additional server>:27017", priority: 0.5 }, { _id: 2, host : "<IP address of additional server(the arbiter)>:27001", arbiterOnly : true, priority: 0.5 } ] } )
执行此操作后,MongoDB 的所有操作都将可用,并开始数据同步。
我不建议像大多数教程一样在主服务器上使用 rs.initiate(),因为主服务器的名称将由默认为 /etc/hostname 中的 DNS-name。这对我来说不是很方便,因为我在项目中使用 IP-addresses 进行通信。
要检查同步进度,您可以从“mongo”控制台调用:
rs.status()
结果示例:
{ "set" : "REPLICA", "date" : ISODate("2017-01-19T14:30:34.292Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "members" : [ { "_id" : 0, "name" : "<IP address of main server>:27017", "health" : 1.0, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 165, "optime" : { "ts" : Timestamp(6377323060650835, 3), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-01-19T14:30:33.000Z"), "infoMessage" : "could not find member to sync from", "electionTime" : Timestamp(6377322974751490, 1), "electionDate" : ISODate("2017-01-19T14:30:13.000Z"), "configVersion" : 1, "self" : true }, { "_id" : 1, "name" : "<IP address of additional server>:27017", "health" : 1.0, "state" : 5, "stateStr" : "STARTUP2", "uptime" : 30, "optime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDate" : ISODate("1970-01-01T00:00:00.000Z"), "lastHeartbeat" : ISODate("2017-01-19T14:30:33.892Z"), "lastHeartbeatRecv" : ISODate("2017-01-19T14:30:34.168Z"), "pingMs" : NumberLong(3), "syncingTo" : "<IP address of main server>:27017", "configVersion" : 1 }, { "_id" : 2, "name" : "<IP address of additional server (the arbiter)>:27001", "health" : 1.0, "state" : 7, "stateStr" : "ARBITER", "uptime" : 30, "lastHeartbeat" : ISODate("2017-01-19T14:30:33.841Z"), "lastHeartbeatRecv" : ISODate("2017-01-19T14:30:30.158Z"), "pingMs" : NumberLong(0), "configVersion" : 1 } ], "ok" : 1.0 }
附加服务器的“stateStr”之后将从“STARTUP2”替换为“SECONDARY”,我们的服务器同步了。
在我们等待同步结束的过程中,有必要稍微修改客户端应用程序,使其可以与副本中的所有服务器一起工作。
如果您使用 ConnectionString,则应将其替换为:
mongodb://<IP address of main server>:27017,<IP address of additional server>:27017,<IP address of additional server (the arbiter)>:27001/?replicaSet=REPLICA
如果你像我一样使用 C++ mongo-cxx-driver legacy,你应该使用 mongo::DBClientReplicaSet 而不是 mongo::DBClientConnection 并在连接参数中列出所有三个服务器,包括仲裁器。
还有第三种选择——你可以简单地在客户端切换PRIMARY-SECONDARY后更改MongoDB服务器的IP ,但不太公平
在同步结束并且附加服务器状态建立为SECONDARY后,我们需要切换PRIMARY 和 SECONDARY 通过在主服务器上的“mongo”控制台中执行命令。这很重要,因为命令将无法在其他服务器上运行。
cfg = rs.conf() cfg.members[0].priority = 0.5 cfg.members[1].priority = 1 cfg.members[2].priority = 0.5 rs.reconfig(cfg)
然后通过执行检查服务器状态:
rs.status()
停止主服务器上的MongoDB
service mongod stop
并简单地删除包含数据库的目录的全部内容。这是安全的,因为我们在附加服务器上有一个工作副本,并且一开始我们已经做了备份。当心。 MongoDB 不创建数据库目录本身。如果你删除了它,你不仅需要恢复
mkdir /var/lib/mongo
和设置所有者:
chown -R mongod:mongod /var/lib/mongo
检查存储引擎wiredTiger是否配置在/etc/mongod.conf中。从 3.2 开始默认使用:
storage: ... engine: wiredTiger ...
和运行 MongoDB:
service mongod start
主服务器会自动从副服务器获取配置数据同步回WiredTiger sto年龄.
同步完成后切换回PRIMARY服务器。此操作应在其他服务器上执行,因为它现在是 PRIMARY。
cfg = rs.conf() cfg.members[0].priority = 1 cfg.members[1].priority = 0.5 cfg.members[2].priority = 0.5 rs.reconfig(cfg)
Return旧版本的数据库客户端或者改ConnectionString回来。
如果需要,现在关闭复制。从主服务器中删除 2 个复制服务器:
rs.remove("<IP address of additional server>:27017") rs.remove("<IP address of additional server (the arbiter)>:27001")
从 /etc/mongod.conf 中删除所有“replication”部分并重新启动 MongoDB:
service mongod restart
在这些之后,我们在通过“mongo”控制台连接时收到警告:
2017-01-19T12:26:51.948+0300 I STORAGE [initandlisten] ** WARNING: mongod started without --replSet yet 1 documents are present in local.system.replset 2017-01-19T12:26:51.948+0300 I STORAGE [initandlisten] ** Restart with --replSet unless you are doing maintenance and no other clients are connected. 2017-01-19T12:26:51.948+0300 I STORAGE [initandlisten] ** The TTL collection monitor will not start because of this.
要摆脱它,您需要删除数据库“local”。这个数据库默认状态下只有一个集合“startup_log”,所以你可以放心地通过“mongo”控制台
use local db.dropDatabase()
并重启 MongoDB:
service mongod restart
如果您要从 /etc/mongod 中删除“replication”部分之前的“local”数据库.conf,立即恢复。所以我不能只做一次 MongoDB 重启。
在附加服务器上执行相同的操作:
- 从 /etc/mongod.conf 中删除“replication”部分
- 重启MongoDB
- 删除“本地“数据库
- 再次重启
仲裁程序停止并删除:
pkill -f /tmp/mongo rm -r /tmp/mongo