elastic/transport

Elastic产品HTTP传输PHP库

v8.10.0 2024-08-14 08:55 UTC

README

Elastic PHP客户端的HTTP传输

Build status

这是一个用于与Elastic产品(如Elasticsearch)通信的HTTP传输PHP库。

它实现了PSR-7标准来管理HTTP消息,PSR-18用于发送HTTP请求。此外,它还使用PSR-17来构建PSR-7对象,如HTTP请求、HTTP响应、URI等。

它使用HTTPlug库来自动发现PSR-18客户端、PSR-17工厂和HttpAsyncClient接口,以异步方式进行HTTP请求。

传输的架构灵活且可定制,您可以使用PSR-18客户端、PSR-3记录器和自定义NodePoolInterface来配置它,以管理节点集群。

快速开始

这个库的主要组件是Transport类。

此类使用以下3个组件

  • 一个PSR-18客户端,使用ClientInterface;
  • 一个节点池,使用NodePoolInterface;
  • 一个PSR-3记录器,使用LoggerInterface。

虽然PSR-3和PSR-18在PHP社区中是众所周知的标准,但NodePoolInterface是本库中提出的新接口。此接口的目的是提供一个能够为一系列主机选择节点的类。例如,使用Elasticsearch,这是一个分布式搜索引擎,您需要管理一个节点集群。每个节点公开一个公共HTTP API,您可以将HTTP请求发送到一个或多个节点。NodePoolInterface是一个用于管理HTTP请求路由到集群节点拓扑的组件。

为了构建Transport实例,您可以使用以下TransportBuilder

use Elastic\Transport\TransportBuilder;

$transport = TransportBuilder::create()
    ->setHosts(['localhost:9200'])
    ->build();

此示例演示了如何将传输设置为与位于localhost:9200(例如Elasticsearch默认端口)的一个节点通信。

默认情况下,TransportBuilder将使用HTTPlug的自动发现功能作为PSR-18客户端、SimpleNodePool作为NodePoolInterface以及NullLogger作为LoggerInterface。

Tranport 类本身实现了 PSR-18HttpAsyncClient 接口,这意味着您可以使用它通过 Tranport::sendRequest() 函数发送任何 HTTP 请求,如下所示

use Http\Discovery\Psr17FactoryDiscovery;

$factory = Psr17FactoryDiscovery::findRequestFactory();
$request = $factory->createRequest('GET', '/info'); // PSR-7 request
$response = $transport->sendRequest($request);
var_dump($response); // PSR-7 response

sendRequest 函数将使用 $request 将 HTTP 请求发送到前面示例代码中指定的 localhost:9200 节点。这种行为可以用来仅指定 HTTP 请求中的 URL 路径,主机将在运行时使用 NodePool 实现来选择。

注意:如果您发送一个包含已指定主机的 $request,则 Transport 将使用它,而不会使用 NodePool 来选择在 TransportBuilder::setHosts() 设置中指定的节点。

例如,以下示例将向 domain 发送 /info 请求,而不是 localhost

use Elastic\Transport\TransportBuilder;

$transport = TransportBuilder::create()
    ->setHosts(['localhost:9200'])
    ->build();

$request = new Request('GET', 'https://domain.com/info');
$response = $transport->sendRequest($request); // the HTTP request will be sent to domain.com

echo $transport->lastRequest()->getUri()->getHost(); // domain.com

异步请求

您可以使用 Transport::sendAsyncRequest() 发送异步 HTTP 请求,如下所示

use Http\Discovery\Psr17FactoryDiscovery;

$factory = Psr17FactoryDiscovery::findRequestFactory();
$request = $factory->createRequest('GET', '/info'); // PSR-7 request
$promise= $transport->sendAsyncRequest($request);
var_dump($promise); // Promise
var_dump($promise->wait()); // PSR-7 response

$promise 包含一个 Promise 对象。Promise 是一个不会阻塞 PHP 执行的对象。这意味着 Promise 不包含 HTTP 响应。为了读取 HTTP 响应,您需要使用 wait() 函数。

使用 Promise 的另一种方法是指定在 HTTP 请求成功和失败时调用的函数。这可以通过 then() 函数实现,如下所示

$promise->then(function (ResponseInterface $response) {
    // onFulfilled callback, $reponse is PSR-7
    echo 'The response is available';

    return $response;
}, function (Exception $e) {
    // onRejected callback
    echo 'An error happens';

    throw $e;
});

有关 Promise 对象的更多信息,您可以阅读 HTTPlug 的 文档

