PHP Mongo批量写入

huangapple go评论65阅读模式
英文:

PHP Mongo Bulk Write

问题

这是一个关于PHP脚本和MongoDB连接问题的描述。如果你需要帮助,可以提供更多细节。

英文:

Please could some one help with this issue. Thanks.

The PHP script below gives rise to the following error when attempting to execute the bulkwrite line.

[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

It is interesting that the error shows a port number. It's also interesting that the connection string printed back to the console doesn't have the +srv.

But you are not allowed to include a port number with a mongo+srv connection type. I am not specifying a port number.

In Compass on the laptop I get this error when taking away the +srv
getaddrinfo ENOTFOUND cluster0.tx3cl.mongodb.net and also if I add the port number 27017 to make up for the lack of +srv, I get the same error.

Is there something I have to do to override the default port being added?
Technical details

[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]$ 

The output of the script on the console is as follows

[prompt]$ php script.php
loaded
MongoDB\Driver\Manager Object
(
    [uri] => mongodb://user:password@blah.blah.mongodb.net/?retryWrites=true&w=majority
    [cluster] => Array
        (
        )

)

The script itself is

<?php
    use MongoDB\Client;
    use MongoDB\Driver\ServerApi;

    echo extension_loaded("mongodb") ? "loaded\n" : "not loaded\n";

    $uri = 'mongodb+srv://user:password@blah.blah.mongodb.net/?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);
    } 
?>

The URL in the connection string is pingable from the server I am trying to connect from.

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

答案1

得分: 1

I just changed the version of PHP from 8.0 to 7.4.
我刚刚将PHP版本从8.0更改为7.4。

The simple answer is that the script works with PHP 7.4. The hint it wasn't a network issue is down to the fact that the same connection string works from a laptop running compass.
简单的答案是该脚本与PHP 7.4兼容。提示不是网络问题的原因在于,相同的连接字符串在运行Compass的笔记本电脑上有效。

The question is now, what is the right syntax for PHP 8.0 PHP Mongo批量写入
现在的问题是,PHP 8.0的正确语法是什么 PHP Mongo批量写入

Additional news. I contacted my hosting company support about this. They opened the port on 27017 and this script now works with PHP 8.0 and 7.4
额外的消息。我联系了我的托管公司支持人员。他们打开了27017端口,现在该脚本适用于PHP 8.0和7.4。

I have posted a question to the monog forums here if anyone is interested.
如果有人感兴趣,我已在此处向Mongo论坛发布了一个问题。
https://www.mongodb.com/community/forums/t/why-does-php-8-0-remove-the-srv/224252

What helped me work out the problem with versions was seeing the same code here: https://help.ovhcloud.com/csm/en-gb-public-cloud-databases-mongodb-connect-php?id=kb_article_view&sysparm_article=KB0049087
帮助我解决版本问题的是在这里看到的相同代码:https://help.ovhcloud.com/csm/en-gb-public-cloud-databases-mongodb-connect-php?id=kb_article_view&sysparm_article=KB0049087
他们提到他们使用的PHP版本,而且代码基本与我所使用的相同。

Previous to this I thought I had done my research for PHP 8.0 and Mongo. Now, if I did, and it's a bug that will be interesting. Can't wait to see what the mongo forums say.
在此之前,我认为我已经为PHP 8.0和Mongo做了研究。现在,如果我真的这样做了,而且这是一个错误,那将很有趣。迫不及待地想看看Mongo论坛上的讨论。

英文:

I just changed the version of PHP from 8.0 to 7.4.

The simple answer is that the script works with PHP 7.4. The hint it wasn't a network issue is down to the fact that the same connection string works from a laptop running compass.

The question is now, what is the right syntax for PHP8.0 PHP Mongo批量写入

> Additional news. I contacted my hosting company support about this. They
> opened the port on 27017 and this script now works with PHP 8.0 and
> 7.4

I have posted a question to the monog forums here if anyone is interested.
https://www.mongodb.com/community/forums/t/why-does-php-8-0-remove-the-srv/224252

What helped me work out the problem with versions was seeing the same code here: https://help.ovhcloud.com/csm/en-gb-public-cloud-databases-mongodb-connect-php?id=kb_article_view&sysparm_article=KB0049087
They stated the version of PHP they were using and the code was essentually the same as what I had.

