关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

2026 Kestra 编排平台服务器租用配置手册:队列执行器与状态库写入怎么拆 + 并发避坑全攻略

发布时间:2026-10-29

2026 Kestra 编排平台服务器租用配置手册:队列执行器与状态库写入怎么拆 + 并发避坑全攻略

给编排平台配服务器,最容易被当成“一个 Web 应用”来估资源,但它真正的压力在另外两处——队列的轮询与出队,以及每完成一个任务就往状态库写一次的那条写路径;角色能不能拆开,取决于这两处谁先饱和。这个错位在 Kestra 上表现得尤其直接:Webserver 只是六类角色里的一类,而真正决定吞吐的那几个角色,一整天也碰不到几个 HTTP 请求。

官方把 Kestra 的服务拆成 Executor、Scheduler、Worker Controller、Worker、Webserver、Indexer 六类角色,并给出两种部署形态:Standalone 把所有角色跑在单个进程里,唯一外部依赖是一个数据库;Distributed 则让每个角色跑独立进程、各自扩缩。官方的说法是 Standalone 与分布式集群行为一致,迁到分布式只需要改部署方式。这句话成立,但成立的是“行为”,不是“资源画像”——角色一旦跑到不同机器上,原先被同一个进程掩盖掉的争抢会立刻显形。

本篇只算一条链:队列那一端(轮询、出队、消息大小)与状态库那一端(每次任务完成写入的执行状态、日志与指标)各自吃多少资源,什么时候该把“一个数据库同时扛队列与仓库”拆成两个后端,以及 Worker 该按什么口径算数量。它不涉及 Kestra 的安装步骤,不做与 Airflow、Dagster、Prefect 的横向对比,也不教怎么写 flow。

六个角色各自吃什么资源:Executor、Scheduler、Worker Controller、Worker、Webserver、Indexer

Executor 从队列取 execution 与 task run 消息,评估 flow 逻辑,决定下一个该跑哪个 task run 并派发出去,同时按固定节奏(默认每 10 秒)检查已注册实例的心跳。它干的是“编排决策”,不是“执行工作”,吃的是 CPU 编排线程与数据库连接。官方给的两条加 Executor 的触发条件,恰好对应它的两种饱和方式:正常负载下执行时延超过几秒,说明单实例的决策吞吐跟不上;稳定超过每 2 vCPU 每分钟 1000 个 task run,说明 CPU 侧的编排预算被吃满。

Scheduler 只做触发器评估,负载随 flow 数量与触发器频率增长,吃 CPU 与数据库连接,内存压力不大。它的扩容单位比较特殊:多副本之间靠把 flow 分摊到虚拟节点上来分担,虚拟节点数默认是 16 个(kestra.scheduler.vnodes)。所以给 Scheduler 扩容时真正要调的是“副本数 × vnode 分配”,而不是简单地再加一台。

Worker Controller 不执行任务,也不碰队列或数据库,它维持与 Worker 的 gRPC 长连接(默认端口 50051),负责注册、心跳与派发转发。它吃的是长连接数与内存,CPU 用量低,自身很少成为吞吐瓶颈,但它的可用性直接决定 Worker 能不能连上控制面。

Worker 是真正跑任务的地方。官方口径很明确:轻量任务(简单 API 调用触发远端作业、变量处理)单机并发高;重任务(复杂脚本、跑容器、重数据转换)单机并发低。Worker 不直接访问队列或数据库,它通过单条出向 gRPC 流连到 Worker Controller。资源上它吃 CPU、内存、容器内的临时 IO,以及到共享内部存储的读写带宽。要用 script 任务,服务器必须支持 Docker-in-Docker,这也是 AWS ECS Fargate 不被支持的原因——这一条是选 Worker 机型时的硬约束,选托管容器服务前必须确认。

Webserver 承载 UI 与 API,负载随用户数与 API 调用量变化,与执行吞吐基本无关。官方建议至少两个副本放在负载均衡后面,健康检查指向管理端口 8081 的 /health 或应用端口 8080 的 /ping。Indexer 则把执行数据写进索引后端供检索,吃的是写入 IOPS 与索引存储空间,负载随执行量与检索字段规模增长。

