lcatlett/newrelic-guzzle-client

解决由于 New Relic 代理导致的 Guzzle 请求性能瓶颈的一种方法。

dev-master 2024-03-28 19:06 UTC

This package is auto-updated.

Last update: 2024-08-28 19:55:32 UTC


README

此软件包提供了一种解决由 New Relic 代理的当前实现中 Guzzle 6 客户端指标跟踪中间件导致的性能和内存瓶颈的方法。

⚠️ 该库是一个依赖当前 New Relic 扩展实现的 解决方案

在使用之前,请仔细测试与新扩展版本一起使用的情况。

请参阅下面的概述部分以获取更多详细信息。

安装

composer require lcatlett/newrelic-guzzle-client

就这样!由于 Composer 自动加载器,脚本将自动导入。

没有 Composer

ℹ️ 您也可以复制文件 NewRelicGuzzle.php 并直接将其包含到项目中。例如,不使用 Composer 的 WordPress 网站可以在 wp-config.php 的顶部添加 require(/path/to/newrelic-guzzle-client/NewRelicGuzzle.php)

概述

newrelic 扩展 定义了一个 PHP 函数,一个 Guzzle 中间件,用于报告从 PHP 发出的每个请求的一些指标。

New Relic 代理扩展的当前实现将 Guzzle 中间件注册在每个新的客户端实例上,并将请求包裹在 curl_exec 而不是 curl_multi_exec 或流中。这会导致性能问题并耗尽内存,因为中间件会在每次请求上重新注册,然后被包裹在一个单独的调用中。

在 Pantheon 客户端网站上观察到的问题包括内存使用量和请求时间的增加,尤其是对于本应异步的请求实际上变成了阻塞调用。这些瓶颈通常可以在 Pantheon 应用程序容器的 php-slow.log 文件中看到,其中调用了 newrelic\Guzzle6

[20-Mar-2024 01:14:07]  [pool www] pid 10017
script_filename = /code/web//index.php
[0x00007f9e4ee17230] curl_exec() /code/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php:40
[0x00007f9e4ee17190] __invoke() newrelic/Guzzle6:1
[0x00007f9e4ee16ff0] newrelic\Guzzle6\{closure}() /code/vendor/guzzlehttp/guzzle/src/Middleware.php:233
[0x00007f9e4ee16f50] GuzzleHttp\{closure}() /code/vendor/guzzlehttp/guzzle/src/HandlerStack.php:71
[0x00007f9e4ee16ec0] __invoke() /code/vendor/guzzlehttp/guzzle/src/Client.php:351
[0x00007f9e4ee16db0] transfer() /code/vendor/guzzlehttp/guzzle/src/Client.php:112
[0x00007f9e4ee16d30] sendAsync() /code/vendor/guzzlehttp/guzzle/src/Client.php:129
[0x00007f9e4ee16cb0] send() /code/web/modules/contrib/search_api_pantheon/src/Services/PantheonGuzzle.php:92
[0x00007f9e4ee16c40] sendRequest() /code/vendor/solarium/solarium/src/Core/Client/Adapter/Psr18Adapter.php:66
[0x00007f9e4ee16ae0] execute() /code/vendor/solarium/solarium/src/Core/Client/Client.php:846
[0x00007f9e4ee16a30] executeRequest() /code/web/modules/contrib/search_api_pantheon/src/Services/SolariumClient.php:61
[0x00007f9e4ee169b0] executeRequest() /code/vendor/solarium/solarium/src/Core/Client/Client.php:817
[0x00007f9e4ee168e0] execute() /code/web/modules/contrib/search_api_pantheon/src/Services/SolariumClient.php:49
[0x00007f9e4ee16860] execute() /code/web/modules/contrib/search_api_solr/src/SolrConnector/SolrConnectorPluginBase.php:974
[0x00007f9e4ee167d0] execute() /code/web/modules/contrib/search_api_solr/src/SolrConnector/SolrConnectorPluginBase.php:938
[0x00007f9e4ee16730] update() /code/web/modules/contrib/search_api_solr/src/Plugin/search_api/backend/SearchApiSolrBackend.php:1129
[0x00007f9e4ee165e0] indexItems() /code/web/modules/contrib/search_api/src/Entity/Server.php:350
[0x00007f9e4ee16510] indexItems() /code/web/modules/contrib/search_api/src/Entity/Index.php:994
[0x00007f9e4ee163c0] indexSpecificItems() /code/web/modules/contrib/search_api/src/Entity/Index.php:930
[0x00007f9e4ee16290] indexItems() /code/web/modules/contrib/search_api/search_api.module:116

上面的例子是当 Pantheon 搜索 API 索引内容时。另一个例子是当 tmgmt_smartling 模块同步翻译时。

[16-Mar-2024 02:32:50]  [pool www] pid 3593
script_filename = /code/web//index.php
[0x00007f6e9d617100] curl_exec() /code/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php:44
[0x00007f6e9d617060] __invoke() /code/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php:28
[0x00007f6e9d616fb0] GuzzleHttp\Handler\{closure}() /code/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php:48
[0x00007f6e9d616f00] GuzzleHttp\Handler\{closure}() newrelic/Guzzle6:1
[0x00007f6e9d616d60] newrelic\Guzzle6\{closure}() /code/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php:35
[0x00007f6e9d616c80] __invoke() /code/vendor/guzzlehttp/guzzle/src/Middleware.php:31
[0x00007f6e9d616bd0] GuzzleHttp\{closure}() /code/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php:71
[0x00007f6e9d616b30] __invoke() /code/vendor/guzzlehttp/guzzle/src/Middleware.php:66
[0x00007f6e9d616a90] GuzzleHttp\{closure}() /code/vendor/guzzlehttp/guzzle/src/HandlerStack.php:75
[0x00007f6e9d616a00] __invoke() /code/vendor/guzzlehttp/guzzle/src/Client.php:333
[0x00007f6e9d6168b0] transfer() /code/vendor/guzzlehttp/guzzle/src/Client.php:169
[0x00007f6e9d6167d0] requestAsync() /code/vendor/guzzlehttp/guzzle/src/Client.php:189
[0x00007f6e9d616740] request() /code/vendor/smartling/api-sdk-php/src/BaseApiAbstract.php:491
[0x00007f6e9d6165f0] sendRequest() /code/vendor/smartling/api-sdk-php/src/ProgressTracker/ProgressTrackerApi.php:61
[0x00007f6e9d616560] getToken() /code/web/modules/contrib/tmgmt_smartling/src/Smartling/ConfigManager/FirebaseConfigManager.php:69
[0x00007f6e9d616460] getAvailableConfigs() /code/web/modules/contrib/tmgmt_smartling/tmgmt_smartling.module:886
[0x00007f6e9d6163c0] tmgmt_smartling_page_attachments() /code/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php:311
[0x00007f6e9d616340] Drupal\Core\Render\MainContent\{closure}() /code/web/core/lib/Drupal/Core/Extension/ModuleHandler.php:388
[0x00007f6e9d616280] invokeAllWith() /code/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php:312
[0x00007f6e9d6161f0] invokePageAttachmentHooks() /code/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php:285

相关的 New Relic 问题

https://github.com/newrelic/newrelic-php-agent 的问题队列中存在一些长期存在的问题,这些问题可能与该问题有关

注意:当 New Relic 代理添加 Guzzle 7 支持时,需要重构此解决方案: newrelic/newrelic-php-agent#498