Пожалуйста, может кто-нибудь помочь с этой проблемой. Спасибо.
Приведенный ниже PHP-скрипт вызывает следующую ошибку при попытке выполнить строку массовой записи.
[russell@hawk mongo]$ cat error_log
[29-Apr-2023 05:04:22 UTC] PHP Fatal error: Uncaught MongoDB\Driver\Exception\ConnectionTimeoutException: No suitable servers found (`serverSelectionTryOnce` set): [connection closed calling ismaster on 'cluster0-shard-00-00.tx3cl.mongodb.net:27017'] [connection closed calling ismaster on 'cluster0-shard-00-01.tx3cl.mongodb.net:27017'] [connection closed calling ismaster on 'cluster0-shard-00-02.tx3cl.mongodb.net:27017'] in /home/mongo/2_test_mongo.php:13
Stack trace:
#0 /home/mongo/2_test_mongo.php(13): MongoDB\Driver\Manager->executeBulkWrite()
#1 {main}
thrown in /home/mongo/2_test_mongo.php on line 13
Интересно, что ошибка показывает номер порта. Также интересно, что строка подключения, напечатанная обратно в консоль, не имеет +srv.
Но вам не разрешено включать номер порта с типом подключения mongo+srv
. Я не указываю номер порта.
В Compass на ноутбуке я получаю эту ошибку при удалении +srv
getaddrinfo ENOTFOUND cluster0.tx3cl.mongodb.net
а также, если я добавляю номер порта 27017, чтобы компенсировать отсутствие +srv, я получаю ту же ошибку.
Есть ли что-то, что я должен сделать, чтобы переопределить добавленный порт по умолчанию? Технические детали
[prompt]$ php --version
PHP 8.0.18 (cli) (built: Apr 13 2022 10:54:57) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.18, Copyright (c) Zend Technologies
[prompt]$ uname -a
Linux blah.blah.net 3.10.0-962.3.2.lve1.5.67.el7.x86_64 #1 SMP Fri Mar 25 07:13:21 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
[prompt]$
Вывод скрипта на консоль следующий
[prompt]$ php script.php
loaded
MongoDB\Driver\Manager Object
(
[uri] => mongodb://user:[email protected]/?retryWrites=true&w=majority
[cluster] => Array
(
)
)
Сам скрипт есть
<?php
use MongoDB\Client;
use MongoDB\Driver\ServerApi;
echo extension_loaded("mongodb") ? "loaded\n" : "not loaded\n";
$uri = 'mongodb+srv://user:[email protected]/?retryWrites=true&w=majority';
$manager = new MongoDB\Driver\Manager($uri);
print_r($manager);
$bulk = new MongoDB\Driver\BulkWrite();
$bulk->insert(['x' => 1]);
$bulk->insert(['x' => 2]);
$bulk->insert(['x' => 3]);
$manager->executeBulkWrite('TestyDB.TestyCollection', $bulk);
$filter = ['x' => ['$gt' => 1]];
$options = [
'projection' => ['_id' => 0],
'sort' => ['x' => -1],
];
$query = new MongoDB\Driver\Query($filter, $options);
$cursor = $manager->executeQuery('TestyDB.TestyCollection', $query);
foreach ($cursor as $document) {
var_dump($document);
}
?>
URL-адрес в строке подключения доступен для проверки связи с сервера, с которого я пытаюсь подключиться.
russell@hawk mongo]$ ping cluster0-shard-00-00.tx3cl.mongodb.net
PING ec2-52-55-183-242.compute-1.amazonaws.com (52.55.183.242) 56(84) bytes of data.
64 bytes from ec2-52-55-183-242.compute-1.amazonaws.com (52.55.183.242): icmp_seq=1 ttl=228 time=76.7 ms
64 bytes from ec2-52-55-183-242.compute-1.amazonaws.com (52.55.183.242): icmp_seq=2 ttl=228 time=76.7 ms
64 bytes from ec2-52-55-183-242.compute-1.amazonaws.com (52.55.183.242): icmp_seq=3 ttl=228 time=76.7 ms
64 bytes from ec2-52-55-183-242.compute-1.amazonaws.com (52.55.183.242): icmp_seq=4 ttl=228 time=76.7 ms
64 bytes from ec2-52-55-183-242.compute-1.amazonaws.com (52.55.183.242): icmp_seq=5 ttl=228 time=76.6 ms
Я только что изменил версию PHP с 8.0 на 7.4.
Ответ прост: скрипт работает с PHP 7.4. Намек на то, что проблема не в сети, заключается в том, что та же строка подключения работает с ноутбуком, на котором запущен компас.
Теперь вопрос в том, какой правильный синтаксис для PHP8.0 :-)
Дополнительные новости. Я связался с поддержкой моей хостинговой компании по этому поводу. Они открыл порт на 27017 и этот скрипт теперь работает с PHP 8.0 и 7.4
Я отправил вопрос на форумы монога здесь, если кому-то интересно. https://www.mongodb.com/community/forums/t/why-does-php-8-0-remove-the-srv/224252
Что помогло мне решить проблему с версиями, так это увидеть тот же код здесь: https://help.ovhcloud.com/csm/en-gb-public-cloud-databases-mongodb-connect-php?id=kb_article_view&sysparm_article= KB0049087 Они указали версию PHP, которую они использовали, и код был практически таким же, как у меня.
До этого я думал, что провел исследование для PHP 8.0 и Mongo. Вот если бы я это сделал, а это баг, то будет интересно. Не могу дождаться, чтобы увидеть, что говорят форумы монго.
Вкратце: я не вижу никаких признаков ошибки драйвера или каких-либо различий в поведении между PHP 7.4 и 8.0. Основной причиной оказалась ограничительная сетевая политика на сервере приложений PHP 8.0 (согласно вашего ответа).
Документы MongoDB PHP Library включают часто задаваемые вопросы, в которых есть раздел Ошибки выбора сервера. Чтение этого должно позволить вам понять ошибку «Подходящие серверы не найдены», но я также разберу ее здесь:
Uncaught MongoDB\Driver\Exception\ConnectionTimeoutException:
No suitable servers found (`serverSelectionTryOnce` set):
[connection closed calling ismaster on 'cluster0-shard-00-00.tx3cl.mongodb.net:27017']
[connection closed calling ismaster on 'cluster0-shard-00-01.tx3cl.mongodb.net:27017']
[connection closed calling ismaster on 'cluster0-shard-00-02.tx3cl.mongodb.net:27017']
in /path/to/script...
Драйверу не удалось выбрать какой-либо сервер для операции с базой данных, и он сообщает о самой последней ошибке при каждом подключении к серверу. Тот факт, что здесь присутствуют три сервера, говорит нам о том, что исходный mongodb+srv://
URI был успешно преобразован в начальный список из трех хостов.
Увидев «соединение закрыто» в сообщении об ошибке сокета, я предполагаю, что что-то немедленно отклонило соединение. Среди многих возможных причин этого могут быть ограничительная конфигурация сети, брандмауэр или удаленный хост, отклоняющий соединение. Что касается MongoDB Atlas, эта ошибка также распространена, если IP-адрес сервера приложений PHP не включен в Записи списка доступа IP.
В вашем ответе вы указали:
Я связался с поддержкой моей хостинговой компании по этому поводу. Они открыли порт на 27017, и этот скрипт теперь работает с PHP 8.0 и 7.4.
Если я правильно понимаю, сетевая конфигурация вашей хостинговой компании блокировала PHP от исходящих подключений к порту 27017. Это, безусловно, объяснило бы ошибку подключения и не предполагает каких-либо проблем с PHP или драйвером MongoDB.
Интересно, что ошибка показывает номер порта.
Хосты и порты, обнаруженные в ошибке выбора сервера, не имеют прямого отношения к mongodb+srv://
URI. Вы упускаете из виду, что драйвер будет запрашивать DNS и создавать начальный список, похожий на mongodb://
URI. Формат подключения DNS Seed List в документации MongoDB объясняет это более подробно.
27017
— это просто порт по умолчанию.
Но вам не разрешено включать номер порта с типом подключения mongo+srv. Я не указываю номер порта.
Вы правы, что mongodb+srv://
URI не включает порт. Порт для каждого сервера в начальном списке фактически получается из записей DNS.
Обратите внимание, что исходный список по-прежнему является лишь промежуточным источником информации и может не отражать все серверы, к которым в конечном итоге подключается драйвер. Если вам это интересно, вы можете прочитать спецификацию драйвера Обнаружение и мониторинг серверов или Обнаружение и мониторинг серверов в драйверах MongoDB следующего поколения в блоге MongoDB (это немного устарело, но его легче переварить, чем сырой спец).
Также интересно, что строка подключения, напечатанная обратно в консоль, не имеет +srv.
У меня нет объяснения этому, основанного на том, что вы поделились выше, но я также не нашел доказательств того, что драйвер сообщит что-либо, кроме исходного URI, используемого для создания диспетчера.
Обработчик get_debug_info объекта Manager заполняет поле uri
с помощью mongoc_uri_get_string() ). Эта функция в libmongoc (драйвер C, на основе которого построен драйвер PHP) возвращает ту же строку , которая использовалась для построения URI, который изначально установлен в mongoc_uri_new_with_error() . Для справки, это та же самая функция , которая используется драйвером PHP при создании объекта Manager.
Я предполагаю, что некоторая другая важная информация опущена. Например, вы упомянули, какие версии PHP использовались (7.4 и 8.0), но ни разу не упомянули версию драйвера PHP (т. е. расширения mongodb
), работающего в каждой среде. Также было неясно, где работает каждая среда PHP. Если первоначальная ошибка подключения была вызвана конфигурацией сети вашей хостинговой компании, и они использовали PHP 8.0, это не означает, что проблема в PHP 8.0 (корреляция не подразумевает причинно-следственную связь).
В Compass на ноутбуке я получаю эту ошибку при удалении +srv getaddrinfo ENOTFOUND cluster0.tx3cl.mongodb.net, а также, если я добавляю номер порта 27017, чтобы компенсировать отсутствие +srv, я получаю ту же ошибку.
Хост, используемый для mongodb+srv://
URI, не обязательно совпадает с хостом(ами), на котором запущена MongoDB. cluster0.tx3cl.mongodb.net
используется для разрешения DNS, но на основании вышеприведенного исключения ConnectionTimeoutException мы видим, что фактические серверы работают на следующих хостах:
Учитывая это, нет причин ожидать, что сервер MongoDB будет прослушивать cluster0.tx3cl.mongodb.net:27017
.
Спасибо за объяснение, однако я не согласен с вашей оценкой, что нет никаких доказательств проблемы. Разница в версиях PHP действительно имеет проблему. Поскольку версия 7.4 работала правильно, а версия 8 вызывала описанные мной проблемы. Это было легко проверить с моим хостинг-провайдером.
PHP 8.0 удалял +srv, а 7.4 — нет. 7.4 правильно подключался без открытия порта хостинговой компанией. Где, как и в PHP 8.0, +srv был удален, и порт нужно было открыть.
Если вы можете воспроизвести проблему, когда объект Manager печатает что-либо, кроме своего первого аргумента конструктора, в поле uri
своего отладочного вывода, откройте проблему либо в JIRA , либо в mongodb/mongo-php-driver GitHub. проект, и я буду рад продолжить расследование. При этом обязательно укажите точную версию PHP и расширение mongodb
.
Я также добавлю, что ваш хостинг-провайдер, разрешающий PHP 8.0 создавать исходящие соединения на порту 27017, не должен иметь ничего общего с поиском DNS, выполняемым во время построения менеджера. executeBulkWrite()
— это первая точка в скрипте, где драйвер попытается подключиться к серверу MongoDB. Поскольку вывод print_r()
генерируется до этой точки, единственным фактором, способствующим ошибке драйвера, будет построение менеджера и любое разрешение SRV, которое происходит внутри. Это должно предоставить вам минимальный объем кода для попытки воспроизведения.
Похоже, это может быть похоже на: stackoverflow.com/questions/51755165/… Однако не было никакого решения, кроме отладки с помощью curl. Это также драйвер С#, а не PHP.