设置重试次数

您可以指定任何 HTTP 请求的重试次数。这意味着如果 HTTP 请求失败,客户端将自动尝试执行另一个请求(或更多)。

默认情况下,重试次数为零(0)。如果您想更改它,可以使用 Transport::setRetries() 函数,如下所示

use Elastic\Transport\TransportBuilder;

$transport = TransportBuilder::create()
    ->setHosts([
        '10.0.0.10:9200',
        '10.0.0.20:9200',
        '10.0.0.30:9200'
    ])
    ->build();

$transport->setRetries(1);
$factory = Psr17FactoryDiscovery::findRequestFactory();
$request = $factory->createRequest('GET', '/info'); 
// If a node is down, the transports retry automatically using another one 
$response = $transport->sendRequest($request); 

此功能对于重试机制特别有趣,尤其是在您有节点集群时。您可以在以下关于 Node Pool 的部分中阅读有关如何配置集群环境中的节点选择的信息。

节点池

SimpleNodePoolTranposrt 使用的默认节点池算法。它使用以下默认值:将 RoundRobin 作为 SelectorInterface,将 NoResurrect 作为 ResurrectInterface

Round-robin 算法按顺序选择节点,从数组的第一个节点到最后一个节点。当到达最后一个节点时,它将从第一个节点开始。

* 注意:节点的顺序将在运行时随机化,以最大限度地利用所有主机。

NoResurrect 选项不会尝试复活被标记为已死的节点。例如,使用 Elasticsearch,您可以使用 HEAD / API 尝试复活一个已死的节点。如果您想使用这种行为,可以使用 ElasticsearchResurrect 类。

使用自定义选择器

您可以在创建 NodePoolInterface 实例时指定 SelectorInterface 实现。例如,假设您实现了 CustomSelector 和自定义 CustomResurrect,您可以使用它如下

use Elastic\Transport\NodePool\SimpleNodePool;
use Elastic\Transport\TransportBuilder;

$nodePool = new SimpleNodePool(
    new CustomSelector(),
    new CustomResurrect()
);

$transport = TransportBuilder::create()
    ->setHosts(['localhost:9200'])
    ->setNodePool($nodePool)
    ->build();

使用自定义PSR-3日志记录器

您可以使用TransportBuilder指定PSR-3 LoggerInterface实现。例如,如果您想使用monolog库,可以使用以下配置

use Elastic\Transport\TransportBuilder;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('name');
$logger->pushHandler(new StreamHandler('debug.log', Logger::DEBUG));

$transport = TransportBuilder::create()
    ->setHosts(['localhost:9200'])
    ->setLogger($logger)
    ->build();

使用自定义PSR-18客户端

您可以使用TransportBuilder::setClient()函数指定PSR-18客户端。例如,如果您想使用Symfony HTTP Client,可以使用以下配置

use Elastic\Transport\TransportBuilder;
use Symfony\Component\HttpClient\Psr18Client;

$transport = TransportBuilder::create()
    ->setHosts(['localhost:9200'])
    ->setClient(new Psr18Client)
    ->build();

如介绍中所述,我们使用HTTPlug库来自动发现PSR-18客户端。

您可以使用TransportBuilder::setClient()手动指定客户端,例如,如果您已安装多个HTTP客户端库。

默认情况下,如果PSR-18客户端实现了HttpAsyncClient接口,则在调用Transport::sendAsyncRequest()时将使用它。如果您想,可以使用Transport::setAsyncClient()函数覆盖此设置。这意味着您可以使用PSR-18客户端进行同步请求,并为异步请求使用不同的HttpAsyncClient客户端。

OpenTelemetry

从v8.9.0版本开始,我们引入了对HTTP发送请求的OpenTelemetry支持。目前,该支持仅适用于同步HTTP调用。

要启用OpenTelemetry,您需要将ENV变量OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_ENABLED设置为true。

我们在Transport:sendRequest()函数中本地添加了对OpenTelemetry的支持。默认情况下,Transport从一个Tracer提供程序(例如Global)创建一个带有以下属性的span

http.request.method
url.full
server.address
server.port

我们还为Transport:sendRequest()添加了一个$opts数组作为第二个可选参数,用于传递给OTel仪器化的额外属性。

我们创建了一个OpenTelemetry类来提供所有配置。

版权和许可

版权所有 (c) Elasticsearch B.V

本软件受MIT许可协议许可。有关更多信息,请参阅LICENSE文件。