erikwang2013/consul-php
📝 2.8k 字
·
⏱️ 13 分钟
阅读 0 次 👀
erikwang2013/consul-php
PHP Consul 客户端,完整覆盖 Consul HTTP API v1,重点支持服务注册发现与配置中心。核心包零框架依赖,内置 Laravel / Hyperf / webman / ThinkPHP 适配,一个 composer require 即可在任何框架下使用。
PHP 8.0+ · PSR-18/PSR-3/PSR-14/PSR-16 · 零框架依赖
文档导航
框架集成一览
|
Laravel |
Hyperf |
webman |
ThinkPHP |
| 扩展包 |
内置 |
内置 |
内置 |
内置 |
| 注入方式 |
自动发现 + ServiceProvider |
自动发现 + ConfigProvider |
手动 new / 插件 |
手动 bind 到容器 |
| 便捷访问 |
Consul Facade |
#[Inject] 注解 |
— |
app('consul') 助手 |
| 配置位置 |
config/consul.php |
config/autoload/consul.php |
config/plugin/erikwang2013/consul-php/app.php |
config/consul.php |
| HTTP 客户端 |
Guzzle (PSR-18) |
Swoole 协程客户端 |
Guzzle (PSR-18) |
Guzzle (PSR-18) |
| 缓存 |
Laravel Cache (PSR-16) |
Hyperf Cache (PSR-16) |
自行注入 |
自行注入 |
| 热更新运行 |
Artisan 命令 |
AbstractProcess 协程 |
Worker 进程 |
Timer / Swoole 进程 |
| 事件监听 |
EventServiceProvider |
Hyperf Event |
— |
ThinkPHP Listener |
| 文档 |
源码 |
源码 |
源码 |
源码 |
同一操作,不同写法
获取客户端:
| 框架 |
写法 |
| 通用 |
$client = new ConsulClient(['base_uri' => '...']); |
| Laravel |
$client = app(ConsulClient::class); 或 Consul::kv->get(...) |
| Hyperf |
#[Inject] private ConsulClient $consul; |
| webman |
$client = new ConsulClient(['base_uri' => '...']); |
| ThinkPHP |
$client = app('consul'); |
服务注册:
1 2 3 4 5 6
| $client->serviceRegistry()->register('my-app', '10.0.0.1', 8080, [ 'id' => 'my-app-1', 'tags' => ['v1'], 'check' => ['ttl' => '30s'], ]);
|
配置读取:
1 2
| $dbHost = $client->configCenter()->get('app/db_host', 'default');
|
热更新运行方式:
| 框架 |
启动命令 / 方式 |
运行环境 |
| Laravel |
php artisan consul:watch |
独立 Artisan 进程 |
| Hyperf |
ConsulWatchProcess (自动启动) |
Swoole 协程 |
| webman |
在 onWorkerStart 中 fork |
Worker 进程 |
| ThinkPHP |
Timer::setInterval / Swoole Process |
独立进程 |
安装
1 2 3 4 5
| composer require erikwang2013/consul-php
composer require guzzlehttp/guzzle php-http/guzzle7-adapter php-http/discovery
|
框架集成
框架适配已内置在核心包中,无需额外安装。安装核心包后,对应框架会自动发现并注册 Consul 服务:
- Laravel — 自动发现
ConsulServiceProvider,提供 Consul Facade 和依赖注入
- Hyperf — 自动发现
ConfigProvider,提供协程客户端工厂和 #[Inject] 注入
- webman — 自动发现插件,
composer install 时自动复制配置文件
- ThinkPHP — 在
app/service 目录下创建 ConsulService 并注册到应用
快速开始(通用)
1 2 3 4 5 6 7 8 9 10
| use Erikwang2013\Consul\Client\ConsulClient;
$client = new ConsulClient(['base_uri' => 'http://127.0.0.1:8500']);
$client = new ConsulClient([ 'base_uri' => 'http://127.0.0.1:8500', 'token' => 'your-consul-acl-token', ]);
|
Token 会自动通过 X-Consul-Token 请求头附加到所有请求中。
服务注册
支持 TTL、HTTP、TCP、gRPC 四种健康检查模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| $registry = $client->serviceRegistry();
$registry->register('user-service', '192.168.1.10', 8080, [ 'id' => 'user-service-1', 'tags' => ['v1', 'primary'], 'meta' => ['region' => 'cn-east'], 'check' => [ 'ttl' => '30s', 'deregister_critical_service_after' => '120s', // 心跳超时自动注销 ], ]);
$registry->register('web', '192.168.1.10', 80, [ 'id' => 'web-1', 'check' => [ 'http' => 'http://192.168.1.10:80/health', 'interval' => '10s', 'timeout' => '3s', ], ]);
$registry->register('mysql', '192.168.1.10', 3306, [ 'check' => ['tcp' => '192.168.1.10:3306', 'interval' => '10s'], ]);
$registry->register('grpc-svc', '192.168.1.10', 50051, [ 'check' => ['grpc' => '192.168.1.10:50051', 'interval' => '10s'], ]);
$registry->heartbeat('user-service-1');
$registry->deregister('user-service-1');
|
服务发现
内置 RoundRobin(默认)和 Random 两种负载均衡策略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| $discovery = $client->serviceDiscovery();
$instances = $discovery->healthyInstances('user-service');
$instance = $discovery->selectInstance('user-service');
use Erikwang2013\Consul\Service\LoadBalancer\Random; $discovery = new Discovery($health, loadBalancer: new Random());
$discovery->watch('user-service', function (array $instances) { });
$discovery->stop();
|
配置中心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| $config = $client->configCenter();
$dbHost = $config->get('app/db_host', 'localhost');
$all = $config->namespace('app/');
$config->set('app/cache_ttl', '3600'); $config->delete('app/old_key');
$watcher = $config->watch('app/'); $watcher ->setBlockingWait(30) ->setPollInterval(10) ->onChange(function (array $updated) { }); $watcher->start();
|
热更新原理: 优先 Consul blocking query(index 长轮询),网络异常时自动降级为定时轮询,连接恢复后自动切回长轮询。回调 + PSR-14 EventDispatcher 双通道通知。
缓存策略: 注入 PSR-16 缓存后,get() 和 namespace() 自动读写缓存。Watcher 始终读 Consul 实时数据,不走缓存。
KV 存储
1 2 3 4 5 6 7 8
| $kv = $client->kv;
$kv->put('key', 'value'); $entry = $kv->get('key'); $all = $kv->all('prefix/'); $keys = $kv->keys('prefix/'); $keys = $kv->keys('prefix/', '/'); $kv->delete('key');
|
健康检查 API
1 2 3 4 5 6
| $health = $client->health;
$health->service('user-service', ['passing' => true]); $health->node('node-1'); $health->checks('user-service'); $health->state('critical');
|
Session / 分布式锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $session = $client->session;
$sess = $session->create([ 'Name' => 'lock-session', 'TTL' => '30s', 'Behavior' => 'delete', // 过期自动删除关联 KV ]); $sessionId = $sess['ID'];
$locked = $client->kv->put('lock/resource', '1', ['acquire' => $sessionId]);
$session->renew($sessionId); $session->destroy($sessionId);
|
ACL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $acl = $client->acl;
$token = $acl->tokenCreate(['Description' => 'read-only', 'Policies' => [['Name' => 'read-policy']]]); $acl->tokenRead($token['AccessorID']); $acl->tokenDelete($token['AccessorID']);
$policy = $acl->policyCreate(['Name' => 'my-policy', 'Rules' => 'node "" { policy = "read" }']);
$role = $acl->roleCreate(['Name' => 'reader', 'Policies' => [['Name' => 'my-policy']]]);
$result = $acl->login(['AuthMethod' => 'my-auth', 'BearerToken' => '...']); $acl->logout();
|
异步客户端
1 2 3 4 5 6 7 8 9 10 11
| use Erikwang2013\Consul\Client\ConsulAsyncClient;
$client = new ConsulAsyncClient(['base_uri' => 'http://127.0.0.1:8500']);
$promise = $client->wrap(fn() => $client->kv->get('key'));
$promise ->then(fn($result) => print_r($result)) ->catch(fn(\Throwable $e) => log_error($e));
$value = $promise->wait();
|
注意: 异步客户端基于 Promise 模式,适用于需要并发请求的场景。Hyperf 协程环境中默认的 HTTP 客户端即可实现协程级并发。
各框架集成指南
Laravel
Laravel 自动发现 ConsulServiceProvider,无需手动注册。
1
| php artisan vendor:publish --tag=consul-config
|
.env 中设置 CONSUL_BASE_URI,之后即可通过依赖注入或 Facade 使用。Laravel 扩展自动注入 PSR-18 客户端、PSR-16 缓存、PSR-3 日志和 PSR-14 事件分发器。
1 2 3 4 5 6 7 8 9 10
| use Erikwang2013\Consul\Client\ConsulClient; public function show(ConsulClient $consul) { ... }
use Consul; $services = Consul::catalog->services();
|
Hyperf
Hyperf 自动发现 ConfigProvider,无需手动注册。
1
| php bin/hyperf.php vendor:publish consul
|
Hyperf 扩展自动注册 ConsulClient 到 DI 容器,HTTP 请求默认使用 Swoole 协程客户端。服务注册建议放在 MainServerStart 事件监听中,热更新使用 AbstractProcess 在协程中运行。
1 2 3 4 5 6 7 8
| #[Inject] private ConsulClient $consul;
$consul->serviceRegistry()->register(...);
|
webman
webman 自动发现插件,composer install 时自动复制配置文件到 config/plugin/erikwang2013/consul-php/。由于 webman 是常驻内存架构,服务注册放在 onWorkerStart 回调中,全局只需注册一次。
1 2 3 4 5 6 7
| class ConsulRegister { public function onWorkerStart(Worker $worker): void { $consul = new ConsulClient(['base_uri' => getenv('CONSUL_BASE_URI')]); $consul->serviceRegistry()->register('webman-app', ...); } }
|
ThinkPHP
ThinkPHP 无自动发现机制,需手动注册 Service。将配置文件复制到 config/consul.php,然后在 app/service 目录下注册 ConsulService:
1 2 3 4 5 6 7 8
| namespace app\service;
use Erikwang2013\Consul\Integration\Thinkphp\ConsulService as BaseConsulService;
class ConsulService extends BaseConsulService { }
|
或在 app/AppService.php 中直接绑定:
1 2 3 4 5 6 7
| $this->app->bind('consul', fn() => new ConsulClient(config('consul')));
$services = app('consul')->catalog->services();
function consul() { return app('consul'); }
|
自定义 HTTP 客户端
1 2 3 4 5 6 7 8 9
| $client = new ConsulClient( config: ['base_uri' => 'http://consul:8500', 'token' => 'acl-token'], httpClient: $myPsr18Client, requestFactory: $myRequestFactory, streamFactory: $myStreamFactory, logger: $myLogger, cache: $myCache, eventDispatcher: $myEventDispatcher, );
|
API 模块速查
| 属性 |
类 |
主要方法 |
$client->kv |
Api\Kv |
get put delete all keys |
$client->agent |
Api\Agent |
members self registerService deregisterService checks services |
$client->catalog |
Api\Catalog |
register deregister nodes services service node |
$client->health |
Api\Health |
service node checks state |
$client->session |
Api\Session |
create destroy renew info all node |
$client->acl |
Api\Acl |
token* policy* role* authMethod* login logout bootstrap |
$client->event |
Api\Event |
fire list |
$client->status |
Api\Status |
leader peers |
$client->coordinate |
Api\Coordinate |
datacenters nodes node |
$client->operator |
Api\Operator |
raftConfig autopilotConfig keyring(常量:KEYRING_LIST KEYRING_INSTALL KEYRING_USE KEYRING_REMOVE) |
$client->snapshot |
Api\Snapshot |
save(返回原始快照字节,通过 getRaw()) restore(发送原始字节,通过 putRaw()) |
高层封装:
| 方法 |
返回 |
说明 |
$client->serviceRegistry() |
Service\Registry |
服务注册/心跳/下线 |
$client->serviceDiscovery() |
Service\Discovery |
实例列表/负载均衡/变更监听 |
$client->configCenter() |
Config\ConfigCenter |
配置读写/缓存/热更新 |
异常体系
所有异常继承 ConsulException(继承 RuntimeException):
1 2 3 4 5 6
| ConsulException ├── ClientException HTTP 传输错误(连接失败、DNS、超时等) ├── ServerException Consul 返回 5xx └── ConsulRequestException Consul 返回 4xx ├── NotFoundException 404 └── AccessDeniedException 403
|
1 2 3 4 5 6 7 8 9
| try { $client->kv->get('key'); } catch (ClientException $e) { } catch (NotFoundException $e) { } catch (ConsulException $e) { }
|
架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ┌─────────────────────────────────────┐ │ ConsulClient │ ← 统一入口(同步 + 异步) ├─────────────────────────────────────┤ │ Service\Registry │ Config\Config │ ← 高层封装 │ Service\Discovery│ Center │ ├─────────────────────────────────────┤ │ Api\Agent │ Api\Kv │ Api\Health │ ← API 模块(11 个) │ Api\Catalog │ Api\Session │ ... │ ├─────────────────────────────────────┤ │ Transport\Psr18Transport │ ← PSR-18 传输层 │ get/put/post/delete + getRaw │ Token 注入 · Header 捕获 │ putRaw + getWithHeaders │ 状态码检查 · JSON 解码 ├─────────────────────────────────────┤ │ PSR-18 Client │ PSR-17 Factory │ ← 用户注入 / 自动发现 └─────────────────────────────────────┘
|
最低要求
- PHP 8.0+
- Composer
- PSR-18 HTTP Client 实现
- [可选] PSR-16 缓存 —
Discovery::healthyInstances() / ConfigCenter::get() 自动缓存
- [可选] PSR-3 Logger — 请求日志
- [可选] PSR-14 EventDispatcher —
ConfigChangedEvent 事件
开源不易,欢迎支持
| 微信 |
支付宝 |
 |
 |
License
MIT