把这六类摆在一起看,资源画像最像“Web 应用”的是 Webserver 与 Scheduler,最不像的是 Executor 与 Worker。采购时如果按“一个应用”的思路一次性给一台机器堆高 vCPU 与内存,通常会得到一台 CPU 很富余、但数据库连接数与队列轮询参数完全没算过的机器——而卡点恰恰在后面这两处。

Standalone 到 Distributed 的迁移门槛:官方说行为一致,那真正变的是什么

“行为一致”指的是 flow 语义、执行模型、状态机不变,迁移不需要改业务逻辑,只改部署方式。但从资源角度看,跨过这道门之后有三件事真的变了。

第一件,内部存储必须共享。分布式部署下所有角色必须能访问同一个共享内部存储(GCS / S3 / Azure Blob);本地文件系统存储不适用于分布式部署,否则一台 Worker 写出的任务产出,Executor 或 Webserver 在另一台机器上读不到。这是从 Standalone 迈出去的第一道硬门槛,也是最容易在测试环境被漏掉的一条——因为单机上“本地路径能读”是理所当然的,环境一换才暴露。

第二件,Worker 只走一条出向 gRPC。Worker 通过单条出向 gRPC 流连接到 Worker Controller,且不直接访问队列或数据库。这一条决定了 Worker 的部署自由度:它可以放在另一个地域、另一个云,或者只允许出向连接的网络里,不需要为它开放到状态库的入向访问。

第三件,角色开始独立扩缩。Standalone 下加资源就是给一台机器加 vCPU 加内存,六类角色的资源比例被同一台机器的规格锁死。拆开之后,Executor 按编排负载扩,Worker 按负载类型与并发扩,两者的比例可以完全不同。这正是前两条能够成立的前提。

还有第四个变量,不算门槛,但必须纳入计算:网络时延进入了关键路径。原先角色间通信是进程内调用,现在变成了 gRPC 往返与数据库往返。Executor 到状态库、Worker 到 Worker Controller、所有角色到对象存储,这三段链路的质量开始直接体现在执行时延上。

最后一个容易被忽略的前提:开源版(OSS)用同一个 JDBC 数据库同时承担 queue 与 repository;企业版(EE)可以为两者分别配置,可选 AMQP、Redis、Kafka、Elasticsearch。也就是说,“能不能把队列和状态库拆开”这件事,在 OSS 与 EE 上的可选项是不一样的,做架构决策前先确认版本。

队列后端三选一:数据库队列的轮询成本、AMQP/Redis 降时延、Kafka 抬上限

数据库队列(PostgreSQL 或 MySQL)是默认后端,官方口径是“最简单,覆盖大多数生产场景”。它的成本在轮询:每次 poll 都是一次数据库查询,轮询越频繁、单次拉取越少,单位吞吐摊到的数据库开销就越高;反过来把单次拉取条数调大、间隔拉长,摊薄成本下降,但空转时的等待时延上升。官方对比表给它的定位是时延基线、吞吐到单实例上限、运维复杂度最低。

AMQP 或 Redis(EE)的定位是显著降低队列时延并提高吞吐上限,运维复杂度中等;其中 RabbitMQ 被认为运维更简单、边界情况更少。它适合的位置是:数据库队列的轮询成本已经明显吃掉库的 IO 与连接,但规模还没大到需要 Kafka 那种运维投入。

Kafka(EE)用于最高吞吐与完全水平扩展,对比表里是时延中等、吞吐最高、运维复杂度高。官方基准也印证了这个排序:简单 flow 在 JDBC 后端约 1500 executions/分钟之前时延不上升,Kafka 后端约 2000。

那为什么官方仍明确推荐 JDBC PostgreSQL 作为基线后端?两个理由。一是覆盖大多数生产场景、运维复杂度最低,故障排查路径最短——队列状态就是库里的一张表,出问题可以直接查,不需要额外维护一套 broker。二是队列与仓库同库时,写入的原子性更容易保证;换成 Elasticsearch 做 repository 是异步索引,牺牲插入原子性换检索性能,这是有代价的。

这里有个口径必须说清楚:官方基准显示 Kafka 后端能支撑更高的执行速率、PostgreSQL 更早饱和,但“更早饱和”不等于“不够用”。在官方 4 vCPU / 16 GB RAM 的基准机上,简单 flow 到 1500 exec/min 之前时延都是平的。要不要上 Kafka,取决于你的目标吞吐离这条饱和线还有多远,以及你愿不愿意为它付运维复杂度这笔账。

