chenbool/etcd

Etcd v3 PHP Client - Service registration and discovery

Maintainers

Package info

github.com/chenbool/etcd-php

pkg:composer/chenbool/etcd

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-05-09 07:08 UTC

This package is auto-updated.

Last update: 2026-05-09 07:11:02 UTC


README

基于 Etcd v3 HTTP API 的 PHP 客户端,提供服务注册、发现、KV 存储等功能

PHP License

目录

特性

特性 说明
服务注册 自动租约续期
服务发现 随机负载均衡
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 = 2379
string $prefix = '/services/'
int $ttl = 30
void 创建 Etcd 实例

服务注册

方法 参数 返回 说明
register() string $serviceName
string $host
int $port
array $metadata = []
bool 注册服务到 Etcd
registerWithCallback() string $serviceName
string $host
int $port
array $metadata = []
?callable $onSuccess = null
?callable $onError = null
bool 带回调注册服务
deregister() string $serviceName
string $host
int $port
bool 注销服务

服务发现

方法 参数 返回 说明
discover() string $serviceName array 发现指定服务的所有实例
discoverAll() - array 发现所有已注册服务,按服务名分组
call() string $serviceName
$request = ''
array $extraParams = []
array 调用远程服务,随机负载均衡

心跳与租约

方法 参数 返回 说明
heartbeat() array $services
int $interval = 25
?callable $onBeat = null
void 启动定时心跳
refreshLease() int $leaseId bool 刷新单个租约
refreshAllServicesLease() array $services
int $interval = 60
void 刷新所有服务租约

KV 存储

方法 参数 返回 说明
kvPut() string $key
string $value
array $options = []
bool 存储键值对
options 支持: lease
get() string $key
array $options = []
?string 获取值
options 支持: revision
getAllKeys() - array 获取所有键
getKeysWithPrefix() string $prefix array 获取前缀匹配的键
del() string $key
array $options = []
bool 删除键
options 支持: range_end
compaction() int $revision bool 压缩存储,清理历史版本

工具方法

方法 参数 返回 说明
parseRequest() $request array 解析请求参数
返回 ['path' => string, 'data' => array]
getServiceHealth() - bool 检查 Etcd 健康状态

协议

MIT License