MongoDB 线上迁移教程

0. 迁移环境

Host A IP: 192.168.108.125

Host B IP: 192.168.108.124

下文所用 MongoDB 版本均为 2.0.7 ,操作系统为 Debian 6

1. 热身

打开两台机器的防火墙 没开防火墙的同学这部分可以不用看了

Host A (数据源) 上执行如下命令

1
iptables -A INPUT -s HostA/32 -p tcp -m tcp --dport 27017 -j ACCEPT

Host B (迁移目标) 上执行如下命令

1
iptables -A INPUT -s HostB/32 -p tcp -m tcp --dport 27017 -j ACCEPT

为了安全,我的 MongoDB 是只绑定在本地环回接口上的,打开 /etc/mongodb.conf,注释掉 bind_ip = 127.0.0.1这行。

同时,在文件末尾加上replSet = rs0以打开 Replication 功能。

/etc/mongodb.conf
1
2
3
4
5
6
7
8
9
dbpath = /db/mongo
logpath = /log/mongo/mongo.log
#bind_ip = 127.0.0.1
noauth = true
verbose = true
journal = true
noprealloc = true
smallfiles = true
replSet = 0

现在,重启 Host A 和 Host B 的 MongoDB。

2. 配置 Replication

Host A 上运行 mongo,输入以下命令

1
2
3
4
5
config = {_id: 'rs0', members: [
{_id: 0, host: '192.168.108.125:27017'},
{_id: 1, host: '192.168.108.124:27017'}
]}
rs.initiate(config)

稍等一会儿,系统会有下列提示

1
2
3
4
5
6
rs.initiate(config)
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}
PRIMARY>

打开 Host Bmongo,我们可以看到有如下的提示

1
2
3
4
MongoDB shell version: 2.0.7
connecting to: test
>
RECOVERING>

输入 rs.status() 查看恢复状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
RECOVERING> rs.status()
{
"set" : "rs0",
"date" : ISODate("2012-08-24T16:03:05Z"),
"myState" : 3,
"syncingTo" : "192.168.108.125:27017",
"members" : [
{
"_id" : 0,
"name" : "192.168.108.125:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 220,
"optime" : {
"t" : 1345824182000,
"i" : 6
},
"optimeDate" : ISODate("2012-08-24T16:03:02Z"),
"lastHeartbeat" : ISODate("2012-08-24T16:03:05Z"),
"pingMs" : 29
},
{
"_id" : 1,
"name" : "192.168.108.124:27017",
"health" : 1,
"state" : 3,
"stateStr" : "RECOVERING",
"optime" : {
"t" : 0,
"i" : 0
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"self" : true
}
],
"ok" : 1
}

依照数据量的大小可能需要传输一阵子,利用这个空闲我们把 Host A 上的网络服务迁移到 Host B

3. 迁移关联服务

在 MongoDB 中,从 Slave 上执行查询需要在查询前先执行 db.getMongo().setSlaveOk(),否则会出现这样的提示:

RECOVERING> db.tasks.find();
error: { "$err" : "not master and slaveok=false", "code" : 13435 }

如果你的程序木有注意这一点,那么…赶紧给我改代码去!!!快去!!!

现在我们的 Web 应用程序已经复制到了 Host B 的硬盘里,并已经可以提供服务。

打开 Host Anginx 的配置文件,在这里是 /etc/nginx/nginx.conf

将原有 server 部分均删除并替换为如下内容:

1
2
3
4
5
6
7
8
9
upstream hostb {
server 192.168.108.124:80;
}

server {
proxy_pass http://localhost:8000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
}

执行命令 /usr/local/nginx/sbin/nginx -s reload 重新载入 nginx 配置。

4. 移除 Replication

在 MongoDB 完成复制后, Host B 的提示符会变成:

1
2
3
4
MongoDB shell version: 2.0.7
connecting to: test
>
SECONDARY>

这时候我们将 Host B 变更为 Primary, 在 Host A 上执行如下命令:

1
2
3
4
cfg = rs.conf()
cfg.members[0].priority = 10
cfg.members[1].priority = 20
rs.reconfig(cfg)

稍等一会儿, Host A 就会变更为 Secondary

rs.reconfig(cfg)
1
2
3
4
5
6
7
8
9
10
11
12
13
Sat Aug 25 00:18:49 DBClientCursor::init call() failed
Sat Aug 25 00:18:49 query failed : admin.$cmd { replSetReconfig: { _id: "rs0", version: 2, members: [ { _id: 0, host: "192.168.108.125:27017", priority: 10.0 }, { _id: 1, host: "192.168.108.124:27017", priority: 20.0 } ] } } to: 127.0.0.1
Sat Aug 25 00:18:49 trying reconnect to 127.0.0.1
Sat Aug 25 00:18:49 reconnect 127.0.0.1 ok
reconnected to server after rs command (which is normal)
PRIMARY>
Sat Aug 25 00:18:59 Socket recv() errno:104 Connection reset by peer 127.0.0.1:27017
Sat Aug 25 00:18:59 SocketException: remote: 127.0.0.1:27017 error: 9001 socket exception [1] server [127.0.0.1:27017]
Sat Aug 25 00:18:59 DBClientCursor::init call() failed
>
Sat Aug 25 00:19:00 trying reconnect to 127.0.0.1
Sat Aug 25 00:19:00 reconnect 127.0.0.1 ok
SECONDARY>

现在我们可以关掉 Host AMongoDB

打开 Host B/etc/mongodb.conf ,去除 Host B 设置中的 replSet = rs0

/etc/mongodb.conf
1
2
3
4
5
6
7
8
9
dbpath = /db/mongo
logpath = /log/mongo/mongo.log
bind_ip = 127.0.0.1
noauth = true
verbose = true
journal = true
noprealloc = true
smallfiles = true
#replSet = 0

重启 MongoDB,至此,本次迁移已经完成,等待 DNS解析生效 后,就可以把 Host A 下架了。