kylin987 / webman-config-center-client
Lightweight, cache-first configuration client for Webman.
Package info
github.com/kylin987/webman-config-center-client
pkg:composer/kylin987/webman-config-center-client
Requires
- php: >=8.1
- guzzlehttp/guzzle: ^7.5
- nikic/php-parser: ^5.0
- predis/predis: ^2.2
- symfony/yaml: ^6.4
README
面向 Webman 项目的轻量配置中心客户端。
它负责从 Config Center 服务端拉取配置,校验内容格式,然后写入业务项目本地配置目录。远端异常时会保留本地旧配置,避免因为配置中心短暂不可用导致业务 worker 退出。
配套服务端仓库:kylin987/webman-config-center
安装
composer require kylin987/webman-config-center-client
安装后,Webman 会自动复制插件配置到:
config/plugin/kylin987/config-center/
同时会创建配置落地目录:
config/cc/
├── .gitignore
└── app.php
其中 config/cc/app.php 是占位配置,保证 config('cc.*') 这类读取方式在远端配置同步前也可用;其他同步生成的配置文件默认不会提交到 git。
主要配置文件是:
config/plugin/kylin987/config-center/app.php
config/plugin/kylin987/config-center/config.php
config/plugin/kylin987/config-center/listeners.php
config/plugin/kylin987/config-center/process.php
配置
打开 config/plugin/kylin987/config-center/config.php,根据项目实际情况修改服务端地址、客户端账号密码、轮询和日志参数。
插件默认开启。Webman 启动时会自动启动一个 config-center 进程:
php start.php start
如果需要关闭自动同步进程,修改:
// config/plugin/kylin987/config-center/app.php return [ 'enable' => false, ];
推荐只把服务端地址、客户端账号密码等环境相关或敏感信息放到 .env:
CONFIG_CENTER_ENDPOINT=http://config-center.example.com/ CONFIG_CENTER_USERNAME=your-client-username CONFIG_CENTER_PASSWORD=your-client-password CONFIG_CENTER_CLIENT_NAME=yhs-web CONFIG_CENTER_REDIS_PASSWORD=your-redis-password
其他普通配置建议直接写在 config.php 中,例如 namespace、Redis 地址、DB、频道、轮询间隔、日志 channel 等。
client_name 用于服务端后台展示“某个配置最近被哪些项目读取过”。如果不配置,客户端会默认使用项目目录名;请求时还会自动携带当前 Pod/主机名。
多 Pod 共享目录和状态目录
客户端会把远端配置写入 config/cc,这个目录可以被多个 Pod 共享。但同步状态目录 state_dir 默认会按主机名再隔离一层:
'state_dir' => runtime_path() . '/config-center', 'state_dir_host_isolation' => true,
实际使用时会变成类似:
runtime/config-center/<hostname>/
这样做是为了兼容多 Pod 共享同一套项目目录的部署方式。如果所有 Pod 共用同一个 state_dir,可能出现一个 Pod 已经写入最新 state,其他 Pod 收到 Redis 通知后判断为 unchanged,从而不执行自己的 reload_command。默认按主机名隔离后,每个 Pod 都会独立记录同步状态,并在配置更新时执行自己的 reload。
如果你明确只有单实例,或者确实希望多个进程共享同一份同步状态,可以关闭:
'state_dir_host_isolation' => false,
如果服务端开启了客户端 IP 白名单,并且公网域名可能解析到 IPv6,可以在 config.php 中强制客户端走 IPv4:
'ip_resolve' => 'v4',
可选值:
auto:默认值,交给系统和 DNS 决定。v4:强制 IPv4,适合公网域名 + IPv4 白名单。v6:强制 IPv6,一般不需要。
轮询默认带随机抖动,避免几十个客户端集中在同一秒请求服务端:
poll_interval=60表示基础轮询间隔是 60 秒。poll_jitter_seconds=30表示每次实际轮询会随机落在 30~90 秒之间。- 如果把
poll_jitter_seconds配成null,默认取poll_interval的一半,最多 30 秒。 - 自动进程启动后会立即同步一次,方便启动后马上生成本地配置文件;后续轮询会带随机抖动。
如果需要 Redis Pub/Sub 实时通知,修改 config.php:
'redis' => [ 'enable' => true, 'host' => 'redis.default.svc', 'port' => 6379, 'password' => getenv('CONFIG_CENTER_REDIS_PASSWORD') ?: '', 'database' => 0, ],
启用 Redis 后,自动进程会同时做两件事:
- 按
poll_interval定时轮询,作为兜底。 - 订阅 Redis Pub/Sub,服务端发布配置后立即收到通知并同步。
旧版或高级用法仍然兼容 redis_url:
'redis_url' => 'tcp://:redis-password@redis.example.com:6379/0',
如果配置文件里存在 redis 数组,并且明确设置了 enable,会优先按 redis 数组判断是否启用。
打开 config/plugin/kylin987/config-center/listeners.php,维护需要监听/同步的配置文件。
listeners.php 是白名单,只有声明过的配置才会被写入本地文件:
<?php return [ [ 'group' => 'DEFAULT_GROUP', 'data_id' => 'app.php', 'format' => 'php', 'path' => config_path() . '/cc/app.php', 'reload_command' => '', ], ];
path 支持绝对路径和相对路径:
- 推荐写绝对路径,例如
config_path() . '/cc/sw-mysql.php',清楚知道文件会写到哪里。 - 如果写相对路径,例如
'sw-mysql.php',客户端会把它拼到config_root下面,默认也就是config/cc/sw-mysql.php。
listeners.php 必须存在并返回数组。监听项不要写到 config.php 里,config.php 只负责服务端地址、账号密码、轮询、Redis、日志等运行参数。
reload_command 是可选项,默认为空。只有远端配置内容实际更新或本地文件被修复时,客户端才会执行对应监听项里的 reload_command;配置未变化时不会执行。命令执行成功或失败都会写入当前 log_channel。
客户端以内容 md5 作为是否需要 reload 的核心判断:如果本地文件内容已经和远端一致,即使当前 Pod 没有自己的 state,或者远端 revision 因重复发布而增加,也只会补写 state 并返回 unchanged,不会执行 reload_command。这可以避免多 Pod 滚动发布时新 Pod 做无意义 reload。
注意:客户端同步配置文件后,Webman 运行中已经加载到内存的 config('cc.xxx') 不会自动变化。如果业务希望配置发布后立即生效,需要给对应监听项配置 reload_command,或者在发布后手动 reload 项目。
如果确实希望某个配置更新后自动 reload,可以这样写:
[
'group' => 'DEFAULT_GROUP',
'data_id' => 'app.php',
'format' => 'php',
'path' => config_path() . '/cc/app.php',
'reload_command' => 'php ' . base_path() . '/start.php reload',
]
修改 listeners.php 后执行 php start.php reload,插件进程会重新读取监听列表;如果你从早期版本升级过来,建议升级后先执行一次 php start.php restart。
PHP 配置和 PHP 代码文件
format => 'php' 专门用于普通配置文件,内容必须是单个静态 return 表达式,例如:
<?php return [ 'debug' => false, ];
如果需要同步 PHP 类文件、函数文件等代码文件,使用 php_code。客户端只做 PHP 语法校验,不要求 return:
[
'group' => 'juhe',
'data_id' => 'HallRuleEvaluator.php',
'format' => 'php_code',
'path' => app_path() . '/common/library/HallRuleEvaluator.php',
'reload_command' => '',
],
业务代码读取配置
客户端默认把远端配置文件写入业务项目的:
config/cc/
所以在 Webman 里读取时,统一使用 cc 作为一级配置名。
例如 listeners.php 中这样配置:
[
'group' => 'DEFAULT_GROUP',
'data_id' => 'redis.php',
'format' => 'php',
'path' => config_path() . '/cc/redis.php',
]
同步后会生成:
config/cc/redis.php
业务代码里这样读取:
$redis = config('cc.redis', []);
如果 path 带目录:
[
'group' => 'DEFAULT_GROUP',
'data_id' => 'mysql.php',
'format' => 'php',
'path' => config_path() . '/cc/database/mysql.php',
]
同步后会生成:
config/cc/database/mysql.php
业务代码里这样读取:
$mysql = config('cc.database.mysql', []);
也就是说,config() 的 key 由本地 path 在 config/ 目录下的相对位置决定,不是由远端 data_id 决定。
如果你把配置写到 config/cc 之外,也可以,但 Webman 的 config() 读取 key 会跟着路径变化。例如:
[
'group' => 'DEFAULT_GROUP',
'data_id' => 'custom.php',
'format' => 'php',
'path' => config_path() . '/custom/config.php',
]
同步后业务代码读取:
$custom = config('custom.config', []);
客户端发布配置
如果业务项目需要主动新增或修改配置,可以使用客户端账号调用发布接口。发布成功后,服务端会生成历史版本,并触发配置变更通知。
use Kylin987\WebmanConfigCenter\ConfigApiClient; use Kylin987\WebmanConfigCenter\ConfigLoader; $client = new ConfigApiClient(ConfigLoader::load()); $result = $client->publish( namespace: 'public', group: 'DEFAULT_GROUP', dataId: 'app.php', format: 'php', content: "<?php\nreturn ['debug' => false];\n", expectedRevision: null, note: 'publish from business project' ); echo $result->revision;
expectedRevision 是可选的乐观锁:
- 不传:直接新增或覆盖发布。
- 传当前版本号:如果服务端版本已经变化,会发布失败,避免覆盖别人刚提交的内容。
命令
一般情况下不需要手动启动监听进程,插件会跟随 Webman 自动启动 config-center 进程。
如果需要手动调试,可以使用下面的命令。
启动前同步一次:
php vendor/bin/config-center-sync
手动启动定时轮询:
php vendor/bin/config-center-poll
Redis 是配置可选项。自动进程已经支持 Redis 订阅;下面这个命令只建议用于手动调试 Redis 事件监听:
php vendor/bin/config-center-listen
运行建议
- 默认使用插件自动注册的
config-center进程,不需要额外 sidecar。 - 默认轮询会带随机抖动,多个 Pod 不会固定在同一秒请求服务端。
config-center-sync可以用于手动调试或启动前同步一次。- 如果需要更实时的发布通知,开启
redis.enable即可,自动进程会同时订阅 Redis。 - 配置中心不可用时,客户端保留本地旧文件,下一次同步成功后再更新。
- 配置中心不可用时,自动轮询进程、
config-center-poll和config-center-listen都不会连续刷屏;错误会写入 Webman 日志,默认 channel 为default,同类错误默认 300 秒最多写一次。 - 如果希望启动前同步失败时阻断启动,可以配置
fail_on_error=true;默认不阻断,适合配置文件已经随项目发布或已经落地到本地的场景。 - 如果服务端版本号未变化,但本地配置文件被误删或内容被手动改坏,客户端会按服务端内容自动修复本地文件,并返回
repaired状态。