由于 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:
分支中可用
我在我的应用程序中使用 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: