部署指南¶
单机部署¶
1. 准备环境¶
2. 启动 Redis¶
3. 启动 Worker¶
集群部署¶
by-framework 支持将 Redis 从单机换成 Redis Cluster 部署,三个 SDK 内部已经完整实现了 Cluster 适配(key 加 hash tag、
跨 slot 操作拆分、XREADGROUP 两阶段轮询、cluster-aware SCAN 等),业务代码不需要改动,只需要调整环境变量。
什么时候需要 Redis Cluster
单实例 Redis(哪怕挂了持久化和主从)在数据量或吞吐量触顶时无法再横向扩容。如果你已经在单机部署下遇到了 Redis 内存 / 连接数瓶颈,或者本身就要求多分片高可用,才需要切到 Cluster;否则单机部署(配合主从 + 哨兵做高可用)已经足够, 没必要为了"以防万一"而提前引入 Cluster 的运维复杂度。
1. 准备 Redis Cluster¶
本地验证可以用 docker-compose 起一个最小的 3 主 3 从集群:
services:
redis-cluster:
image: redis:7-alpine
command: >
redis-cli --cluster create
redis-node-1:6379 redis-node-2:6379 redis-node-3:6379
redis-node-4:6379 redis-node-5:6379 redis-node-6:6379
--cluster-replicas 1 --cluster-yes
depends_on: [redis-node-1, redis-node-2, redis-node-3, redis-node-4, redis-node-5, redis-node-6]
redis-node-1: &redis-node
image: redis:7-alpine
command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --appendonly yes
ports: ["6371:6379"]
redis-node-2:
<<: *redis-node
ports: ["6372:6379"]
redis-node-3:
<<: *redis-node
ports: ["6373:6379"]
redis-node-4:
<<: *redis-node
ports: ["6374:6379"]
redis-node-5:
<<: *redis-node
ports: ["6375:6379"]
redis-node-6:
<<: *redis-node
ports: ["6376:6379"]
生产环境通常由运维团队提供托管的 Redis Cluster(云厂商托管实例或自建),拿到的是一份 host:port 节点列表。
2. 设置环境变量¶
只需要设置一个 REDIS_CLUSTER_HOST(逗号分隔的 host:port 列表),SDK 会自动:
- 把部署形态从
standalone切换到cluster; - 把 Redis key 的物理格式从 v1(无 hash tag)切换到 v2(带 hash tag,
byai_gateway:v2:前缀)——Cluster 下多 key 操作 必须落在同一个 slot,v1 的 key 格式做不到这一点,会触发CROSSSLOT错误,详见 Redis Streams 深度剖析 · Key Schema 版本。
不需要再像早期版本那样分别设置 REDIS_MODE=cluster 和 REDIS_KEY_SCHEMA_VERSION=v2 两个变量:
export REDIS_CLUSTER_HOST="10.10.168.203:6371,10.10.168.203:6372,10.10.168.203:6373,10.10.168.203:6374,10.10.168.203:6375,10.10.168.203:6376"
export REDIS_USERNAME=default
export REDIS_PASSWORD=your-password
如果显式设置了 REDIS_MODE 或 REDIS_KEY_SCHEMA_VERSION,显式值始终优先于这条自动推断——这两个变量只在你想覆盖默认行为
(比如临时强制某个进程回退到单机模式)时才需要手动设置。
3. 启动 Worker¶
export REDIS_CLUSTER_HOST="10.10.168.203:6371,...,10.10.168.203:6376"
uv run python -m by_framework \
--worker-class my_agent.MyAgent \
--worker-id worker-01
也可以在代码里显式传入,不依赖环境变量:
export REDIS_CLUSTER_HOST="10.10.168.203:6371,...,10.10.168.203:6376"
java -cp target/my-worker.jar MyAgent --worker-id worker-01
RedisClient.getInstance()(GatewayWorker 无显式 RedisClient 参数时的默认路径)会自动读取
REDIS_CLUSTER_HOST 并切到 Cluster;需要显式控制时可以自己构造:
runWorker() 的 RunWorkerOptions 目前没有 redisMode / redisClusterNodes 字段
TypeScript 的 runWorker() 只能通过环境变量(REDIS_CLUSTER_HOST)切到集群模式——这条路径本身是可靠的,
因为 runWorker() 内部没有覆盖 mode,会一路 fallback 到 createRedis() 对 REDIS_CLUSTER_HOST 的解析。
但如果要完全脱离环境变量、纯编程式指定集群节点,RunWorkerOptions 还没有暴露对应字段,需要自己先构造好
客户端再传入 redisClient:
4. 数据迁移注意事项¶
切到 v2 key schema 后,所有参与 hash tag 改造的 key 物理名字会变(例如
byai_gateway:registry:worker:online:{worker_id} → byai_gateway:v2:registry:worker:{worker_id}:online),旧 key 下的数据在
新代码里读不到。多数 key 都带 TTL(会话数据 7 天、任务组 1 天、心跳 15 秒等),部署新版本后旧 key 自然过期即可,不需要额外
迁移脚本;只有极少数无 TTL 的 key(如管理员标记状态)需要一次性迁移。建议先在测试环境完整走一遍升级流程,确认数据丢失面
可以接受,再排期上生产。
多 Worker 部署¶
如需横向扩展,可以启动多个不同 worker_id 的 Worker 进程,并让它们共享同一个 Redis 实例(或同一个 Redis Cluster)与相同的
target_agent_type stream。
生产环境建议¶
使用连接池¶
配置监控¶
环境变量¶
| 环境变量 | 描述 | 默认值 |
|---|---|---|
BYAI_WORKER_CONCURRENCY |
最大并发数 | 50 |
BYAI_WORKER_FETCH_COUNT |
批量获取消息数 | 10 |
BYAI_REDIS_MAX_CONNECTIONS |
Redis 最大连接数 | max_concurrency + 10 |
REDIS_HOST |
Redis 主机地址(单机模式) | localhost |
REDIS_PORT |
Redis 端口(单机模式) | 6379 |
REDIS_DATABASE |
Redis 数据库号(单机模式)。替代旧的 REDIS_DB(REDIS_DB 仍可用,作为过期兼容 fallback,读取时打印一条 deprecation 日志) |
0 |
REDIS_USERNAME |
Redis 用户名 | (无) |
REDIS_PASSWORD |
Redis 密码 | (无) |
REDIS_CLUSTER_HOST |
逗号分隔的 host:port 列表;配置后自动切到 Cluster 模式,并自动把 key schema 推断为 v2(未显式设置 REDIS_MODE / REDIS_KEY_SCHEMA_VERSION 时) |
(无),即单机模式 |
REDIS_CLUSTER_NODES |
REDIS_CLUSTER_HOST 的旧变量名 / 等价别名,未设置 REDIS_CLUSTER_HOST 时才会读取;不会触发 key schema 自动推断 |
(无) |
REDIS_MODE |
显式指定 standalone / cluster,优先级高于 REDIS_CLUSTER_HOST 的隐式推断 |
standalone(未显式设置且无 REDIS_CLUSTER_HOST 时) |
REDIS_KEY_SCHEMA_VERSION |
显式指定 v1 / v2,优先级高于 REDIS_CLUSTER_HOST 的隐式推断;Cluster 模式下必须最终为 v2,否则启动时 fail-fast 拒绝 |
v1(未显式设置且无 REDIS_CLUSTER_HOST 时) |
run_worker 配置参数¶
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
worker_class |
Type[GatewayWorker] |
必填。业务 Worker 类。 | - |
worker_id |
str |
Worker 实例的唯一标识名。 | "worker-1" |
redis_host |
str |
Redis 服务器地址(单机模式)。 | "localhost" |
redis_port |
int |
Redis 端口(单机模式)。 | 6379 |
redis_db |
int |
Redis 数据库号(单机模式)。 | 0 |
redis_username |
str |
Redis 用户名 (可选)。 | None |
redis_password |
str |
Redis 密码 (可选)。 | None |
redis_mode |
Literal["standalone", "cluster"] |
显式指定部署形态;不传时按环境变量推断(含 REDIS_CLUSTER_HOST 隐式判定)。 |
None |
redis_cluster_nodes |
List[Tuple[str, int]] |
集群节点列表。非空即可推断为集群模式,不需要再单独传 redis_mode="cluster"。 |
None |
workspace_dir |
str |
任务执行的本地工作目录。 | "/tmp/gateway-workspace" |
consumer_group |
str |
Redis 消费者组名称。 | "agent_engines" |
max_concurrency |
int |
最大并发处理数。 | 50 |
fetch_count |
int |
每次批量获取的消息数量。 | 10 |
以上 redis_* 参数全部支持"不传则读环境变量",且显式传参始终优先于环境变量,两条路径可以任意混用。
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
workerId |
String |
Worker 实例的唯一标识名。 | "worker-1" |
RedisConnectionConfig |
RedisConnectionConfig |
Redis 连接配置,支持单机 / 集群两种模式;不显式传入时 GatewayWorker/WorkerRunner 走 RedisClient.getInstance() 默认单例,自动从环境变量(含 REDIS_CLUSTER_HOST)解析。 |
RedisConnectionConfig.fromEnv() |
WorkerConfig |
WorkerConfig |
Worker 运行参数配置。 | 默认值 |
Java 没有一个统一的 run_worker(...) 函数,而是显式构造 RedisClient / WorkerRunner;RedisConnectionConfig
的字段(mode / host / port / db / clusterNodes / username / password)与环境变量一一对应,
参见集群部署一节的示例。
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
workerId |
string |
Worker 实例的唯一标识名。 | "worker-1" |
redisHost |
string |
Redis 服务器地址(单机模式)。 | "localhost" |
redisPort |
number |
Redis 端口(单机模式)。 | 6379 |
redisDb |
number |
Redis 数据库号(单机模式)。 | 0 |
redisUsername |
string |
Redis 用户名 (可选)。 | undefined |
redisPassword |
string |
Redis 密码 (可选)。 | undefined |
redisClient |
Redis |
预先构造好的 Redis 客户端,传入后跳过上面几个字段,直接复用。目前是 TypeScript 里唯一的纯编程式集群配置方式(RunWorkerOptions 还没有 redisMode / redisClusterNodes 字段)。 |
undefined |
workspaceDir |
string |
任务执行的本地工作目录。 | "/tmp/gateway-workspace" |
consumerGroup |
string |
Redis 消费者组名称。 | "agent_engines" |
maxConcurrency |
number |
最大并发处理数。 | 50 |
fetchCount |
number |
每次批量获取的消息数量。 | 10 |
pluginList |
Plugin[] |
插件实例列表。 | [] |
pluginDir |
string |
插件目录路径。 | undefined |
集群模式在 TypeScript 里只能通过 REDIS_CLUSTER_HOST 环境变量触发(runWorker() 不会覆盖 mode,会一路
fallback 到底层 createRedis() 对该环境变量的解析),或者通过上面的 redisClient 字段自己传入已经用
createRedis({ mode: 'cluster', clusterNodes: [...] }) 构造好的客户端。