状态库写入账:每次任务完成都要写执行状态、日志与指标

状态库这一侧的写入,频率不是按“flow 数”算的,是按 task run 数算的。每完成一个 task run,就要往状态库写一次执行状态、日志与指标。一个 200 个任务的 ForEach,一次执行就是 200 次写入。这就是为什么复杂 flow(每执行包含很多任务)的吞吐会掉到 300–400 executions/分钟,而简单 flow 能到 1500——差的不是“执行次数”,是“每次执行里的任务数”。

官方给了一条很硬的提醒:PostgreSQL 存储增长很快,可达每年数 TB,要定期清理执行历史。这个量级是怎么长出来的?按公开口径做一次推算(以下为推算,非实测):假设每个 task run 平均产生 2 KB 日志,每 100 万个 task run 就是约 2 GB 日志;以复杂 flow 的 300 exec/min、每执行 10 个 task run 计算,等于 3000 task run/min,一天约 432 万个 task run,对应约 8.6 GB/天,一年约 3.1 TB。这个结果正好落在官方提醒的“每年数 TB”量级上,说明驱动存储增长的主要不是执行元数据,而是日志与指标的高频写入。把假设换成日志平均 8 KB,同样规模下年增量会到十几 TB。结论很直接:控制日志体量,比控制执行数量更能决定存储账单。

日志该不该单独走 Log Data Store?EE 中可以把执行日志路由到独立的 Log Data Store(PostgreSQL、MySQL、H2、Elasticsearch、Splunk、Datadog),收益是让主库保持精简、缩短 schema 迁移时间。判断依据有两条:一是 schema 迁移窗口是否已经变长(表越大迁移越慢);二是主库的存储增长是否已经影响到备份与恢复的时间目标。两条中任意一条成立,就该把日志分出去。

分离也有代价。日志与执行状态落到不同后端,回溯某一次执行时的一致性语义会变化;Elasticsearch 作为 repository 时是异步索引,检索型场景(大量历史执行查询)值得这个取舍,纯归档型场景未必。OSS 环境下没有这个可选项,默认的路子是保留 JDBC 主库同时承担 queue 与 repository,只做定期清理执行历史——成本最低,也最符合官方推荐的基线。

六个角色的负载、最先饱和的资源与拆分触发条件对照

