chenbool / etcd
Etcd v3 PHP Client - Service registration and discovery
dev-main
2026-05-09 07:08 UTC
Requires
- php: >=7.4
- guzzlehttp/guzzle: ^6.0 || ^7.0
This package is auto-updated.
Last update: 2026-05-09 07:11:02 UTC
README
基于 Etcd v3 HTTP API 的 PHP 客户端,提供服务注册、发现、KV 存储等功能
目录
特性
| 特性 | 说明 |
|---|---|
| 服务注册 | 自动租约续期 |
| 服务发现 | 随机负载均衡 |
| KV 存储 | 完整的 CRUD 操作 |
| 心跳保活 | 定时刷新租约 |
| 健康检查 | Etcd 集群状态监控 |
安装
composer require guzzlehttp/guzzle
或直接引入:
require_once __DIR__ . '/extra/Etcd.php';
快速开始
use extra\Etcd; $etcd = new Etcd(); // 注册服务 $etcd->register('my-service', '127.0.0.1', 8080); // 发现服务 $services = $etcd->discover('my-service'); // 注销服务 $etcd->deregister('my-service', '127.0.0.1', 8080);
配置
构造函数
$etcd = new Etcd( '127.0.0.1', // host - Etcd 服务器地址 2379, // port - Etcd 端口 '/services/', // prefix - 服务注册 key 前缀 30 // ttl - 租约 TTL(秒) );
环境变量
构造函数参数支持环境变量覆盖
$etcd = new Etcd(); // 或通过环境变量: ETCD_HOST, ETCD_PORT, ETCD_PREFIX, ETCD_TTL
服务注册与发现
注册服务
$etcd = new Etcd(); // 基础注册 $etcd->register('user-api', '127.0.0.1', 8080); // 带元数据 $etcd->register('user-api', '127.0.0.1', 8080, [ 'version' => '1.0.0', 'region' => 'cn-beijing' ]); // 带回调 $etcd->registerWithCallback( 'user-api', '127.0.0.1', 8080, [], fn() => print "OK\n", fn($e) => print $e->getMessage() . "\n" );
发现服务
// 发现指定服务 $services = $etcd->discover('user-api'); /* 返回: [ ['host' => '127.0.0.1', 'port' => 8080, 'metadata' => [...], 'registered_at' => '...'], ['host' => '127.0.0.1', 'port' => 8081, ...] ] */ // 发现所有服务 $allServices = $etcd->discoverAll(); /* 返回: [ 'user-api' => [...], 'order-api' => [...] ] */
注销服务
$etcd->deregister('user-api', '127.0.0.1', 8080);
心跳与租约
启动心跳
$services = [ ['name' => 'user-api', 'host' => '127.0.0.1', 'port' => 8080], ['name' => 'order-api', 'host' => '127.0.0.1', 'port' => 8081], ]; // 每 25 秒重新注册 $etcd->heartbeat($services, 25, fn(string $name) => print "{$name} OK\n");
刷新租约
// 刷新单个租约 $etcd->refreshLease($leaseId); // 刷新所有服务租约(每 60 秒) $etcd->refreshAllServicesLease($services, 60);
KV 存储
基础操作
// 存储 $etcd->kvPut('/my/key', 'hello world'); $etcd->kvPut('/config/app', json_encode(['debug' => true])); $etcd->kvPut('/temp/key', 'value', ['lease' => $leaseId]); // 获取 $value = $etcd->get('/my/key'); $value = $etcd->get('/my/key', ['revision' => 10]); // 删除 $etcd->del('/my/key'); $etcd->del('/prefix/', ['range_end' => '/prefix0']);
键操作
// 获取所有键 $keys = $etcd->getAllKeys(); // 前缀匹配 $keys = $etcd->getKeysWithPrefix('/services/'); // 压缩存储 $etcd->compaction(100);
服务调用
// 字符串路径 $result = $etcd->call('user-api', '/api/user/1'); // 带参数 $result = $etcd->call('user-api', '/api/user', ['id' => 1]); // Request 对象 $result = $etcd->call('user-api', $request, ['extra' => 'param']); /* 成功返回: { "success": true, "data": { "service": "user-api", "target": "127.0.0.1:8080", "response": {...} } } 失败返回: { "success": false, "error": "错误信息", "target": "127.0.0.1:8080" } */
工具方法
解析请求参数
// 从 Request 对象解析 $parsed = Etcd::parseRequest($request); // 返回 ['path' => '/xxx', 'data' => [...]] // 从数组解析 $parsed = Etcd::parseRequest(['path' => '/api/user', 'data' => ['id' => 1]]);
健康检查
if ($etcd->getServiceHealth()) { echo "Etcd 服务正常"; }
完整示例
Webman
<?php namespace app\controller; use support\Request; use extra\Etcd; class IndexController { private static ?Etcd $etcd = null; private static function getEtcd(): Etcd { self::$etcd ??= new Etcd(); return self::$etcd; } public function index(Request $request) { $etcd = self::getEtcd(); $name = $request->get('service'); if ($name) { return json(['code' => 0, 'data' => ['instances' => $etcd->discover($name)]]); } return json(['code' => 0, 'data' => $etcd->discoverAll()]); } public function call(Request $request) { $etcd = self::getEtcd(); $result = $etcd->call($request->get('service', 'api'), $request); return $result['success'] ? json(['code' => 0, 'data' => $result['data']]) : json(['code' => 404, 'msg' => $result['error']]); } }
Workerman
<?php namespace app\process; use extra\Etcd; class EtcdRegister { private static ?Etcd $etcd = null; public static function init(array $config): void { $cfg = $config['etcd'] ?? []; self::$etcd = new Etcd( $cfg['host'] ?? '127.0.0.1', $cfg['port'] ?? 2379, $cfg['prefix'] ?? '/services/', $cfg['ttl'] ?? 30 ); foreach ($config['services'] ?? [] as $s) { self::$etcd->register($s['name'], $s['host'], $s['port']); } self::$etcd->heartbeat($config['services'] ?? []); } public static function getEtcd(): Etcd { return self::$etcd; } }
API 参考
构造方法
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
__construct() |
string $host = '127.0.0.1'int $port = 2379string $prefix = '/services/'int $ttl = 30 |
void |
创建 Etcd 实例 |
服务注册
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
register() |
string $serviceNamestring $hostint $portarray $metadata = [] |
bool |
注册服务到 Etcd |
registerWithCallback() |
string $serviceNamestring $hostint $portarray $metadata = []?callable $onSuccess = null?callable $onError = null |
bool |
带回调注册服务 |
deregister() |
string $serviceNamestring $hostint $port |
bool |
注销服务 |
服务发现
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
discover() |
string $serviceName |
array |
发现指定服务的所有实例 |
discoverAll() |
- | array |
发现所有已注册服务,按服务名分组 |
call() |
string $serviceName$request = ''array $extraParams = [] |
array |
调用远程服务,随机负载均衡 |
心跳与租约
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
heartbeat() |
array $servicesint $interval = 25?callable $onBeat = null |
void |
启动定时心跳 |
refreshLease() |
int $leaseId |
bool |
刷新单个租约 |
refreshAllServicesLease() |
array $servicesint $interval = 60 |
void |
刷新所有服务租约 |
KV 存储
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
kvPut() |
string $keystring $valuearray $options = [] |
bool |
存储键值对options 支持: lease |
get() |
string $keyarray $options = [] |
?string |
获取值options 支持: revision |
getAllKeys() |
- | array |
获取所有键 |
getKeysWithPrefix() |
string $prefix |
array |
获取前缀匹配的键 |
del() |
string $keyarray $options = [] |
bool |
删除键options 支持: range_end |
compaction() |
int $revision |
bool |
压缩存储,清理历史版本 |
工具方法
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
parseRequest() |
$request |
array |
解析请求参数 返回 ['path' => string, 'data' => array] |
getServiceHealth() |
- | bool |
检查 Etcd 健康状态 |
协议
MIT License