常见问题解答
常见扩展安装错误
未找到 PHP 标头
例如:
/private/tmp/pear/install/mongodb/php_phongo.c:24:10: fatal error: 'php.h' file not found #include <php.h> ^~~~~~~
此错误表明 PHP 的构建系统找不到必要的标头。 所有 PHP 扩展都需要标头才能编译。 Additionally, those headers must correspond to the PHP runtime for which the extension will be used. 通常, phpize
命令(由pecl
调用)将确保使用正确的标头构建扩展。
请注意,仅存在 PHP 运行时并不意味着标头可用。 在各种 Linux 发行版上,标头通常在单独的php-dev
或php-devel
包下发布。 在 macOS 上,默认 PHP 运行时不包含标头,用户通常需要通过 Homebrew 安装 PHP(和标头) 以构建扩展。
安装多个 PHP 运行时
如果您的系统安装了多个版本的 PHP,则每个版本都有自己的pecl
和phpize
命令。 此外,每个 PHP 运行时可能有针对每个 SAPI 的单独php.ini
文件(例如 FPM、CLI)。 如果扩展已安装,但在运行时不可用,请仔细检查是否使用了正确的pecl
命令并修改了相应的php.ini
文件。
php.ini
如果对PHP运行时使用的 文件有任何疑问,则应检查 phpinfo() 的输出 对于该特定 SAPI。此外, php_ini_loaded_file() 和 php_ini_scanned_files() 可用于准确确定PHP已加载哪些 INI 文件。
要调试未加载扩展的问题,可以使用工具目录中提供的detect-extension
脚本。 您可以从 CLI 运行此脚本,或将其包含在可通过 Web 服务器访问的脚本中。 该工具将指出系统的潜在问题和安装说明。 假设您已通过 Composer 安装该库,则可以从供应商目录中调用该脚本:
php vendor/mongodb/mongodb/tools/detect-extension.php
如果要检查 Web 服务器 SAPI 的配置,请将该文件包含在可通过 Web 服务器访问的脚本中,然后在浏览器中打开它。 请记住将脚本包装在<pre>
标记中,以正确格式化其输出:
<pre>require(...); </pre>
在 Windows 上加载不兼容的 DLL
Windows binaries are available for various combinations of PHP version, thread safety (TS or NTS), and architecture (x86 or x64). 尝试在运行时加载扩展 DLL 时,如果未能选择正确的二进制文件,将导致错误:
PHP Warning: PHP Startup: Unable to load dynamic library 'mongodb'
确保您已下载与以下 PHP 运行时属性相对应的 DLL:
PHP 版本 (
PHP_VERSION
)线程安全 (
PHP_ZTS
)架构 (
PHP_INT_SIZE
)
除了上述常量之外,这些属性还可以从 phpinfo() 。如果您的系统安装了多个 PHP 运行时,请仔细检查您正在检查的phpinfo()
输出是否存在正确的环境。
上述detect-extension
脚本还可用于确定适合您的 PHP 环境的 DLL。
连接处理和持久性
与MongoDB 部署的连接由libmongoc
库和PHP扩展处理。当您构造MongoDB\Client
实例时, PHP库会使用相同的连接字符串和选项创建MongoDB\ 驱动程序\ 经理实例。该扩展还使用这些构造函数参数为持久libmongoc
客户端派生哈希键。如果您以前使用密钥持久保存了libmongoc
客户端,则系统会重复使用该客户端。否则,将创建一个新的libmongoc
客户端,并在PHP工作进程的生命周期内保留。您可以在PHP扩展文档中学习;了解有关此进程的更多信息。
每个 libmongoc
客户端都维护自己与MongoDB 部署的连接及其拓扑结构视图。当您重复使用持久性 libmongoc
客户端时, PHP库可以避免建立新连接和重新发现拓扑结构的开销。这种方法通常可以提高性能,并且是驱动程序的默认行为。
在PHP工作进程结束之前,持久 libmongoc
客户端不会释放。这意味着在 MongoDB\Driver\Manager
对象超出范围后,与MongoDB 部署的连接可能会保持打开状态。虽然对于连接到一个MongoDB 部署的应用程序来说,这通常不是问题,但在某些情况下可能会出现问题,如下列表所述:
PHP-FPM 配置为
pm.max_requests=0
,因此工作线程永不重生,并且PHP应用程序可以多次部署,只需对其MongoDB连接字符串或选项进行少量更改。这可能会导致每个工作进程中累积libmongoc
个客户端对象。应用程序偶尔会连接到后端组件中的单独MongoDB 部署,其中请求延迟不是最重要的方面。
在第一种情况下,作为应用程序部署的一部分重新启动PHP -FPM 允许应用程序发布任何未使用的 libmongoc
客户端,并仍然使用持久客户端作为最新的连接字符串。
第二种情况需要不同的解决方案。为 disableClientPersistence
驾驶员选项指定 true
会指示PHP库创建新的 libmongoc
客户端,并确保在相应的 MongoDB\Driver\Manager
超出范围时将其释放。
以下代码演示了如何在创建客户端时将 disableClientPersistence
选项设立为 true
:
$client = new MongoDB\Client( uri: getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/', uriOptions: [], driverOptions: ['disableClientPersistence' => true], );
请在仔细考虑后使用 disableClientPersistence
驾驶员选项,因为选择退出客户端持久性需要更多时间来建立与MongoDB 部署的连接并发现其拓扑结构。
服务器选择失败
以下是服务器选择失败的所有示例:
No suitable servers found (`serverSelectionTryOnce` set): [connection refused calling hello on 'a.example.com:27017'] [connection refused calling hello on 'b.example.com:27017'] No suitable servers found: `serverSelectionTimeoutMS` expired: [socket timeout calling hello on 'example.com:27017'] No suitable servers found: `serverSelectionTimeoutMS` expired: [connection timeout calling hello on 'a.example.com:27017'] [connection timeout calling hello on 'b.example.com:27017'] [TLS handshake failed: -9806 calling hello on 'c.example.com:27017'] No suitable servers found: `serverselectiontimeoutms` timed out: [TLS handshake failed: certificate verify failed (64): IP address mismatch calling hello on 'a.example.com:27017'] [TLS handshake failed: certificate verify failed (64): IP address mismatch calling hello on 'b.example.com:27017']
这些错误通常表现为 MongoDB\ 驱动程序\Exception\ConnectionTimeoutException 扩展中的异常。实际的异常消息源自 libmongoc,它是扩展使用的根本的系统库。 由于这些消息可以采用多种形式,因此分解消息的结构很有帮助,这样您就可以更好地诊断应用程序中的错误。
消息通常以“未找到合适的服务器”开头。 消息的下一部分指示服务器选择失败的原因。 默认,扩展会避免服务器选择循环,而是进行单次尝试(根据 serverSelectionTryOnce
连接string选项)。 如果扩展配置为利用循环,则类似“serverSelectionTimeoutMS expired”的消息将告诉我们已用完其时间限制。
The last component of the message tells us why server selection failed, and includes one or more errors directly from the topology scanner, which is the service responsible for connecting to and monitoring each host. 上次在监控期间出现错误的任何主机都将包含在此列表中。 这些消息通常源自低级套接字或 TLS 函数。
以下内容并非详尽无遗,但希望能为您指明分析服务器选择失败的影响因素的正确方向:
“连接被拒绝”可能表示远程主机未侦听预期的端口。
“连接超时”可能表示路由或防火墙问题,或者可能是由于延迟而导致的超时。
“套接字超时”表示在某个点建立了连接,但由于延迟而被断开或超时。
“TLS握手失败”表示与 TLS 或 OCSP 验证相关的问题,有时表示 TLS 证书配置错误。
如果连接失败,您可以使用connect
工具尝试接收更多信息。 此工具尝试使用套接字函数连接到连接字符串中的每个主机,看看它是否能够建立连接、发送和接收数据。 该工具将 MongoDB 部署的连接字符串作为其唯一参数。 假设您已通过 Composer 安装该库,则应从供应商目录中调用该脚本:
php vendor/mongodb/mongodb/tools/connect.php mongodb://127.0.0.1:27017
如果服务器不接受连接,输出将如下所示:
Looking up MongoDB at mongodb://127.0.0.1:27017 Found 1 host(s) in the URI. Will attempt to connect to each. Could not connect to 127.0.0.1:27017: Connection refused
注意
该工具仅支持mongodb://
URI 模式。 不支持使用mongodb+srv
方案。