9.8 KiB
9.8 KiB
Worker 管理与多实例运维
网关(chongming-gateway)对 Worker 副本的运维能力:管理指令与 REST 端点、扩缩容语义、 实例定向调用,以及多网关/多实例部署时的收敛前提。inline 与 external(进程)插件共用同一套 管理协议。
使用入口速览见主 README。
1. 管理协议
每个用 Worker 框架创建的副本都会注册管理 Queryable:
worker/<type>/<worker_id>/__admin__
| 指令 | 说明 |
|---|---|
status |
查询副本状态(含 instance_id,实例定向据此寻址) |
restart |
重启该副本:副本槽位由管理循环驱动,重新生成新 worker_id 并更新 liveliness |
stop |
停止该副本 |
drain |
优雅排空:摘除 liveliness/业务 Queryable 隔绝新请求,等待在途请求完成后退出,管理循环不重建 |
rescale |
调整副本数:不带 instance_id 为「全局对称分摊」;带 instance_id + absolute=true 且命中本实例时为「逐实例精细扩缩」,target 非本实例则安全忽略 |
config_set |
更新 [workers.config] 运行时配置(路由配置除外);成功则写回配置并重启该类型副本,任一失败返回失败明细 |
旧版运行时未声明
__admin__管理能力时,管理指令会超时(HTTP 502,日志有提示)。
2. REST 管理端点(仅超管)
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/v1/admin/workers |
盘点全部副本(inline 本地注册 + external liveliness 发现) |
POST |
/api/v1/admin/workers/restart |
重启单个副本(worker_type / worker_id 查询参数) |
POST |
/api/v1/admin/workers/<type>/stop |
停止单个副本 / 某插件全部副本 |
GET |
/api/v1/admin/workers/<type>/config |
读取现有 [workers.config](响应含 source/mode 标注取值来路) |
POST |
/api/v1/admin/workers/<type>/config |
更新配置(body {updates:{k:v}}),下发并重启 |
POST |
/api/v1/admin/workers/<type>/scale |
调整副本数(body {count:<全局总量>}),全局对称分摊 |
GET |
/api/v1/admin/workers/<type>/instances |
按进程实例(instance_id)分组读取副本 |
POST |
/api/v1/admin/workers/<type>/scale_instance |
逐实例精细扩缩(body {instance_id, count}) |
3. 配置热更新
- 回写插件
config.toml的[workers]段(保留其他段),拒绝写保留键(type/module/count等路由与加载控制键)。 - 插件按新配置先
on_cleanup()释放旧资源、再on_init()重建客户端(AI/DB client 等), 配置无需重启网关即生效。 - 仅 index0 副本落盘避免并发写冲突;其余副本同样应用新配置。
4. 扩缩容语义
- 扩容:新增副本槽位并注册 liveliness,随即参与负载均衡。
- 缩容:多余副本走
drain优雅排空——先隔绝新请求,等在途请求完成后关闭,避免中断业务。 - 持久化:目标数量写回插件
config.toml的[workers].count,重启后按新数量加载。 - 全局对称 vs 逐实例:
/scale调整某类型的全局总量(多实例下由各实例均分); 需单独调整某一个外部实例时用/scale_instance。
5. 多实例收敛(副本数分摊 / 领导选举 / MQTT Bridge 单例)
多网关或多进程部署时,以下三件事都以共享 [cache] 为单一事实来源:
[cache]
backend = "redis" # 多实例必须共享(redis 或共享卷 sqlite);单机 sqlite 即可
launch_worker_count = "toml" # 副本数/运行时配置以 toml(默认)还是 cache 为准
前提:所有网关与 external 进程指向同一 cache 后端。若各实例各用本机 cache, 副本数无法收敛、锁跨不了主机,多实例行为会退化。
5.1 副本数(count)按在线实例分摊
count语义为该类 Worker 的全局目标总量,各参与者按在线数量自动分摊。- 在线清单与心跳:网关启动登记、每 15s 心跳续约,超 60s 未续约的实例自动清理;关闭时注销。
同宿主多网关需显式设置
CHONGMING_GATEWAY_ID(缺省回退 hostname)。 - external 进程实例同样登记参与分摊,避免多实例把副本数翻倍;实例标识用
--instance/CHONGMING_WORKER_INSTANCE(缺省{hostname}:{pid},跨重启持续命中请显式指定)。 /scale写全局 count 后向该类型全部存活实例广播rescale,各实例按同一份数据计算 quota, 重复下发幂等。
5.2 inline 领导选举(多 worker 兼容)
- 同一网关的多个服务器 worker(gunicorn
-w等)中,同一时刻仅一个进程托管 inline worker (副本数精确等于count,而非 worker 数 × count);其余进程只做 HTTP 转发。 - 持有者崩溃后,其余进程经周期性巡检抢锁接管并拉起 worker(
set_nx唯一胜出,无双持有)。 - key 按
gateway_id隔离,多网关各自选举、互不抢占。
5.3 MQTT Bridge 单例(多实例免重复响应)
- Bridge 启动采用共享缓存分布式锁(
set_nx+ 租约续约),全局仅持锁网关消费 MQTT 请求, 避免共享外部 Broker 时「一条请求被各消费一次、各回一份响应」。 - 持有者失联后租约到期,其余网关经周期巡检(
bridge_supervise_interval,默认 15s)自动接管重建。 - 内嵌 Broker 单例按宿主隔离(
mqtt_broker:<hostname>):同宿主多进程仅启动一个 Broker, 接管时会清理前任遗留的孤儿 Broker 子进程。
5.4 部署形态速查
| 部署形态 | MQTT Broker | [cache] 后端 |
|---|---|---|
| 单机(含多 worker) | 内嵌 amqtt | 本地 sqlite |
| 多实例分布式 | 外部 Broker(必须) | redis(或共享卷 sqlite) |
6. 逐实例精细扩缩
同一类型跑多个外部进程(多机/多容器)时,除全局对称扩缩外,可只对某一个实例精确扩缩:
- 语义:把目标实例的副本数设为绝对值 N,其它实例不动;与全局
scale共存—— 全局对称是默认/一键复位(scale会清除整张覆盖表回到均分),逐实例是定制覆盖。 - 覆盖表:cache 键
worker:cm:instcounts:<type>={instance_id: 绝对副本数}; 无记录的实例回退到全局均分。 - 命中判断:
rescale命中本实例(instance_id与登记一致)才执行,目标是其它实例则忽略。 - REST / UI:
POST /admin/workers/<type>/scale_instance下发;GET /admin/workers/<type>/instances供前端按实例分组展示。
7. 实例定向调用
默认逐请求随机负载均衡,适合无状态插件。若插件持有只存在于某个进程本地的状态 (本地 SQLite/文件、串口、设备连接),可用实例定向把请求固定到该进程:
- 指定方式(三入口语义一致):
- HTTP 请求头
X-Chongming-Instance: <实例id> - MQTT 信封载荷顶层
target_instance(网关读后摘除,业务侧不可见) - 程序内
worker_manager.call(...)/call_raw(...)/call_stream(...)的instance_id=参数
- HTTP 请求头
- 实例 id 取值:
--instance→CHONGMING_WORKER_INSTANCE→CHONGMING_GATEWAY_ID→{hostname}:{pid};容器环境(K8s 注入CHONGMING_GATEWAY_ID)下两侧自动一致, 裸机同宿主多网关请显式指定。可读列表见GET /api/v1/admin/workers/<type>/instances。 - 粒度:定向到进程实例;实例内有多个副本时,请求仍在这几个副本间随机均衡。
- 实例离线时严格报错(HTTP 503 / MQTT
{"error": ...}),不静默回退到其它实例。 - 重试不跨实例;流式端点不重试,实例离线即失败。
- 缓存按实例隔离:定向且
cacheable=true时缓存键带实例前缀。
# 把这次请求固定到实例 edge-01 的进程
curl -H 'X-Chongming-Instance: edge-01' http://127.0.0.1:8000/api/v1/demo/state
# MQTT:载荷顶层带 target_instance(网关转发前摘掉)
# topic: chongming/demo/state payload: {"meta":{}, "data":{}, "target_instance":"edge-01"}
8. 前端管理页
Worker 管理(/workers):
- 登录:内置
POST /auth/login领取管理 Token(不依赖 auth 插件),仅is_superuser可操作。 - 列表:副本类型 / 副本 ID / 模式(inline|external)/ 状态,支持关键字、模式、副本数筛选与分页;
筛选同时作用于下方逐实例分组表。
worker_type == "auth"的配置项不展示、不可改。 - 操作:单副本重启、批量重启、插件级重启、配置编辑(结构化 JSON 校验/格式化)、 调整副本数量(全局对称)、逐实例精细扩缩(按实例分组,仅调该实例)。
- 自动刷新:每 10s 轮询列表与分组表,异步操作结果自动反映。
- 调小副本数会触发优雅排空,前端确认提示中会说明。
9. external 插件的可管理性前提
- 插件容器运行含管理能力(
__admin__+reload+rescale)的chongming-worker; config_set/rescale由副本在其进程 cwd 下写config/workers/<type>/config.toml, 容器需挂载与网关同款的配置目录才能写回(含[workers].count持久化);- 其它语言自行实现的进程插件需实现
__admin__Queryable + liveliness + 数量管理, 否则只能被发现,无法改配置或扩缩容。
10. 多 worker 与 worker 副本的分工
gunicorn -w N 提升的是网关的 HTTP 接入/转发能力;插件计算能力由 Worker 副本数
(count)或 external 进程数决定。高并发场景按瓶颈扩:转发瓶颈加 -w,计算瓶颈加 count
或改跑 external。