PHP code example of erikwang2013 / etcd
1. Go to this page and download the library: Download erikwang2013/etcd library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
erikwang2013 / etcd example snippets
use Erikwang2013\Etcd\EtcdClient;
$etcd = new EtcdClient(['endpoints' => ['127.0.0.1:2379']]);
// 写入
$etcd->kv()->put('/app/config', '{"debug":true}');
// 读取
$result = $etcd->kv()->get('/app/config');
print_r($result['kvs'][0]); // ['key' => '/app/config', 'value' => '{"debug":true}', ...]
// 找不到时抛异常
$kv = $etcd->kv()->getOrFail('/app/config');
// 前缀扫描
$all = $etcd->kv()->getByPrefix('/app/');
echo "共 {$all['count']} 条\n";
// 删除
$etcd->kv()->delete('/app/config');
$etcd->kv()->deleteByPrefix('/cache/');
// 带租约写入(60 秒后自动删除)
$lease = $etcd->lease()->grant(60);
$etcd->kv()->put('/session/123', 'active', ['lease' => $lease['ID']]);
// 续约
$etcd->lease()->keepAlive($lease['ID']);
$etcd = new EtcdClient([
'endpoints' => ['192.168.1.10:2379', '192.168.1.11:2379'], // 多节点
'transport' => 'auto', // auto(默认)| http | grpc
'timeout' => 5.0, // 秒
'retry' => 3, // 连接失败重试次数
'auth' => [ // 可选,Basic Auth
'user' => 'root',
'password' => 'secret',
],
]);
// 写入
$etcd->kv()->put('key', 'value', [
'lease' => 12345, // 绑定租约 ID
'prevKv' => true, // 返回写入前的旧值
'ignoreValue' => false,
'ignoreLease' => false,
]);
// 读取单键
$etcd->kv()->get('/exact/key');
// 找不到即抛异常
$kv = $etcd->kv()->getOrFail('/exact/key');
// 前缀扫描
$etcd->kv()->getByPrefix('/prefix/');
// 范围查询(完整参数)
$etcd->kv()->get('/start', [
'rangeEnd' => '/startz', // 范围结束 key
'limit' => 100, // 最大返回条数
'revision' => 42, // 快照版本号
'sortOrder' => 'ascend', // none | ascend | descend
'sortTarget' => 'key', // key | version | create | mod | value
'serializable'=> true, // 跳过 Raft 共识(更快,可能过期)
'keysOnly' => true, // 只返回 key,不返回 value
'countOnly' => false, // 只返回计数
]);
// 删除
$etcd->kv()->delete('/key');
$etcd->kv()->deleteByPrefix('/prefix/');
$etcd->kv()->delete('/key', ['prevKv' => true]); // 同时返回被删的值
// 事务(原子 CAS)
$etcd->kv()->txn(
compare: [
['result' => 0, 'target' => 3, 'key' => '/counter', 'value' => '100']
],
success: [
['request_put' => ['key' => '/counter', 'value' => '101']]
],
failure: [
['request_put' => ['key' => '/counter', 'value' => '1']]
]
);
// 压缩历史版本(释放存储空间)
$etcd->kv()->compact(1000);
// 监听单个 key(阻塞模式,建议在协程/独立进程中运行)
$etcd->watch()->watch('/config/key', function (array $events) {
foreach ($events as $event) {
// $event: ['type' => 'PUT'|'DELETE', 'kv' => [...], 'prev_kv' => [...]|null]
echo "{$event['type']} {$event['kv']['key']} = {$event['kv']['value']}\n";
}
});
// 监听前缀下所有 key 的变更
$etcd->watch()->watchPrefix('/config/', $callback, [
'startRevision' => 100, // 从指定版本开始
'prevKv' => true, // DELETE 事件返回原值
'progressNotify'=> true, // 定期发送空事件(心跳)
]);
// 创建租约
$lease = $etcd->lease()->grant(300); // 300 秒 TTL
$lease = $etcd->lease()->grant(300, 99999); // 指定租约 ID
// 续约(单次)
$result = $etcd->lease()->keepAlive($lease['ID']);
echo "TTL 剩余: {$result['TTL']} 秒";
// 查看租约状态
$info = $etcd->lease()->timeToLive($lease['ID']);
$info = $etcd->lease()->timeToLive($lease['ID'], true); // 含绑定的 key 列表
// 列出所有活跃租约
$leases = $etcd->lease()->list();
// 撤销租约(绑定的所有 key 立即删除)
$etcd->lease()->revoke($lease['ID']);
$auth = $etcd->auth();
// === 用户管理 ===
$auth->user()->add('alice', 'password123'); // 创建用户
$auth->user()->get('alice'); // 查看用户及其角色
$auth->user()->list(); // 列出所有用户
$auth->user()->changePassword('alice', 'newpass'); // 修改密码
$auth->user()->grantRole('alice', 'admin'); // 授权角色
$auth->user()->revokeRole('alice', 'admin'); // 撤销角色
$auth->user()->delete('alice'); // 删除用户
// === 角色管理 ===
$auth->role()->add('reader'); // 创建角色
$auth->role()->get('reader'); // 查看角色权限
$auth->role()->list(); // 列出所有角色
// 授予权限(permType: 0=READ, 1=WRITE, 2=READWRITE)
$auth->role()->grantPermission('reader', 0, '/data/', "\0"); // 对 /data/ 前缀的读权限
$auth->role()->grantPermission('writer', 2, '/data/', "\0"); // 读写权限
$auth->role()->revokePermission('reader', '/data/', "\0"); // 撤销权限
$auth->role()->delete('reader');
// === 认证开关 ===
$auth->enable(); // 开启认证
$auth->disable(); // 关闭认证
$status = $auth->status(); // ['enabled' => true, 'authRevision' => 5]
// 查看集群成员
$members = $etcd->cluster()->memberList();
// 添加成员
$etcd->cluster()->memberAdd(['http://node3:2380']); // 添加 Voting 成员
$etcd->cluster()->memberAdd(['http://node4:2380'], true); // 添加 Learner 成员
// 修改成员 peer URL
$etcd->cluster()->memberUpdate(123456, ['http://newnode:2380']);
// Learner 提升为 Voter
$etcd->cluster()->memberPromote(789012);
// 移除成员
$etcd->cluster()->memberRemove(345678);
// 查看节点状态
$status = $etcd->maintenance()->status();
// ['version' => '3.5.0', 'dbSize' => 24576, 'leader' => 123, 'raftIndex' => 1000, ...]
// 告警管理
$alarms = $etcd->maintenance()->alarm(); // 查看告警
$etcd->maintenance()->alarm(action: 2, alarm: 1); // 清除 NOSPACE 告警
// 碎片整理(回收存储空间)
$etcd->maintenance()->defragment();
// KV 哈希校验
$hash = $etcd->maintenance()->hash();
// 获取快照(返回二进制数据,写入文件即可)
$snapshot = $etcd->maintenance()->snapshot();
file_put_contents('/backup/etcd-snapshot.db', $snapshot);
use Erikwang2013\Etcd\Transport\HttpTransport;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
$transport = new HttpTransport(['127.0.0.1:2379'], ['timeout' => 3.0]);
$transport->setHttpClient(
new Client(['timeout' => 3]),
new HttpFactory(),
new HttpFactory()
);
// Facade 方式
use Etcd;
Etcd::kv()->put('/foo', 'bar');
$val = Etcd::kv()->get('/foo');
// 依赖注入方式
use Erikwang2013\Etcd\EtcdClient;
class MyService
{
public function __construct(private EtcdClient $etcd) {}
public function work(): void
{
$this->etcd->kv()->put('/key', 'value');
}
}
use Erikwang2013\Etcd\EtcdClient;
use Hyperf\Di\Annotation\Inject;
class MyService
{
#[Inject]
private EtcdClient $etcd;
public function work(): void
{
$this->etcd->kv()->put('/key', 'value');
}
}
// 或者直接 make
$etcd = make(EtcdClient::class);
return [
Erikwang2013\Etcd\Adapter\ThinkPHP\Service::class,
];
// Facade 方式
use think\facade\Etcd;
Etcd::kv()->put('/key', 'value');
// 容器方式
app('etcd')->kv()->get('/key');
use Erikwang2013\Etcd\EtcdClient;
$etcd = EtcdClient::instance();
$etcd->kv()->put('/key', 'value');
use Erikwang2013\Etcd\Exception\{
EtcdException,
ConnectionException,
AuthException,
KeyNotFoundException,
};
try {
$etcd->kv()->put('/key', 'value');
} catch (ConnectionException $e) {
// etcd 节点无法连接(网络故障、宕机)
} catch (AuthException $e) {
// 认证失败(用户名密码错误)
} catch (KeyNotFoundException $e) {
// getOrFail() 时 key 不存在
} catch (EtcdException $e) {
// 其他 etcd 服务端错误
}
bash
php artisan vendor:publish --tag=etcd-config
# → config/etcd.php
bash
php bin/hyperf.php vendor:publish erikwang2013/etcd
# → config/autoload/etcd.php