MongoDB复制集如何防止在辅助节点上执行查询

38

为设置副本集,我在三个不同的终端选项卡中分别运行了以下命令:

 $ sudo mongod --replSet rs0 --dbpath /data/mining --port 27017
 $ sudo mongod --replSet rs0 --dbpath /data/mining2 --port 27018
 $ sudo mongod --replSet rs0 --dbpath /data/mining3 --port 27019

然后,在Mongo shell中配置了复制,并验证它是否正常工作:

 > var rsconf = {
     _id: "rs0",
     members: [
       {
         _id: 0,
         host: 'localhost:27017'
       },
       {
         _id: 1,
         host: 'localhost:27018'
       },
       {
         _id: 2,
         host: 'localhost:27019'
       }
     ]
   };
 > rs.initiate(rsconf);
{
  "info": "Config now saved locally.  Should come online in about a minute.",
  "ok": 1
}
// Some time later...
 > rs.status()
{
  "set": "rs0",
  "date": ISODate("2013-06-17T13:23:45-0400"),
  "myState": 2,
  "syncingTo": "localhost:27017",
  "members": [
    {
      "_id": 0,
      "name": "localhost:27017",
      "health": 1,
      "state": 1,
      "stateStr": "PRIMARY",
      "uptime": 4582,
      "optime": {
        "t": 1371489546,
        "i": 1
      },
      "optimeDate": ISODate("2013-06-17T13:19:06-0400"),
      "lastHeartbeat": ISODate("2013-06-17T13:23:44-0400"),
      "lastHeartbeatRecv": ISODate("2013-06-17T13:23:44-0400"),
      "pingMs": 0
    },
    {
      "_id": 1,
      "name": "localhost:27018",
      "health": 1,
      "state": 2,
      "stateStr": "SECONDARY",
      "uptime": 5034,
      "optime": {
        "t": 1371489546,
        "i": 1
      },
      "optimeDate": ISODate("2013-06-17T13:19:06-0400"),
      "self": true
    },
    {
      "_id": 2,
      "name": "localhost:27019",
      "health": 1,
      "state": 2,
      "stateStr": "SECONDARY",
      "uptime": 4582,
      "optime": {
        "t": 1371489546,
        "i": 1
      },
      "optimeDate": ISODate("2013-06-17T13:19:06-0400"),
      "lastHeartbeat": ISODate("2013-06-17T13:23:44-0400"),
      "lastHeartbeatRecv": ISODate("2013-06-17T13:23:45-0400"),
      "pingMs": 0,
      "syncingTo": "localhost:27017"
    }
  ],
  "ok": 1
}

我的脚本在主服务器上运行良好:

 $ ./runScripts.sh -h localhost -p 27017
MongoDB shell version: 2.4.3
connecting to: localhost:27017/test
Successful completion

但是,无论对于哪种次要方面:

 $ ./runScripts.sh -h localhost -p 27018
MongoDB shell version: 2.4.3
connecting to: localhost:27017/test
Mon Jun 17 13:30:22.989 JavaScript execution failed: count failed: 
{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" } 
at src/mongo/shell/query.js:L180
failed to load: /.../.../myAggregateScript.js

我在多个地方读到应该使用rs.slaveOk()或者db.getMongo().setSlaveOk(),但是无论是在shell中还是在我的脚本中调用这些语句都没有生效。虽然这些语句被调用时没有抛出错误,但是它们也没有解决问题。

有人知道为什么我不能配置我的副本集以允许查询次要节点吗?


1
rs.slaveOk() 应该允许您进行读取。我刚在mongo shell和2.4.3上进行了测试,count()对我有效。您能分享一下您的脚本吗? - James Wahlin
@JamesWahlin 是正确的 - 唯一可能发生这种情况的方式是在运行产生此输出的命令之前未设置 rs.slaveOk()。提供有关您js脚本内容的更多信息可能会有所帮助。 - Asya Kamsky
3个回答

84

rs.slaveOk() 在Mongo shell中运行可以让你从secondary节点读取数据。以下是在MongoDB 2.4.3下使用mongo shell进行演示的示例:

$ mongo --port 27017
MongoDB shell version: 2.4.3
connecting to: 127.0.0.1:27017/test
replset:PRIMARY> db.foo.save({})
replset:PRIMARY> db.foo.find()
{ "_id" : ObjectId("51bf5dbd473d5e80fc095b17") }
replset:PRIMARY> exit

$ mongo --port 27018
MongoDB shell version: 2.4.3
connecting to: 127.0.0.1:27018/test
replset:SECONDARY> db.foo.find()
error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
replset:SECONDARY> rs.slaveOk()
replset:SECONDARY> db.foo.find()
{ "_id" : ObjectId("51bf5dbd473d5e80fc095b17") }
replset:SECONDARY> db.foo.count()
1

3
slaveOK参数存在有其原因,值得指出这些原因。例如:重要提示在指定读取偏好时应该小心:除主节点外的其他模式可能会返回过期数据,因为在异步复制中,从节点上的数据可能不反映最新的写操作。 - Madbreaks
我之前连接的是27017,那是我的主服务器... 重启后,我不得不重新构建这个愚蠢的东西,我的新主服务器是27018。上面的帖子帮了我很多。 - Andy
5
仅供参考:rs.slaveOk() 是一个每个连接的设置。每个连接在尝试与数据库交互之前都必须发出此命令。 - Daniel F

21

您需要在从服务器的 shell 中运行命令 rs.slaveOk()


0
使用以下内容在 MongoDB 次要节点上运行查询:
db.getMongo().setReadPref('secondary') 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接