角色 主要负载 最先饱和的资源 官方/公开口径的容量参考 单独拆出来的触发条件 选型时需确认的项
Executor 消费队列消息、评估 flow 逻辑、派发下一个 task run、按节奏检查实例心跳 CPU 编排线程,以及数据库连接与队列轮询开销 简单 flow:JDBC 约 1500 exec/min、Kafka 约 2000 之前时延不上升;复杂 flow:约 300–400 exec/min;加实例线为每 2 vCPU 每分钟 1000 个 task run 正常负载下执行时延超过几秒;或稳定超过每 2 vCPU 每分钟 1000 个 task run executor.thread-count、目标 exec/min、flow 平均 task run 数、到状态库的往返时延、JDBC 队列的 poll-size 与轮询间隔
Scheduler 触发器评估,多副本间按虚拟节点分摊 flow CPU 与数据库连接,内存压力相对低 副本通过把 flow 分摊到虚拟节点上来分担触发器评估,默认 16 个(kestra.scheduler.vnodes) flow 数量与触发器频率上升,触发评估出现延迟;或需要消除 Scheduler 单点 vnode 数、副本数、flow 总数与最短触发周期、数据库版本(PostgreSQL ≥ 14 / MySQL ≥ 8,8.0.31 除外)、MySQL 时区表是否已加载
Worker 真正执行任务。轻量任务(简单 API 调用触发远端作业、变量处理)单机并发高;重任务(复杂脚本、跑容器、重数据转换)单机并发低 CPU、内存、容器内临时 IO、到共享内部存储的读写带宽 官方口径:Workers 随负载类型与并发扩展;200 个任务的 ForEach 约 20 task runs/秒(总计 10–11 秒) 峰值时段 task run/小时超过现有并发槽处理量;或 ForEach 不设并发上限把编排拖慢到约 20 task runs/秒 单机并发槽数、平均 task run 时长、是否需 Docker-in-Docker(script 任务)、Worker 到对象存储的链路带宽与稳定性
Worker Controller 维持 Worker 的 gRPC 长连接(默认端口 50051),负责注册、心跳与派发转发 长连接数与内存,CPU 用量低 Worker 通过单条出向 gRPC 流连接,不直接访问队列或数据库 Worker 数量或地域分布增加;需要把多条 Worker 连接收敛到统一控制面 50051 端口的出向可达性、连接数上限、心跳 3 秒与超时 1 分钟的匹配、worker-task-restart-strategy(设为 NEVER 时不会重新派发)
Webserver UI 与 API 请求处理 HTTP 连接数与少量 CPU,与执行吞吐基本无关 官方建议至少两个副本置于负载均衡之后 用户与 API 调用量上升;或需要消除访问入口单点 副本数与负载均衡策略、健康检查端点(管理端口 8081 的 /health 或应用端口 8080 的 /ping)、静态资源与会话策略
Indexer 把执行数据写入索引后端,供历史执行检索 写入 IOPS 与索引存储容量 EE 中可作为独立后端;Elasticsearch 也可在 Kafka 部署中作为 repository,异步索引、牺牲插入原子性换检索性能 历史执行检索成为主库压力来源;或需要把检索负载从主库剥离 索引后端版本(Elasticsearch ≥ 7 或 OpenSearch ≥ 2)、索引保留期、字段与映射规模、与主库的一致性要求
队列后端(Database / AMQP 或 Redis / Kafka) 消息入队、轮询与出队;数据库队列下表现为周期性查询 数据库队列:轮询查询与连接;AMQP/Redis:broker 资源;Kafka:分区与运维投入 官方对比表——Database+Database:基线 / 单实例上限 / 最低;AMQP 或 Redis+Database:更低 / 更高 / 中等;Kafka+Database:中等 / 最高 / 高;Kafka+Elasticsearch:中等 / 最高 / 最高 简单 flow 的 OSS 时延从 1500 exec/min 的 0.9 秒跃升到 2000 exec/min 的 24 秒;或消息体偏大导致远低于该速率就出现尖峰 目标 exec/min、平均消息大小、是否为 EE(可选 AMQP、Redis、Kafka、Elasticsearch)、团队可承受的运维复杂度
状态库与内部存储 每个 task run 完成写入执行状态、日志与指标;任务输入与产出的读写 写入 IOPS、连接数(各 pod HikariCP 池上限之和)、存储容量 官方提醒:PostgreSQL 存储增长很快,可达每年数 TB,需定期清理执行历史;EE 可把日志路由到独立 Log Data Store(PostgreSQL、MySQL、H2、Elasticsearch、Splunk、Datadog) schema 迁移时间变长、备份恢复窗口超出目标;或日志报出 remaining connection slots are reserved max_connections 与所有 pod 池上限之和、HikariCP max-lifetime 与库侧空闲超时、random_page_cost(SSD 上 1.1)、queues 表膨胀后的 REINDEX、内部存储必须共享(GCS / S3 / Azure Blob)

并发与吞吐的换算:1500 exec/min 与 300–400 exec/min 这两个数怎么用

官方给了三条吞吐线和两条扩容触发线,把它们放在一张账上算,机器规格就能推出来。三条吞吐线是:简单 flow 在 JDBC 后端约 1500 executions/分钟、Kafka 后端约 2000 之前时延不上升;复杂 flow(每执行包含很多任务)降到 300–400 executions/分钟,其中每执行 10 个 task run 时 OSS 约 300、EE 约 400。两条扩容触发线是:正常负载下执行时延超过几秒;稳定超过每 2 vCPU 每分钟 1000 个 task run。

换算法是把 exec/min 换成 task run/min。设每个执行平均含 N 个 task run,则 task run/min 等于 exec/min 乘以 N。官方那条 300–400 对应的正是 N 等于 10 的情形。而每 2 vCPU 每分钟 1000 个 task run,等价于每 vCPU 每分钟 500 个,约 8.3 task run/秒。

把这两个数落到一个具体机器上试试。简单 flow 取 N 等于 1(推算假设,实际取决于你的 flow 结构),目标 1500 exec/min,则 1500 task run/min,按每 vCPU 每分钟 500 个算,约需 3 vCPU。这个结果和官方基准机 4 vCPU / 16 GB RAM 的规格是吻合的,说明在数据库队列下,4 vCPU 大约就是单执行器的饱和区。复杂 flow 取 N 等于 10、目标 300 exec/min,则 3000 task run/min,约需 6 vCPU,已经超出基准机规格。这就是为什么复杂 flow 的 exec/min 会比简单 flow 掉一个数量级:卡的不是执行次数,是每次执行里的任务数。

