根因分析
原因一: mongodb配置的地址和php里使用的地址不一致
- mongodb server配置为机器名而php里使用的链接地址是ip
- mongodb server配置为ip而php里使用的链接地址是机器名
扩展C相关代码
//connections.c>mongo_discover_topology>mongo_connection_ismaster
if (bson_find_field_as_string(ptr, "me", &connected_name)) {
we_think_we_are = mongo_server_hash_to_server(con->hash);
if (strcmp(connected_name, we_think_we_are) == 0) {
mongo_manager_log(manager, MLOG_CON, MLOG_FINE, "ismaster: the server name matches what we thought it'd be (%s).", we_think_we_are);
} else {
mongo_manager_log(manager, MLOG_CON, MLOG_WARN, "ismaster: the server name (%s) did not match with what we thought it'd be (%s).", connected_name, we_think_we_are);
/* We reset the name as the server responded with a different name than
* what we thought it was */
free(server->host);
server->host = mcon_strndup(connected_name, strchr(connected_name, ':') - connected_name);
server->port = atoi(strchr(connected_name, ':') + 1);
retval = 3;
}
原因二: 建立链接时发现缓存连接不可用
$mongo = new MongoClient("mongodb://127.0.0.1:27018",
array(
'replicaSet' => 'rs0',
'connect' => true,
'connectTimeoutMS' => 10000
)); \\这里会报No candidate servers found错误
原因三: 创建链接指定connect为false, 在查询或者修改删除时发现连接不可用
$mongo = new MongoClient("mongodb://127.0.0.1:27018",
array(
'replicaSet' => 'rs0',
'connect' => false,
'connectTimeoutMS' => 10000
));
$collection = $mongo->test->test;
$cusor = $collection->find()->limit(5);
foreach($cusor as $doc) { \\这里会报No candidate servers found错误
echo getmypid() .json_encode($doc) . "\n";
}
问题出现场景
- mongodb服务器挂掉
- mongodb主挂掉,选举期间
- mongodb服务器挂掉恢复正常,第一次访问由于缓存长连接失效导致
第三种情况,如果PHP与mongodb采用的是长链接,没有主动close,那么可能会导致这个报错持续很长时间。因为每一个php-fpm进程链接之前故障服务器的缓存链接都不可用了,当第一次访问时就会发生失败,会把失效的链接释放,第二次访问会重新建立链接就OK了。
问题解决
mongo.so扩展经过测试,都会存在这个问题,有几种方式可以解决:
* php与mongodb之间建立链接,使用完成后主动调用close,即每次使用短链接。
* 如果建立链接时指定connect=true,建议增加重试机制,保证链接成功。
$retry = 2;
do {
try {
$mongo = new MongoClient("mongodb://127.0.0.1:27018",
array(
'replicaSet' => 'rs0',
'connect' => true,
'connectTimeoutMS' => 10000
));
break;
} catch(MongoException $e) {
if (0 == $retry--) {
//log
return;
}
}
} while($retry);
- 如果建立链接时指定connect=false,建议在读写mongodb时增加重试机制,参考如上代码。
- 如果您当前使用的PHP版本大于等于5.4,建议使用mongodb.so扩展,具体里面代码没有看过,但是经过实测发现该扩展已经包含了重试的机制在里面。
Be First to Comment