如何设置PHP MongoDB自动故障转移

时间:2015-04-08 15:18:39

标签: php linux mongodb failover

当我的复制集的主服务器出现故障时,当前打开的连接也会立即失败(!)抛出MongoConnectionExceptionNo candidate servers found)或MongoCursorExceptionmongoUbuntu:8004: Remote server has closed the connection)我使用GridFS。 这是一个错误还是我必须更改我的设置才能实现自动故障转移?

安装

  • Linux ubuntu内核3.16.0-31-generic
  • PHP 5.5.12-2ubuntu4.3
  • pecl / mongo 1.6.6
  • mongo 2.6.3
  • PHP via cli
  • 服务器的主机名为mongoUbuntu,使用以下命令行在一台计算机上启动mongodb进程

Mongod选项

我在端口8001,8002,8003和8004上运行4个服务器,在8010上运行一个仲裁器.8001的命令行如下:

mongod --replSet rs1 --dbpath /var/lib/mongodb1 --port 8001 --smallfiles --oplogSize 200 --httpinterface --rest

复制集rs.status()

{            
"set" : "rs1",            
"date" : ISODate("2015-04-08T14:48:57Z"),            
"myState" : 3,            
"members" : [            
    {            
        "_id" : 0,            
        "name" : "mongoUbuntu:8004",            
        "health" : 1,            
        "state" : 2,            
        "stateStr" : "SECONDARY",            
        "uptime" : 467,            
        "optime" : Timestamp(1428501340, 1),            
        "optimeDate" : ISODate("2015-04-08T13:55:40Z"),            
        "lastHeartbeat" : ISODate("2015-04-08T14:48:56Z"),            
        "lastHeartbeatRecv" : ISODate("2015-04-08T14:48:55Z"),            
        "pingMs" : 0,            
        "syncingTo" : "mongoUbuntu:8001"            
    },            
    {            
        "_id" : 1,            
        "name" : "mongoUbuntu:8003",            
        "health" : 1,            
        "state" : 2,            
        "stateStr" : "SECONDARY",            
        "uptime" : 987,            
        "optime" : Timestamp(1428501340, 1),            
        "optimeDate" : ISODate("2015-04-08T13:55:40Z"),            
        "lastHeartbeat" : ISODate("2015-04-08T14:48:56Z"),            
        "lastHeartbeatRecv" : ISODate("2015-04-08T14:48:56Z"),            
        "pingMs" : 0,            
        "syncingTo" : "mongoUbuntu:8001"            
    },            
    {            
        "_id" : 2,            
        "name" : "mongoUbuntu:8002",            
        "health" : 1,            
        "state" : 3,            
        "stateStr" : "RECOVERING",            
        "uptime" : 3142,            
        "optime" : Timestamp(1428498901, 1),            
        "optimeDate" : ISODate("2015-04-08T13:15:01Z"),            
        "infoMessage" : "still syncing, not yet to minValid optime 55252e9b:37",            
        "self" : true            
    },            
    {            
        "_id" : 3,            
        "name" : "mongoUbuntu:8001",            
        "health" : 1,            
        "state" : 1,            
        "stateStr" : "PRIMARY",            
        "uptime" : 3139,            
        "optime" : Timestamp(1428501340, 1),            
        "optimeDate" : ISODate("2015-04-08T13:55:40Z"),            
        "lastHeartbeat" : ISODate("2015-04-08T14:48:56Z"),            
        "lastHeartbeatRecv" : ISODate("2015-04-08T14:48:56Z"),            
        "pingMs" : 0,            
        "electionTime" : Timestamp(1428503596, 1),            
        "electionDate" : ISODate("2015-04-08T14:33:16Z")            
    },            
    {            
        "_id" : 4,            
        "name" : "mongoUbuntu:8010",            
        "health" : 1,            
        "state" : 7,            
        "stateStr" : "ARBITER",            
        "uptime" : 3139,            
        "lastHeartbeat" : ISODate("2015-04-08T14:48:56Z"),            
        "lastHeartbeatRecv" : ISODate("2015-04-08T14:48:55Z"),            
        "pingMs" : 0            
    }            
],            
"ok" : 1            
}            

PHP脚本

当我终止当前主节点时,正在运行以下脚本(没有实际使用GridFS但直接执行查询的示例。)

<?php
$conn   = new \MongoClient(
    'mongodb://mongoUbuntu:8001,mongoUbuntu:8002,mongoUbuntu:8003',
    array('replicaSet' => 'rs1', 'readPreference' => \MongoClient::RP_PRIMARY_PREFERRED)
);

$db     = $conn->bat; //db name: bat
$gridfs = $this->_db->getGridFS();

while(true) {
    $documents  = $db->execute('db.getCollection(\'fs.files\').count()');

    echo $documents['retval']."\n";
    sleep(1);
}

问题

在我终止当前主节点之前,脚本正在将文档计数打印到命令行。当我终止当前主要(在respectiv mongod命令行上按Ctrl + C)时,php脚本立即因为异常,在这种情况下MongoConnectionException No candidate servers found

我使用github脚本创建full debug log,并将其保存为Gist mongo-php-log-automaticfailover-fails

我是否必须为创建连接或复制集的配置添加其他选项?如果在mongodb文档或mongodb php驱动程序的文档中对此进行了描述,我在哪里可以找到它?

1 个答案:

答案 0 :(得分:1)

是的,驱动程序确实抛出异常。从技术上讲,这是正确的做法,特别是如果你想知道集合何时故障转移。您需要做的是捕获异常并重试。

你最大的问题是,由于某种原因,你正在评估。 Eval只需要在主服务器上运行,因此当一个服务器故障转移时,它必须等待一个可能需要10秒钟的当选主服务器。

然而,似乎eval的这个方面实际上没有记录,尽管它被认可:https://dba.stackexchange.com/questions/75852/mongodb-replicaset-reconfig-when-primary-and-majority-dont-exist因为该问题的回答者实际上是10gen(MongoDB Inc)并且他似乎并不否认eval没有从事辅助工作。我很确定这曾经是在文档中,这是我第一次看到它。

在Python的MongoDB 101课程中对此进行了很好的解释。这同样适用于大多数语言。我个人只是禁止连接,直到找到一个新的主要(但后来我没有eval的东西),但如果你只是阅读你可以删除eval并通过PHP执行此操作。这应该让你无阻碍地阅读。