这两条线的交叉点决定了扩容动作完全不同。flow 平均任务数少,瓶颈先出现在 Executor 的编排决策与队列轮询,正确动作是加 Executor 或换更快的队列后端;平均任务数多,瓶颈会先出现在状态库写入与 Worker 并发,正确动作是加 Worker 或把日志分出去。买错方向的机器,钱花完了指标也不动。

官方基准里的两个尖峰值得单独拿出来看,它们跑在同一台 4 vCPU / 16 GB RAM 的机器上。第一个是简单 flow 的 OSS 时延从 1500 exec/min 时的 0.9 秒跳到 2000 exec/min 时的 24 秒,26 倍的跃升说明数据库队列存在明确的饱和拐点,而不是线性劣化;跨过这条线之后加机器收益很低,该换的是后端。第二个是 160 KB 的大消息会造成时延尖峰,OSS 在 625 exec/min 时就已经到 34 秒,所以大 payload 绝不能塞进队列消息体,应该写进内部存储、只在消息里带引用。

ForEach 场景的两个数字同样出自官方基准:200 个任务的 ForEach 约 20 task runs/秒,总计 10–11 秒完成;不设上限的 ForEach(100 个并发迭代)会把整体编排拖慢到约 20 task runs/秒。后者是个反直觉的结论——并发完全放开,编排层的吞吐上限反而被压到跟中小规模差不多的水平,这时候再加 Worker 也补不回来,得回去给迭代次数设上限。

峰值时段的陷阱:为什么按全天平均算 Worker 会算少

Worker Calculator 里的 Active Hours 字段,官方口径是按峰值时段而不是全天平均来算。理由很朴素:Worker 是常驻资源,窗口内不够用就是排队,排队会同时抬高执行时延和状态库的写入压力。

官方给的例子是:每天 12 万个 task run,其中 10 万集中在 6 小时的夜间 ETL 窗口。按 24 小时摊算只有约 5 千/小时,按 6 小时算则是约 1.66 万/小时,需要的 Worker 数量是 3 倍。这个差距不是精度问题,是量级问题——按平均配出来的集群,在窗口内会直接崩。

把这条再往下推一步,就能算出具体台数。设单个 task run 平均占用 Worker 一个并发槽 T 秒,单 Worker 并发槽数为 C,则单 Worker 每小时处理 3600 乘以 C 再除以 T 个 task run。取 T 等于 30 秒、C 等于 8(这两个数字是推算假设,取决于你的任务性质与 Worker 配置,需以实际观测校准),单 Worker 约 960 个/小时;要扛住 1.66 万/小时的峰值,需要约 17 个 Worker。如果按全天平均的 5 千/小时算,只要约 5 个。差了三倍多,和官方给出的比例一致。

这里 T 是杠杆最大的变量。把平均任务时长从 30 秒压到 10 秒,同样的 Worker 数量吞吐直接翻倍,这比加机器便宜得多。所以算 Worker 之前,先问一句任务本身能不能更快,而不是默认去加节点。

还有一个连带判断:峰值窗口越短,对 Worker 的弹性要求越高。自建物理机的弹性只能靠“多配 + 空闲时闲置”,这种情况下与其按峰值买满,不如先试试把窗口拉长、做错峰调度,把峰值削下来,再决定买多少。

连接池这道暗坎:HikariCP 池上限之和与 PostgreSQL max_connections

这一节的内容来自一家服务商的生产实践总结,属于第三方口径,不是官方基准,引用时请注意区分。

该文给出的结构是:Kestra 各组件(Webserver、Executor、Scheduler、每个 Worker)各自维护一个 HikariCP 连接池,指向同一个数据库。由此产生两类故障。

第一类,各 pod 池上限之和超过 PostgreSQL 的 max_connections。该文的例子是:4 个 worker × 20 + Executor 20 + Scheduler 20 + Webserver 20 等于 140,超过默认的 100 就会报 “remaining connection slots are reserved”。这里的关键判断是,池上限之和算的不是“平均并发使用量”,而是“最坏情况下的同时占用量”。只要这个和超过 max_connections,就存在某一刻全部打满并报错的可能,哪怕日常平均使用率只有两成。所以算连接数用的是加法,不是估算平均值——每加一个 Worker 副本,就要把它的池上限重新加进总账里。