Previous to this I thought I had done my research for PHP 8.0 and Mongo. Now, if I did, and it's a bug that will be interesting. Can't wait to see what the mongo forums say.

答案2

得分: 1

tl;dr: 我没有看到驱动程序错误的证据,也没有在 PHP 7.4 和 8.0 之间看到任何行为差异。根本原因似乎是 PHP 8.0 应用服务器上存在限制性的网络策略(参考 你的回答)。

解释 ConnectionTimeoutException

MongoDB PHP 库文档中包含了一个常见问题解答,其中有一个关于 服务器选择失败 的部分。阅读这部分将帮助你理解 "找不到合适的服务器" 错误,但我也会在这里做一些解释:

未捕获的 MongoDB\Driver\Exception\ConnectionTimeoutException:
  未找到合适的服务器(`serverSelectionTryOnce` 设置):
  [在 'cluster0-shard-00-00.tx3cl.mongodb.net:27017' 上调用 ismaster 时关闭连接]
  [在 'cluster0-shard-00-01.tx3cl.mongodb.net:27017' 上调用 ismaster 时关闭连接]
  [在 'cluster0-shard-00-02.tx3cl.mongodb.net:27017' 上调用 ismaster 时关闭连接]
  位于 /path/to/script...

驱动程序无法为数据库操作选择任何服务器,并报告了每个服务器连接上的最新错误。这里出现三台服务器告诉我们,最初的 mongodb+srv:// URI 已成功解析为三个主机的种子列表。

在套接字错误消息中看到 "连接关闭" 让我立即想到某些东西拒绝了连接。造成这种情况的许多可能原因之一可能是限制性的网络配置、防火墙或远程主机拒绝连接。就 MongoDB Atlas 而言,如果 PHP 应用服务器的 IP 地址未包括在集群的 IP 访问列表条目 中,也会出现此错误。

确定根本原因

你的回答 中,你说:

> 我联系了我的托管公司支持。他们打开了 27017 端口,现在此脚本可以在 PHP 8.0 和 7.4 上运行。

如果我理解正确,你托管公司的网络配置阻止了 PHP 进行对 27017 端口的出站连接。这肯定可以解释连接错误,也不表明 PHP 或 MongoDB 驱动存在任何问题。

澄清一些误解

> 有趣的是错误显示了一个端口号。

在服务器选择错误中找到的主机和端口与 mongodb+srv:// URI 不是直接相关的。你忽视了驱动程序将查询 DNS 并构建一个种子列表,类似于 mongodb:// URI。MongoDB 文档中的 DNS 种子列表连接格式 对此进行了更详细的解释。

27017 只是默认端口。

> 但你不能在 mongo+srv 连接类型中包含端口号。我没有指定端口号。

你说得对,mongodb+srv:// URI 不包括端口号。种子列表中每个服务器的端口实际上是从 DNS 记录中获取的。

请注意,种子列表仍然只是信息的中介来源,可能不反映驱动程序最终连接到的所有服务器。如果你对此感兴趣,你可以阅读 服务器发现和监视 驱动程序规范或 MongoDB 博客上的 下一代 MongoDB 驱动程序中的服务器发现和监视(它有点旧,但比原始规范更容易理解)。

> 有趣的是,控制台打印回的连接字符串没有 +srv。

根据你上面分享的信息,我对此没有解释,但我也没有找到驱动程序会报告除构建 Manager 时使用的原始 URI 之外的任何其他内容的证据。

Manager 对象的 get_debug_info 处理程序 使用 mongoc_uri_get_string()) 填充 uri 字段。libmongoc 中的这个函数(构建 PHP 驱动程序的 C 驱动程序) 返回相同的字符串,用于构建 URI,最初在 mongoc_uri_new_with_error() 中设置。值得一提的是,当创建 Manager 对象时,PHP 驱动程序也 使用了相同的函数

