由于 CLOSE_WAIT 个文件的数量,调用第 3 方 API 导致 "Too many open files." 错误

Calling 3rd party API causes "Too many open files." error due to number of CLOSE_WAIT files

我在我的应用程序中使用 Bigcommerce PHP SDK。此 SDK 记录在此处:

https://github.com/bigcommerce/bigcommerce-api-php

我有一个脚本可以遍历大量对象(1000 个对象)。在每次迭代期间,都会使用此 SDK 对 Bigcommerce 进行多次调用。例如,在脚本中的一个文件中,此处可能是获取产品 skus 的调用:

Bigcommerce::configure(array(
    'client_id' => BC_CLIENT_ID,
    'auth_token' => BC_AUTH_TOKEN,
    'store_hash' => BC_STORE_HASH,
));

Bigcommerce::getCollection('product/123/skus', 'Sku');

稍后在脚本中使用的另一个文件中,有一个调用来检索另一个资源,例如产品的图像:

Bigcommerce::configure(array(
    'client_id' => BC_CLIENT_ID,
    'auth_token' => BC_AUTH_TOKEN,
    'store_hash' => BC_STORE_HASH,
));

Bigcommerce::getCollection('product/123/images', 'Sku');

我遇到的问题是,在该脚本运行一段时间后,我收到一条错误消息,提示打开的文件过多。这是实际错误:

PHP Fatal error:  Uncaught exception 'ErrorException' with message 'include(/var/www/html/app/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Response.php): failed to open stream: Too many open files' in /var/www/html/app/vendor/composer/ClassLoader.php:386
Stack trace:
#0 /var/www/html/app/vendor/composer/ClassLoader.php(386): Illuminate\Exception\Handler->handleError(2, 'include(/var/ww...', '/var/www/html/a...', 386, Array)
#1 /var/www/html/app/vendor/composer/ClassLoader.php(386): Composer\Autoload\includeFile()
#2 /var/www/html/app/vendor/composer/ClassLoader.php(278): Composer\Autoload\includeFile('/var/www/html/a...')
#3 [internal function]: Composer\Autoload\ClassLoader->loadClass('Symfony\Compone...')
#4 /var/www/html/app/vendor/laravel/framework/src/Illuminate/Exception/WhoopsDisplayer.php(49): spl_autoload_call('Symfony\Compone...')
#5 /var/www/html/app/ve in /var/www/html/app/vendor/composer/ClassLoader.php on line 386

PHP Fatal error:  Uncaught exception 'ErrorException' with message 'include(/var/www/html/app/vendor/symfony/debug/Symfony/Component/Debug/Exception/FatalErrorException.php): failed to open stream: Too many open files' in /var/www/html/app/vendor/composer/ClassLoader.php:386
Stack trace:
#0 /var/www/html/app/vendor/composer/ClassLoader.php(386): Illuminate\Exception\Handler->handleError(2, 'include(/var/ww...', '/var/www/html/a...', 386, Array)
#1 /var/www/html/app/vendor/composer/ClassLoader.php(386): Composer\Autoload\includeFile()
#2 /var/www/html/app/vendor/composer/ClassLoader.php(278): Composer\Autoload\includeFile('/var/www/html/a...')
#3 [internal function]: Composer\Autoload\ClassLoader->loadClass('Symfony\Compone...')
#4 /var/www/html/app/vendor/laravel/framework/src/Illuminate/Exception/Handler.php(191): spl_autoload_call('Symfony\Compone...')
#5 [internal function]: Illuminate\Exception\Hand in /var/www/html/app/vendor/composer/ClassLoader.php on line 386

我已经能够确定,由于脚本是 运行,与 Bigcommerce 建立的每个连接似乎都算作另一个打开的 "file"。我通过 运行 以下命令看到了这一点:

lsof -uroot | grep 104.236.XX.XXX | wc -l

该命令输出的数字不断增加。如果我真的查看打开的文件,我会看到一长串状态为 CLOSE_WAIT 的文件,例如:

php       14005 root    5u     IPv4            1792827      0t0     TCP 104.236.XX.XXX:58077->192.200.169.163:https (CLOSE_WAIT)
php       14005 root    7u     IPv4            1793002      0t0     TCP 104.236.XX.XXX:58078->192.200.169.163:https (CLOSE_WAIT)
php       14005 root    8u     IPv4            1793003      0t0     TCP 104.236.XX.XXX:58079->192.200.169.163:https (CLOSE_WAIT)
php       14005 root    9u     IPv4            1793004      0t0     TCP 104.236.XX.XXX:58080->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   10u     IPv4            1793005      0t0     TCP 104.236.XX.XXX:58081->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   11u     IPv4            1793006      0t0     TCP 104.236.XX.XXX:58082->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   12u     IPv4            1793007      0t0     TCP 104.236.XX.XXX:58083->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   13u     IPv4            1793008      0t0     TCP 104.236.XX.XXX:58084->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   14u     IPv4            1793093      0t0     TCP 104.236.XX.XXX:58085->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   15u     IPv4            1793094      0t0     TCP 104.236.XX.XXX:58086->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   16u     IPv4            1793095      0t0     TCP 104.236.XX.XXX:58087->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   17u     IPv4            1793170      0t0     TCP 104.236.XX.XXX:58088->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   18u     IPv4            1793234      0t0     TCP 104.236.XX.XXX:58089->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   19u     IPv4            1793242      0t0     TCP 104.236.XX.XXX:58090->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   20u     IPv4            1793315      0t0     TCP 104.236.XX.XXX:58091->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   21u     IPv4            1793328      0t0     TCP 104.236.XX.XXX:58092->192.200.169.163:https (CLOSE_WAIT)
php       14005 root   22u     IPv4            1793389      0t0     TCP 104.236.XX.XXX:58093->192.200.169.163:https (ESTABLISHED)
php       14005 root   23u     IPv4            1793390      0t0     TCP 104.236.XX.XXX:58094->192.200.169.163:https (ESTABLISHED)
php       14005 root   24u     IPv4            1793458      0t0     TCP 104.236.XX.XXX:58095->192.200.169.163:https (ESTABLISHED)
php       14005 root   25u     IPv4            1793464      0t0     TCP 104.236.XX.XXX:58096->192.200.169.163:https (ESTABLISHED)
php       14005 root   26u     IPv4            1793465      0t0     TCP 104.236.XX.XXX:58097->192.200.169.163:https (ESTABLISHED)

此列表继续变得越来越长,直到脚本因上面显示的 "Too many files open" 错误而出错。

我的假设是这些 CLOSE_WAIT 文件导致我达到了可以打开的文件数量的限制。我能做些什么来摆脱这些文件吗?如果与 Bigcommerce 的连接已经完成,为什么它们被视为 "open" 文件?

可能是我SDK使用不当?换句话说,有没有办法让所有调用都来自单个 Bigcommerce class 而不是每次都创建一个新连接?

我能够通过更改 configure 方法来解决这个问题,使其在每次调用时都不创建新连接。新方法在我的 github:

分支中可用

https://github.com/flyingL123/bigcommerce-api-php