第二类,连接被服务端静默断开。该文的口径是:HikariCP 默认 max-lifetime 为 30 分钟,需要比照数据库侧的空闲超时设置逐一核对;一旦客户端与服务端两侧的超时配置不匹配,池中的连接会被服务端静默断开,而客户端要等到下次取用这条连接时才会发现,表现为周期性报错,严重时会触发滚动重启。这类故障的排查难点在于,报错时间点与真正的断连时间点完全错位,看应用日志很容易误判成别的问题。

该文给出的调优示例可以直接作为核对清单来用。Kestra 侧:kestra.jdbc.queues 下 poll-size 设为 100、min-poll-interval 设为 25ms、max-poll-interval 设为 1000ms、poll-switch-interval 设为 5s;executor.thread-count 设为 8;queue.postgres.disable-seq-scan 设为 true 以强制走索引扫描。数据库侧:SSD 上把 random_page_cost 设为 1.1;队列表膨胀后执行 REINDEX TABLE queues。

按参数名推断(确切语义需以实际版本文档为准),这几个参数本质上是在做两种交换。poll-size 与 min-poll-interval 是在“数据库查询开销”和“队列时延”之间换:单次拉取得多、轮询得慢,库的压力小但消息等待久;拉取得少、轮询得快,时延低但库查询频率飙升。max-poll-interval 是空闲时的退避上限,防止空队列把库打成无用功。disable-seq-scan 与 random_page_cost 是在纠正规划器对队列表的访问方式——队列表行数未必多但更新极其频繁,规划器一旦选了全表扫描,代价会随表膨胀快速放大。REINDEX 针对的则是膨胀本身。

必须提醒一句:这些取值出自那篇文章的具体环境,是示例不是通解。poll-size 100 与 thread-count 8 之间是有关联的,脱离那台机器的规格和那批任务的性质照搬,很可能只是把瓶颈从一处挪到另一处。搬进生产前,先在压测环境按自己的 exec/min 与消息大小验一遍。

内部存储与 Worker 的地理分布:一条出向 gRPC 带来的自由度与代价

官方对 Worker 的连接模型描述得很清楚:Worker 通过单条出向 gRPC 流连接到 Worker Controller,且不直接访问队列或数据库。因此 Worker 可以部署在另一个地域、另一个云,或者只允许出向连接的网络里。这在编排平台里是个相当强的自由度——大部分同类系统里,执行节点都是要能连回中心库的。

代价落在内部存储上。既然 Worker 不碰状态库,它的任务输入与产出就必须落在所有角色都能读到的地方。分布式部署下所有角色必须能访问同一个共享内部存储(GCS / S3 / Azure Blob),本地文件系统存储不适用,否则一台 Worker 写出的任务产出,Executor 或 Webserver 在另一台机器上读不到。于是实际的部署拓扑是一个三角:Worker 出向 gRPC 到 Worker Controller 的 50051 端口;Worker 出向到对象存储;Executor、Webserver、Indexer 通过 JDBC 到状态库,同时也要到对象存储。

第一个实务含义是 Worker 可以贴近数据源跑。ETL 的目标库在某个云,就把 Worker 放过去,它只需要出向连回控制面。这比把整个控制面搬过去便宜,也更安全——不需要为它开放到 Kestra 状态库的入向访问。

第二个实务含义是 Worker 到对象存储的链路要单独算。任务的输入文件与产出都走这条路,ForEach 这类会一次性展开大量迭代的任务尤其容易在这里堆出突发流量。链路不稳时,表现为任务随机失败或明显变慢,但控制面的所有指标都是正常的,排查方向很容易跑偏。

第三个实务含义是健康检查的方式要跟着改。官方给的健康检查端点是管理端口 8081 的 /health 或应用端口 8080 的 /ping;如果 Worker 所在网络只允许出向,那么从控制面主动探活 Worker 未必可行,健康状态更适合由 Worker 到 Worker Controller 的连接状态来判定。这一条官方没有单独给出指引,具体做法需结合实际网络策略确定。

还有一条硬前提不能漏:要用 script 任务,服务器必须支持 Docker-in-Docker,这也是 AWS ECS Fargate 不被支持的原因。选 Worker 的执行环境时,先把这条确认掉,再谈规格。

