docs: 说明文件重整(README 改使用导向,运维细节移入 docs/worker-management.md)
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
# Worker 管理与多实例运维
|
||||
|
||||
网关(chongming-gateway)对 Worker 副本的运维能力:管理指令与 REST 端点、扩缩容语义、
|
||||
实例定向调用,以及多网关/多实例部署时的收敛前提。inline 与 external(进程)插件共用同一套
|
||||
管理协议。
|
||||
|
||||
> 使用入口速览见主 [README](../README.md#worker-管理与扩缩容)。
|
||||
|
||||
## 1. 管理协议
|
||||
|
||||
每个用 Worker 框架创建的副本都会注册管理 Queryable:
|
||||
|
||||
```text
|
||||
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]` 为单一事实来源**:
|
||||
|
||||
```toml
|
||||
[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` 时缓存键带实例前缀。
|
||||
|
||||
```bash
|
||||
# 把这次请求固定到实例 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。
|
||||
Reference in New Issue
Block a user