Files
chongming-core/docs/worker-management.md
T

9.8 KiB
Raw Blame History

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= 参数
  • 实例 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 插件的可管理性前提

  1. 插件容器运行含管理能力(__admin__ + reload + rescale)的 chongming-worker;
  2. config_set / rescale 由副本在其进程 cwd 下写 config/workers/<type>/config.toml, 容器需挂载与网关同款的配置目录才能写回(含 [workers].count 持久化);
  3. 其它语言自行实现的进程插件需实现 __admin__ Queryable + liveliness + 数量管理, 否则只能被发现,无法改配置或扩缩容。

10. 多 worker 与 worker 副本的分工

gunicorn -w N 提升的是网关的 HTTP 接入/转发能力;插件计算能力由 Worker 副本数 (count)或 external 进程数决定。高并发场景按瓶颈扩:转发瓶颈加 -w,计算瓶颈加 count 或改跑 external。