什么时候该拆、什么时候一台 4 GiB / 2 vCPU 就够

官方给出的独立(standalone)服务器最低要求是 4 GiB 内存加 2 vCPU。注意“最低要求”这四个字,它是能跑起来的下限,不是推荐的生产规格。真实环境应当以它为起点,按下面的条件逐条判断要不要往上走。

一台 4 GiB / 2 vCPU 够用的边界条件:执行量处在低位,明显低于官方基准里复杂 flow 的 300–400 exec/min 区间;任务以轻量的 API 调用触发远端作业、变量处理为主,而不是复杂脚本或跑容器;flow 数量与触发器频率不高,Scheduler 评估不构成负担;执行历史有定期清理机制,状态库不会无上限增长;没有需要 Docker-in-Docker 的 script 任务,或者机型确认支持 DinD。这几条同时成立,Standalone 一台机器是最省事也最省钱的方案。

该把 Executor 单独拆出来的触发条件,官方给了明确的两条:正常负载下执行时延超过几秒;稳定超过每 2 vCPU 每分钟 1000 个 task run。前者是时延信号,后者是 CPU 预算信号,两个只要持续成立,就说明编排决策这一步已经不是一台机器能舒服扛下的了。

该换队列后端的信号,看时延的形态。官方基准里简单 flow 的 OSS 时延从 1500 exec/min 的 0.9 秒跃升到 2000 exec/min 的 24 秒,这种量级的跳变说明数据库队列到了饱和拐点,再加 Executor 收益很低,正确的动作是换后端——要降时延选 AMQP 或 Redis,要抬上限选 Kafka。另外,如果消息体普遍偏大,160 KB 量级就会让 OSS 在 625 exec/min 时出现 34 秒的尖峰,这时先做的不是换后端,而是把大 payload 移出消息体。

该把日志分出去的信号,看数据层。schema 迁移时间开始变长,或者主库存储增长已经影响到备份与恢复的时间目标,就该用 EE 的 Log Data Store(PostgreSQL、MySQL、H2、Elasticsearch、Splunk、Datadog)把日志路由出去,让主库保持精简。该加 Worker 的判断,按峰值时段的 task run/小时算,用 Active Hours 口径,不用全天平均。

扩容顺序上,本篇给出的口径是:先判断队列后端是不是瓶颈(看 exec/min 与时延的对应关系)→ 再拆 Executor → 再按峰值算 Worker → 再动状态库(日志分离、连接数核对、清理策略)→ 最后才考虑换后端。理由是前三步是横向加角色或调参数,变更快、可回滚;后两步涉及数据层,变更窗口长、回滚代价高。这是工程判断,不是官方给出的固定路径。

部署前还有一份很短但必须核对的清单:运行时 JDK 25(源码/目标 21);PostgreSQL ≥ 14;MySQL ≥ 8(8.0.31 除外);EE 另需 Kafka ≥ 3、Elasticsearch ≥ 7 或 OpenSearch ≥ 2。其中 MySQL 部署必须加载时区表,否则调度器可能误触发或跳过运行。这条漏掉的代价极高,因为症状是“偶发的调度不准”,很难第一时间联想到时区表。

Kestra 的执行器与状态库,谁是第一个瓶颈

答案取决于你的 flow 平均含多少个 task run。任务数少,瓶颈先出现在队列与 Executor 的编排决策上;任务数多,瓶颈先出现在状态库的写路径上。官方的数字已经把这条分界线画出来了:简单 flow 在 JDBC 后端约 1500 executions/分钟之前时延不上升,复杂 flow(每执行包含很多任务)吞吐降到 300–400 executions/分钟。

判断当下卡在哪一侧,看时延的形态就够了。时延随着 exec/min 陡升,出现类似 1500 到 2000 时 0.9 秒变 24 秒的跃变,瓶颈在队列与 Executor;时延平稳但吞吐就是上不去,同时状态库的写入 IOPS 与连接占用长期居高,瓶颈在写路径。还可以加一个维度看消息大小:同样归在“执行器瓶颈”里,成因可能是吞吐到顶,也可能是 payload 太大,两者的处置方式完全相反。

