握手税

你的 Magento 集成可能因为一项隐藏的网络成本而变得缓慢。

我曾经运行过一个需要调用定价 API 的产品导出任务。单个产品处理得很快,但整个目录却耗费了极长时间。我的数据库处于空闲状态,而性能分析工具显示问题出在网络上。

代码在循环内部创建了一个新的 HTTP 客户端。

在通过 HTTPS 发送数据之前,你的机器需要进行大量工作。它需要执行 TCP 握手来打开套接字(socket),然后执行 TLS 握手来交换证书并协商密钥。这需要多次往返。

如果你只做一次,成本很低。但如果你在 40,000 个产品的循环中这样做,你就得支付 40,000 次这样的成本。实际传输的数据量很小,而建立连接的过程才是昂贵的部分。

在 PHP 中,你往往觉得应该创建一个客户端然后就将其丢弃。这对于单个 Web 请求是可行的,但在长时间运行的任务中则会失效。

在 cron job、控制台命令或消息队列消费者中,请避免这种模式:

这段代码会为每一个产品都打开一个新连接并运行完整的握手过程。

如果你使用同一个客户端实例,Guzzle 会保持连接处于活跃状态。请将客户端移到循环之外:

  • $client = new \GuzzleHttp\Client(['base_uri' => 'https://api.example.com']);
  • foreach ($products as $product) {
  • $client->post('/sync', [...]);
  • }

现在,套接字和 TLS 会话将保持开启。你只需进行一次握手,然后就可以流式传输剩余的数据。在 Magento 中,应该通过构造函数注入一个配置好的客户端,而不是手动创建它。

不这样做带来的不仅仅是延迟。你可能会耗尽出站端口。已关闭的连接在操作系统回收它们之前,会以比回收速度更快的速度堆积在 TIME_WAIT 状态。最终,你的服务将完全无法打开新的套接字。

检查你的代码是否存在此错误。在终端运行此命令:

grep -rn "new .*Client(" app/code | grep -i http

寻找任何位于循环内部的新客户端创建语句。将客户端移出循环。对于大规模同步任务,这只是改动一行代码,却能带来巨大的速度提升。

Source: https://dev.to/iamrobindhiman/the-handshake-tax-reuse-your-http-client-in-magento-integrations-3kk7