【问题标题】:How to setup PHP MongoDB automatic failover如何设置 PHP MongoDB 自动故障转移
【发布时间】:2015-06-13 15:38:46
【问题描述】:

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

安装

  • Linux ubuntu 内核 3.16.0-31-generic
  • PHP 5.5.12-2ubuntu4.3
  • pecl/mongo 1.6.6
  • mongo 2.6.3
  • PHP 通过 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);
}

问题

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

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

我是否必须添加另一个选项来创建连接或复制集的配置?如果在 mongodb 文档或 mongodb php 驱动程序文档中有描述,我在哪里可以找到它?

【问题讨论】:

    标签: php linux mongodb failover


    【解决方案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 课程中得到了很好的解释。这同样适用于大多数语言。我个人只是禁止连接,直到找到新的主节点(但我不评估东西),但如果您只是阅读,您可以删除评估并通过 PHP 执行此操作。这应该可以让您毫无障碍地阅读。

    【讨论】:

    • 我希望驱动程序在自动故障转移期间在达到超时时抛出异常,这个假设是完全错误的。谢谢你的解释。但是你能告诉我你用eval是什么意思吗,你是说调用$db-&gt;execute('')吗,如果没有可用的主数据库,这样的查询总是会失败?
    • @Theoboldt execute 实际上是 eval 的包装器,所以是的
    • 此外: 使用 eval 的调用会导致 global write lock(默认情况下),因此它们的行为总是像写访问,这是我们都知道的唯一可能在小学。
    • @Theoboldt 您可以使用 nolock 标志,但我相信 eval 默认情况下被分配为主要功能
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-14
    • 2015-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多