后端Web框架微服务RPC框架异步编程【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/hyperf/hyperf点击查看免费下载本文以 hyperf/elasticsearch 组件为核心讲解如何在 Hyperf 框架中优雅地创建 Elasticsearch 客户端通过ClientBuilderFactory工厂类自动接入协程版 HTTP Handler彻底解决阻塞问题同时覆盖手动创建客户端、连接池调优、用户名密码认证等实战细节。读完本文你将掌握在 Hyperf 协程环境下安全、高效地调用 Elasticsearch 的完整方案。组件定位为 elasticsearch-php 套上协程外壳Elasticsearch 官方 PHP 客户端 elasticsearch-php 默认使用基于Guzzle Ring的客户端进行 HTTP 通信而 Guzzle 的传统实现依赖同步阻塞的 cURL 调用。在 Swoole/Swow 协程环境下一次同步网络请求就会阻塞整个 Worker 进程导致并发能力急剧下降。hyperf/elasticsearch组件正是为解决这一问题而生它在 hyperf/guzzle 组件提供的协程版Handler基础上对 elasticsearch-php 的客户端对象创建过程做了工厂类封装。从 composer.json 可以看出组件要求 PHP 8.2支持elasticsearch/elasticsearch的^8.0 || ^9.0版本并依赖hyperf/guzzle~3.2.0。其核心思路是在协程环境中创建客户端时自动替换为协程版 Handler在非协程环境下则保持官方默认行为不变。这样开发者无需关心底层传输细节同一份业务代码在两种环境下都能正确运行。安装在项目根目录执行 Composer 命令安装组件composer require hyperf/elasticsearch安装完成后即可在 Hyperf 应用中通过依赖注入容器ContainerInterface获取工厂类并使用。使用ClientBuilderFactory创建客户端推荐最简单的方式是直接从容器中取出Hyperf\Elasticsearch\ClientBuilderFactory调用其create()方法获得一个Elasticsearch\ClientBuilder实例?php use Hyperf\Elasticsearch\ClientBuilderFactory; // 如果在协程环境下创建则会自动使用协程版的 Handler非协程环境下无改变 $builder $this-container-get(ClientBuilderFactory::class)-create(); $client $builder-setHosts([http://127.0.0.1:9200])-build(); $info $client-info();这段代码完成了三件事get(ClientBuilderFactory::class)从 Hyperf 依赖注入容器中解析工厂类框架会自动完成构造参数的注入create()内部调用 elasticsearch-php 官方的Elasticsearch\ClientBuilder::create()创建 Builder并自动注入协程化后的 Guzzle HTTP 客户端setHosts()-build()配置 Elasticsearch 节点地址列表并构建出正式客户端随后即可像使用官方客户端一样调用info()、search()、index()等任意方法。底层实现自动注入协程 HTTP 客户端查看 ClientBuilderFactory.php 的源码可以清楚地看到工厂的工作方式class ClientBuilderFactory { protected ?GuzzleClientFactory $guzzleClientFactory null; public function __construct(protected ContainerInterface $container) { if ($container-has(GuzzleClientFactory::class)) { $this-guzzleClientFactory $container-get(GuzzleClientFactory::class); } } public function create(): ClientBuilder { $builder ClientBuilder::create(); $this-guzzleClientFactory $builder-setHttpClient( $this-guzzleClientFactory-create() ); return $builder; } }关键点有两个构造函数中检测容器中是否存在Hyperf\Guzzle\ClientFactory存在则取出备用create()时若存在该工厂就通过setHttpClient()将协程版 Guzzle 客户端注入 Builder。而Hyperf\Guzzle\ClientFactory::create()的实现见 ClientFactory.php会判断运行环境当扩展swoole已加载、当前处于协程上下文、且 Swoole 原生 cURL Hook 未开启时使用CoroutineHandler构建 GuzzleHandlerStack从而让所有 HTTP 请求都在协程中完成不阻塞进程否则退化为原生 Guzzle 行为。对应地组件的单元测试见 ClientFactoryTest.php验证了两点create()返回的是Elasticsearch\ClientBuilder实例当连接的节点不可达时http://127.0.0.1:9201调用info()会抛出Elastic\Transport\Exception\NoNodeAvailableException——这是排查连接问题的关键线索。自行创建客户端不依赖工厂如果你希望完全手动控制客户端的构建过程也可以绕开工厂类直接使用 elasticsearch-php 官方的ClientBuilder并手动接入 Hyperf 的连接池 Handler?php use Elasticsearch\ClientBuilder; use Hyperf\Guzzle\RingPHP\PoolHandler; use Swoole\Coroutine; $builder ClientBuilder::create(); if (Coroutine::getCid() 0) { $handler make(PoolHandler::class, [ option [ max_connections 50, ], ]); $builder-setHandler($handler); } $client $builder-setHosts([http://127.0.0.1:9200])-build(); $info $client-info();这段代码中的Coroutine::getCid() 0用于判断当前是否处于协程上下文getCid()返回当前协程 ID主上下文返回 -1 或 0。只有处于协程中时才需要也才应当替换为协程 Handler从而保证在传统 PHP-FPM 环境下也能安全运行。理解PoolHandler与RingPHP\PoolHandler注意由于 elasticsearch-php 的传输层在不同版本间存在差异hyperf/guzzle 同时提供了两套协程 HandlerHyperf\Guzzle\RingPHP\PoolHandler面向基于GuzzleHttp\Ring的传输层即 elasticsearch-php 旧版默认使用的 Ring 客户端也就是上文示例中所引用的类Hyperf\Guzzle\PoolHandler面向 Guzzle 7 的 Promise 风格 Handler。从 RingPHP/PoolHandler.php 源码可以看到该类继承自协程版CoroutineHandler其__invoke()内部按照host:port维度池名为guzzle.ring.handler.{host}.{port}从PoolFactory获取连接池从池中取出连接发起请求并在finally中释放连接。换言之同一 host:port 的请求会复用连接池中的 TCP 连接避免频繁建连带来的开销。连接池的可用配置项option数组可参考 Pool.php 中的initOption()实现包含配置项默认值含义min_connections1连接池最小连接数max_connections10连接池最大连接数connect_timeout10.0建立连接的超时时间秒wait_timeout3.0从池中获取连接的最大等待时间秒heartbeat-1心跳间隔-1 表示不启用max_idle_time60.0连接最大空闲时间秒超过后会被回收此外hyperf/guzzle 还提供了HandlerStackFactory见 HandlerStackFactory.php其默认池参数为min_connections 1、max_connections 30、wait_timeout 3.0、max_idle_time 60并内置了retry中间件重试 1 次、间隔 10ms可作为构建 Guzzle 客户端时的高阶参考。协程 Handler 的传输细节如果你使用非池化的Hyperf\Guzzle\RingPHP\CoroutineHandler每次请求都会新建连接。其内部见 RingPHP/CoroutineHandler.php直接基于Hyperf\Engine\Http\Client发起请求并做了几件对 Elasticsearch 场景很重要的事情从CURLOPT_USERPWD提取用户名密码并自动生成Authorization: Basic xxx请求头对应官方客户端通过client[curl][CURLOPT_USERPWD]传参的认证方式主动移除Content-Length请求头源码注释说明该头在某些场景会导致 400 错误支持timeout、delay等传输选项的透传。如何设置用户名密码当 Elasticsearch 服务需要认证时例如购买了阿里云 Elasticsearch 企业版等托管服务无需编写额外的认证逻辑直接把用户名密码以标准 URL 形式拼入 host 即可http://username:passwordxxxx.aliyuncs.com:9200将该地址传入setHosts()客户端便会使用 Basic Auth 访问搜索引擎。这一机制在协程 Handler 中得到天然支持如上文所述CoroutineHandler::initHeaders()会读取 URI 中的 userinfo 部分并自动生成Authorization: Basic ...请求头见 CoroutineHandler.php 中initHeaders()的实现因此无论是通过工厂创建还是手动创建客户端认证都能正常工作。在业务代码中的典型用法由于ClientBuilderFactory是标准的 PSR 容器服务你可以把它注入到任意业务类中。以下是一个结合构造函数依赖注入的完整示例?php namespace App\Service; use Hyperf\Elasticsearch\ClientBuilderFactory; use Elastic\Elasticsearch\Client; class SearchService { protected Client $client; public function __construct(ClientBuilderFactory $clientBuilderFactory) { $this-client $clientBuilderFactory -create() -setHosts([env(ELASTICSEARCH_HOST, http://127.0.0.1:9200)]) -build(); } public function search(string $keyword): array { return $this-client-search([ index articles, body [ query [ match [title $keyword], ], ], ])-asArray(); } }与 Scout 等组件的联动ClientBuilderFactory不仅在业务代码中可以直接使用Hyperf 的hyperf/scout全文搜索组件也复用了它。查看 ElasticsearchProvider.php 可以发现Scout 的 Elasticsearch 驱动正是通过$this-container-get(ClientBuilderFactory::class)-create()创建 Builder再从配置中读取scout.engine.{name}.hosts和scout.engine.{name}.index完成客户端构建。对应的默认配置见 scout.phpengine [ elasticsearch [ driver ElasticsearchProvider::class, index null, hosts [ env(ELASTICSEARCH_HOST, http://127.0.0.1:9200), ], ], ],这说明凡是需要 Elasticsearch 客户端的组件都可以通过ClientBuilderFactory统一获得协程安全的客户端实例这是 Hyperf 生态中处理 Elasticsearch 连接的标准姿势。小结与最佳实践综合文档与源码在 Hyperf 中使用 Elasticsearch 的推荐路径可以总结为首选工厂方式container-get(ClientBuilderFactory::class)-create()自动获得协程 Handler非协程环境自动降级无需任何条件判断手动方式注意两点用Coroutine::getCid() 0判断协程环境在协程中使用PoolHandler并合理设置max_connections等连接池参数以复用连接、降低建连开销认证直接使用http://username:passwordhost:9200形式的 host协程 Handler 会自动生成 Basic Auth 头排查连接问题节点不可达时客户端会抛出NoNodeAvailableException可从 ClientFactoryTest.php 的测试用例中了解其触发条件集成生态构建 Elasticsearch 客户端统一走ClientBuilderFactory无论是业务代码还是 Scout 等组件都能获得一致、协程安全的传输行为。赞分享后端Web框架微服务RPC框架异步编程【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/hyperf/hyperf点击查看免费下载相关推荐Hyperf 集成 Elasticsearch 客户端协程化 ClientBuilderFactory 使用与连接池实战指南Hyperf 集成 Elasticsearch 客户端协程化 ClientBuilderFactory 使用与连接池实战指南 本篇技术指南围绕 Hyperf后端微服务Hyperf Elasticsearch 客户端实战基于协程 Handler 的工厂封装与连接池配置Hyperf Elasticsearch 客户端实战基于协程 Handler 的工厂封装与连接池配置 本指南围绕 hyperf/elasticsearch 组后端微服务Hyperf 协程环境下的 Elasticsearch 客户端接入指南ClientBuilderFactory 使用与连接池调优Hyperf 协程环境下的 Elasticsearch 客户端接入指南ClientBuilderFactory 使用与连接池调优 导读 本篇指南围绕 Hype后端Web框架微服务RPC框架异步编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考