我假设还有一些重要信息被省略了。例如,你提到了使用了哪些 PHP 版本(7.4 和 8.0),但从未提及在每个环境中运行的 PHP 驱动程序(即 mongodb 扩展)的版本。每个 PHP 环境运行在哪里也不太清楚。如果最初的连接错误是由你托管公司的网络配置引起的,并且他们碰巧运行的是 PHP 8.0,这并不意

英文:

tl;dr: I see no evidence of a driver bug, nor any behavioral difference between PHP 7.4 and 8.0. The root cause appeared to be a restrictive network policy on the PHP 8.0 application server (per your answer).

Explaining the ConnectionTimeoutException

The MongoDB PHP Library docs include an FAQ, which has a section on Server Selection Failures. Reading through that should allow you to make sense of the "No suitable servers found" error, but I'll break it down here as well:

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...

The driver was unable to select any server for the database operation and is reporting the most recent error on each server connection. The fact that three servers are present here tells us that the original mongodb+srv:// URI was successfully resolved into a seed list of three hosts.

Seeing "connection closed" in the socket error message leads me to assume something immediately rejected the connection. Among the many possible causes for that may be a restrictive network configuration, firewall, or the remote host rejecting a connection. With respect to MongoDB Atlas, this error is also common if PHP application server's IP address is not included in the cluster's IP Access List Entries.

Identifying the root cause

In your answer you stated:

> I contacted my hosting company support about this. They opened the port on 27017 and this script now works with PHP 8.0 and 7.4

If I understand correctly, your hosting company's network configuration was blocking PHP from making outgoing connections to port 27017. That certainly would have explained the connection error, and doesn't suggest any issue with PHP or the MongoDB driver.

Clearing up some misunderstandings

> It is interesting that the error shows a port number.

The hosts and ports found in the server selection error are not directly related to the mongodb+srv:// URI. You are overlooking that the driver is going to query DNS and construct a seed list, akin to a mongodb:// URI. DNS Seed List Connection Format in the MongoDB docs explains that in more detail.

27017 is merely the default port.

> But you are not allowed to include a port number with a mongo+srv connection type. I am not specifying a port number.

You're correct that a mongodb+srv:// URI does not include the port. The port for each server in the seed list is actually obtained from the DNS records.

Note that the seed list is still just an intermediary source of information and may not reflect all servers that the driver ultimately connects to. If you're curious about that you can read through the Server Discovery and Monitoring driver specification or Server Discovery and Monitoring In Next Generation MongoDB Drivers on the MongoDB blog (it's a bit old but easier to digest than the raw spec).

> It's also interesting that the connection string printed back to the console doesn't have the +srv.

I don't have an explanation for this based on what you shared above, but I also found no evidence that the driver would report anything other than the original URI used to construct the Manager.

The Manager object's get_debug_info handler populates the uri field using mongoc_uri_get_string()). That function in libmongoc (the C driver upon which the PHP driver is built) returns the same string used to construct the URI, which is originally set in mongoc_uri_new_with_error(). For the record, that is the same function used by the PHP driver when creating a Manager object.

I assume some other vital information is being omitted. For example, you mentioned which PHP versions were being used (7.4 and 8.0), but never mentioned the version of the PHP driver (i.e. mongodb extension) running in each environment. It also wasn't clear where each PHP environment was running. If the original connection error was caused by your hosting company's network configuration, and they happened to be running PHP 8.0, that doesn't mean that PHP 8.0 is the problem (correlation does not imply causation).

> In Compass on the laptop I get this error when taking away the +srv getaddrinfo ENOTFOUND cluster0.tx3cl.mongodb.net and also if I add the port number 27017 to make up for the lack of +srv, I get the same error.

The host used for a mongodb+srv:// URI is not necessarily the same as the host(s) running MongoDB. cluster0.tx3cl.mongodb.net is used for DNS resolution, but based on the ConnectionTimeoutException above we can see the actual servers are running on the following hosts:

  • cluster0-shard-00-00.tx3cl.mongodb.net
  • cluster0-shard-00-01.tx3cl.mongodb.net
  • cluster0-shard-00-02.tx3cl.mongodb.net

Given that, there's no reason to expect a MongoDB server to be listening on cluster0.tx3cl.mongodb.net:27017.

huangapple
  • 本文由 发表于 2023年4月17日 00:33:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76029036.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定