数据层那道坎要单独盯住,它在官方口径里没有对应的监控项,但故障率高。各 pod 的 HikariCP 池上限之和必须小于 PostgreSQL 的 max_connections,用的是加法不是平均值;max-lifetime 与库侧空闲超时要逐一核对,否则连接会被静默断开,报错时间点与断连时间点错位。这两条来自第三方生产实践总结,不是官方基准,但值得照着查一遍。

一万网络深耕 IDC 行业 19 年(成立于 2007 年),在华南、华东、华北及中国香港、海外多地整合自营节点与 BGP 多线资源,提供服务器租用、机柜托管与带宽接入的一体化交付;具体机型、带宽与报价以官网实时信息或咨询确认为准。就 Kestra 这类编排负载而言,我们的看法是:控制面(Webserver、Scheduler、Executor)与执行面(Worker、Worker Controller)应该分开看 vCPU 与内存的配比,而数据面(状态库与共享内部存储)的 IO 与连接数,才是决定这套集群上限的那一层。

最后把限制说清楚。本篇所有数字均来自 Kestra 官方文档口径或官方公布的基准,官方基准均运行在 4 vCPU / 16 GB RAM 的机器上;连接池部分来自第三方实践文章。全文不含我们自己的实测数据、客户案例或机型报价。你要把这些数搬进自己的环境,至少先校准三个变量:flow 的平均 task run 数、消息平均大小、峰值窗口的长度与峰值 task run/小时。这三个数对了,上面每一条换算才成立。

一万网络给编排平台节点的分层配置口径

第一层是控制面节点:Webserver、Scheduler、Executor。这一层的负载特征是 CPU 与数据库连接,内存需求相对温和,IO 压力主要在数据库的轮询查询上。选型时按 Executor 的目标 task run/min 与 executor.thread-count 反推 vCPU,按官方那条“每 2 vCPU 每分钟 1000 个 task run”的线校准。Webserver 至少两个副本挂在负载均衡后面,健康检查指向管理端口 8081 的 /health 或应用端口 8080 的 /ping。Scheduler 副本数变化时同步看 kestra.scheduler.vnodes 的分摊是否均匀。

第二层是执行面节点:Worker 与 Worker Controller。这一层的负载特征是 CPU、内存、容器临时 IO 与到对象存储的带宽,并发能力高度依赖任务轻重。选型时先确认是否需要 script 任务(需要则机型必须支持 Docker-in-Docker),再按峰值窗口的 task run/小时与平均任务时长算并发槽和台数。Worker 放在只允许出向连接的网络、另一个地域或另一个云都是可行的,前提是把 Worker Controller 的 50051 出向可达性和到对象存储的链路质量一起测掉。

第三层是数据面节点:状态库与共享内部存储。这一层决定整套集群的上限,也最难改。核对项包括 max_connections 与所有 pod 池上限之和、max-lifetime 与库侧空闲超时、SSD 上的 random_page_cost、队列表膨胀后的 REINDEX,以及内部存储必须是 GCS / S3 / Azure Blob 这类共享存储(本地文件系统不适用于分布式部署)。官方同时建议把 PostgreSQL 部署为 HA 模式(PGPool 或云托管),避免数据库成为单点。日志体量按官方提醒的“每年可达数 TB”预留,并执行历史定期清理。

一万网络深耕 IDC 行业 19 年(成立于 2007 年),在华南、华东、华北及中国香港、海外多地整合自营节点与 BGP 多线资源,提供服务器租用、机柜托管与带宽接入的一体化交付;具体机型、带宽与报价以官网实时信息或咨询确认为准。落到 Kestra 这套负载上,我们的分层口径是:控制面按吞吐配 vCPU,执行面按峰值并发配台数,数据面按随机写 IOPS 与连接数配额配盘和配库——三层里任意一层配薄了,另外两层的投入都收不回。

来沟通配置之前,建议先把四个数字准备好:目标 executions/分钟、flow 的平均 task run 数、峰值窗口的长度与该窗口内的 task run 总数、消息平均大小。有这四个数,按本篇的换算链就能推出需要几个 Executor、几个 Worker,以及状态库该按什么规格配;机型、带宽与报价需实时询价,以官网实时信息或咨询确认为准。


上一篇:同一个请求被处理两次会发生在哪些环节:幂等键、去重窗口与副作用边界怎么定

下一篇:2026 Headless CMS 服务器租用配置手册:Strapi 与 Directus 的媒体与 API 缓存账 + 构建避坑全解