PowerJob:分布式任务调度、计算与工作流
凌晨两点的数据同步、每分钟的状态巡检、订单超时处理、全体节点上的日志清理,通常会从几段散落在业务系统里的定时代码开始。任务变多后,团队还会遇到另一组问题:谁在执行、失败后重试了几次、某台机器离线会怎样、日志到哪里看、多个任务怎样按依赖顺序衔接。
PowerJob 给出的答案是一套公司级调度中间件。团队统一部署 powerjob-server,各业务应用接入 powerjob-worker;任务的时间、并发、路由、重试和报警留在调度中心管理,真正的业务逻辑仍运行在业务应用中。PowerJob 还允许一次任务拆成子任务分发给多个 Worker,或者把多项任务编排成有向无环图(DAG)工作流。
这种边界决定了 PowerJob 的价值和成本。PowerJob 比单个应用内的 @Scheduled 或 Quartz 多出统一控制台、跨节点调度、在线实例治理与分布式计算,也要求团队维护 Server、关系型数据库、网络端口和账号权限。需要统一治理多条业务线任务的 Java 团队最容易获得收益;只有少量本地定时方法时,接入一套中心化平台往往偏重。
GitHub 仓库信息
| 信息 | 内容 |
|---|---|
| 项目标题 | PowerJob |
| 项目描述 | 分布式任务调度与计算框架(仓库 README 的项目定位) |
| GitHub 仓库 | PowerJob/PowerJob |
| 官网地址 | 未公开 |
| 内容摘要 | 统一管理定时任务、跨节点执行、Map/MapReduce 计算和 DAG 工作流,并覆盖 Spring Boot 接入、OpenAPI、生产运维与升级。 |
核心角色
PowerJob 的整体结构可以先压缩成 Server、Worker 和可选 Client 三类角色。
powerjob-server 提供 Web 控制台、计算触发时间、创建任务实例、选择 Worker、分发执行请求并收集结果。Worker 随业务应用启动,向 Server 发现和报告自身状态,接到请求后加载处理器并执行。powerjob-client 则把创建任务、立即运行、查询实例、停止任务和操作工作流等管理能力暴露给业务代码。
Worker 不是一台独立的“执行服务器”。常规 Java 业务任务直接随宿主应用部署,因此处理器能使用 Spring Bean、数据库访问层和业务服务;调度中心只负责何时、在哪个节点、以何种策略执行。仓库中的 Worker 自动配置确认了 Server 地址、应用名、通信协议、本地存储和任务容量等装配过程。
核心能力
时间与执行方式
固定提交中的时间策略枚举覆盖 API、CRON、固定频率、固定延迟、工作流触发和每日时间区间;执行方式枚举覆盖单机、广播、Map 和 MapReduce。两组选择解决的问题不同:前者决定何时产生实例,后者决定一次实例怎样使用 Worker 集群。
| 执行方式 | 一次运行会发生什么 | 典型场景 | 主要代价 |
|---|---|---|---|
| 单机 | Server 从可用 Worker 中选择一个节点执行 | 报表生成、数据同步、普通业务任务 | 业务仍需保证重复执行时的幂等性 |
| 广播 | 集群内所有符合条件的 Worker 都执行,并支持集群前置、后置处理 | 清理本地缓存、刷新所有节点配置 | 节点数会直接放大执行量 |
| Map | 根任务生成子任务,PowerJob 把子任务分发到集群 | 批量更新、文件或数据分片处理 | 分片粒度过细会增加调度和网络开销 |
| MapReduce | Map 分发后集中读取子任务结果并执行 Reduce | 需要汇总统计的分布式计算 | Reduce 全量持有结果,子任务巨大时增加内存压力 |
Map/MapReduce 进一步改变了一次任务利用 Worker 集群的方式:PowerJob 不只是在多台机器中挑一台执行 Cron。处理器可以在运行时调用 map 生成业务自定义子任务,Worker 集群共同处理后再汇总。官方 MapReduce 示例同时提醒,分片大小需要在失败重试成本与 PowerJob 调度开销之间取舍。
任务与实例管理
任务定义保存名称、触发方式、处理器、并发、超时、重试、机器门槛、日志和报警等配置。每次触发会产生独立实例,控制台可以观察状态和日志,也可以立即运行、停止、取消或重试。处理器使用 TaskContext 读取静态任务参数 jobParams、OpenAPI 运行参数 instanceParams、当前重试次数、子任务、工作流上下文和调度元信息。
OmsLogger 能把处理器日志送到控制台。官方处理器文档和示例都提醒,在线日志会增加 Server 通信与存储压力:开发阶段适合使用 Server 日志,稳定任务更适合切换到本地日志并提高日志级别。日志可见性是一种可配置的运维能力,不应变成无上限的远程日志管道。
工作流与 OpenAPI
工作流用 DAG 描述任务依赖,例如 A 成功后并行执行 B、C,最后执行 D。上游处理器可以通过 WorkflowContext 追加键值数据,下游节点再读取;Worker 配置会限制单次追加数据长度。工作流适合批处理流水线,不替代需要补偿事务、人工审批或长时间状态编排的完整流程引擎。
powerjob-client 提供另一条入口。固定提交的客户端接口覆盖任务、任务实例、工作流和工作流实例操作;5.1.2 还允许用业务主键 outerKey 关联一次运行。业务系统因此可以创建 API 类型任务,再根据订单、批次或事件决定立即执行还是延迟执行。
Docker Compose 试用
这条路径的目标不是看到三个容器处于运行状态,而是亲手创建并完成一次任务,再从控制台找到实例、结果和日志。仓库根目录的 Compose 文件会启动 MySQL、PowerJob Server 和示例 Worker,适合本地试用,不是生产模板。
前置条件与安全边界
- 已安装 Docker Engine 或 Docker Desktop,以及 Compose V2;
- 本机的
7700、10086、10010、10077、3307、8081和27777端口未被占用; - 只在可信测试网络运行,避免把数据库和通信端口暴露到公网;
- Compose 文件使用
latest镜像和公开示例凭据。生产环境应固定经过验证的镜像版本,使用独立强密码和密钥管理,并限制网络入口。
在一个准备保存测试数据的目录中克隆仓库,然后切换到本文核对的版本:
git clone https://github.com/PowerJob/PowerJob.git
cd PowerJob
git checkout v5.1.2
docker compose up -d
docker compose ps这些命令来自仓库 Compose 结构与官方快速开始,本次研究没有实际启动容器。首次启动需要初始化 MySQL 和 Server,示例 Worker 可能先失败再重启。观察日志时使用服务名,不要只看单个容器是否存在:
docker compose logs -f powerjob-server powerjob-worker-samples当 Server 日志不再持续报数据库连接错误、示例 Worker 完成注册,并且浏览器能打开 http://127.0.0.1:7700/,基础环境才算可用。5.x 默认 PowerJob 账号为 ADMIN,仓库配置的本地初始密码为 powerjob_admin;登录后立即修改密码。进入“应用管理”,确认 powerjob-worker-samples 存在并能看到在线 Worker。
创建并运行一个任务
进入示例应用,打开“任务管理”并新建任务。下面这组值刻意选择 API 触发,避免等待定时器:
| 字段 | 测试值 | 作用 |
|---|---|---|
| 任务名称 | powerjob-first-run | 便于在实例列表检索 |
| 任务参数 | CN | 示例处理器会返回中文成功消息 |
| 定时信息 | API | 只由手工或 OpenAPI 触发 |
| 执行类型 | 单机执行 | 从一个可用 Worker 执行 |
| 处理器类型 | 内置 Java | 使用示例 Worker 内已有类 |
| 处理器信息 | tech.powerjob.samples.processors.SimpleProcessor | 固定提交中的示例处理器全限定名 |
| 实例重试次数 | 0 | 避免第一次试用出现重试放大 |
| Task 重试次数 | 0 | 让一次点击对应一次实际执行 |
保存后点击运行按钮,再进入“任务实例”。成功信号应同时包括:实例状态为成功;结果中出现示例处理器返回的“任务成功啦”;在线日志能看到当前任务参数或上下文。这个闭环验证了 Server 调度、Worker 注册、处理器加载、执行结果和日志回传,而不是只验证 Web 页面能打开。
常见失败可以按信号定位:
no worker available:先确认 Worker 与任务属于同一个 App,再检查server-address、协议和对应通信端口;fetch Processor failed:核对处理器类型、全限定类名或 Spring Bean 名称,确认类确实进入 Worker 的运行时 classpath;- 页面正常但任务一直等待:检查 Worker 在线状态、指定机器或 Tag、CPU/内存/磁盘门槛和最大实例数;
- 日志为空:核对任务的 LogType 与 LogLevel,若使用本地日志则到 Worker 日志文件查看。
试用结束后可停止容器:
docker compose downCompose 使用宿主机 ./powerjob-data/ 保存数据。普通 down 不会主动删除该目录;需要清理测试数据时,应先确认目录内容和备份要求,再单独处理。
接入 Spring Boot Worker
本节使用 PowerJob 5.1.2。业务项目的 Spring Boot、JDK 和依赖树仍要在接入前做兼容性验证;仓库示例使用 Spring Boot 2.7.18,项目 POM 的编译目标是 Java 8,5.1.2 Release 声明已通过 JDK 21 编译与运行测试。
添加依赖与配置
<dependency>
<groupId>tech.powerjob</groupId>
<artifactId>powerjob-worker-spring-boot-starter</artifactId>
<version>5.1.2</version>
</dependency>先在 PowerJob 控制台创建 App,例如 billing-service,再在业务应用中加入配置:
powerjob:
worker:
enabled: true
app-name: billing-service
server-address: 10.0.10.21:7700,10.0.10.22:7700
protocol: http
port: 27777
store-strategy: memory
max-result-length: 8192
max-appended-wf-context-length: 8192server-address 使用 Server 的 Web 端口,不加 http:// 前缀;多个地址用英文逗号分隔。Worker 的 port 必须能被 Server 回连,同一主机部署多个 Worker 时需要使用不同端口,也可以在 5.1.2 中配置非正数以选择随机端口。普通单机或广播任务偏向 memory;可能产生大量子任务的 Map/MapReduce 更适合 disk,以降低内存压力。
开发环境没有 Server 时,可以临时设 allow-lazy-connect-server: true 让宿主应用启动。这个选项只放宽启动时连接要求,不代表 Worker 已经注册,也不能作为集成测试通过的证据。
编写一个 Spring Bean 处理器
package com.example.billing.job;
import org.springframework.stereotype.Component;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
@Component("dailyBillingReport")
public class DailyBillingReportProcessor implements BasicProcessor {
@Override
public ProcessResult process(TaskContext context) {
String reportDate = context.getJobParams();
context.getOmsLogger().info("Generating billing report for {}", reportDate);
// 调用业务 Service,并自行保证重复执行时的幂等性。
return new ProcessResult(true, "report generated: " + reportDate);
}
}启动业务应用后,在 App 的 Worker 列表确认节点在线。新建任务时,处理器类型选择内置 Java,处理器信息填写 Bean 名称 dailyBillingReport;也可以填写处理器全限定类名。非 MapReduce 任务还支持在 Spring Bean 方法上使用 @PowerJobHandler,处理器信息写成 Bean名称#方法名 或 全限定类名#方法名,固定提交的方法处理器示例展示了签名要求。
ProcessResult.success 决定 Task 成败,msg 有长度限制并可能被截断。异常可以抛出,但业务处理器通常应捕获可预期异常、记录必要上下文并返回明确结果。PowerJob 的失败重试不会自动让数据库写入、HTTP 调用或消息发送具备幂等性;业务代码需要使用唯一键、状态机、去重表或业务幂等键处理重复执行。
常见配置问题
高频任务的时间策略
官方快速开始的维护者回复指出,CRON 的最小调度间隔是 15 秒;需要秒级高频执行时选择固定频率或固定延迟。固定频率按触发节奏推进,固定延迟会参考前一次完成后的间隔,选择前需要明确任务是否允许重叠。
重试策略
实例重试会重跑整个实例,Task 重试只重跑失败 Task。单机任务若两项都设为 1,最坏可能执行 4 次。通常先把实例重试设为 0,再根据 Task 的幂等性与失败成本设置 Task 重试;大型 Map/MapReduce 的实例级重试尤其昂贵。
Worker 筛选
指定地址、Worker Tag、最大执行机器数,以及最低 CPU、内存和磁盘条件会共同缩小候选集。调试 no worker available 时,应先清空非必要筛选,再逐项恢复。Tag 适合环境或单元隔离,但不能代替网络隔离和权限控制。
Reduce 与在线日志
MapReduce 的 Reduce 阶段需要读取全部子任务结果;超大任务只需要分发计算而不需要集中汇总时,Map 更稳妥。在线日志同样会把 Worker 侧输出集中送到 Server,生产任务应限制数量、单条长度和级别,并为日志存储选择独立于核心调度数据的介质。
业务系统触发
需要按订单或批次触发任务时,先在控制台创建一个 API 类型任务,并为 App 设置独立密码。业务项目加入客户端:
<dependency>
<groupId>tech.powerjob</groupId>
<artifactId>powerjob-client</artifactId>
<version>5.1.2</version>
</dependency>import java.util.Arrays;
import tech.powerjob.client.IPowerJobClient;
import tech.powerjob.client.PowerJobClient;
import tech.powerjob.common.response.ResultDTO;
IPowerJobClient client = new PowerJobClient(
Arrays.asList("10.0.10.21:7700", "10.0.10.22:7700"),
"billing-service",
System.getenv("POWERJOB_APP_PASSWORD")
);
ResultDTO<Long> result = client.runJob(42L, "batch=2026-08-31", 0L);
if (!result.isSuccess()) {
throw new IllegalStateException(result.getMessage());
}
Long instanceId = result.getData();示例中的地址、App、密码和 Job ID 都是占位值。密码应来自密钥管理系统,不写进源码、镜像或普通配置仓库。PowerJobClient 初始化时会校验 App,并能在 Server 集群节点间请求;应用关闭时应释放客户端资源。
5.1.2 的 Server 默认配置 oms.auth.openapi.enable=false 是为旧客户端兼容保留的开关。固定提交的拦截器显示,关闭时 OpenAPI 请求直接放行。生产部署应先把所有调用方升级到支持令牌鉴权的客户端,再设置 oms.auth.openapi.enable=true,同时在网关或防火墙限制 OpenAPI 来源。
生产部署要点
Server 与数据层
生产环境至少需要一套受管控的关系型数据库。官方部署文档称核心持久层基于 Spring Data JPA,可适配多种关系型数据库;仓库提供的完整 Schema 和升级 SQL 以 MySQL 8 为基准,其他数据库或版本应在测试库让目标 Server 自动建表,再对比 Schema 并验证方言、索引和分页行为。
多台 Server 连接同一套核心数据库即可组成集群。Server 间主通信协议由 oms.transporter.main.protocol 决定,对应端口必须互通。默认端口关系如下:
| 端口 | 默认职责 | 暴露建议 |
|---|---|---|
| 7700 | Web 控制台、Worker 发现和 OpenAPI | 只对管理入口、Worker 与调用方开放,公网入口放在鉴权代理后 |
| 10086 | AKKA 通信 | 只在启用 AKKA 的 Server/Worker 网络开放 |
| 10010 | HTTP 传输协议 | 默认 Server 间主协议需要,按集群拓扑开放 |
| 10077 | MU 协议 | 5.1.2 Release 标为 Beta,只建议开发环境验证 |
关系型数据库保存核心元数据。MongoDB、阿里云 OSS 或 MySQL 系列存储扩展用于在线日志和容器文件等非核心数据。若选择数据库存日志,官方部署文档建议使用独立库,避免日志流量影响调度主链路。
账号、权限和密钥
PowerJob 5.x 采用基于角色的访问控制。权限可以收口到 App、Namespace 或全局范围,角色包含观察、测试、开发和管理员等层级。初次部署会创建 ADMIN 超级管理员;生产配置应提供一次性强初始密码,首次登录立即修改,并把日常操作授权到最小范围的用户或企业账号体系。
不要沿用仓库 Compose 的数据库密码、App 密码或管理员密码。数据库凭据、邮件密钥、钉钉密钥、OSS 凭据和 App 密码应进入专用密钥系统。仓库的 SECURITY.md提供私下披露安全问题的渠道。
发布、监控与备份
生产变更至少建立以下检查:
- 固定 Server、Worker 和 Client 版本,不使用
latest;先在预发验证版本兼容和数据库变更; - 监控 Server 可用性、数据库连接池、调度延迟、等待分发实例、Worker 在线数、任务失败率与报警通道;
- 为核心数据库和日志存储分别制定备份、恢复与保留策略,并实际演练恢复;
- Worker 滚动发布时观察注册与下线,长任务需要明确停止、超时、重试和重复执行策略;
- 对任务创建、修改、立即运行、停止和 OpenAPI 调用保留最小必要权限与审计链路。
升级与迁移
仓库当前 Release 为 v5.1.2,并在 others/sql/schema/ 保存版本化 MySQL Schema,在 others/sql/upgrade/ 保存部分升级脚本。5.1.0 到 5.1.2 的脚本会为实例表增加 extend_value、meta、outer_key 和索引。官方也明确说明,脚本并不覆盖所有数据库与所有版本组合。
兼容升级可以按“备份与恢复演练、测试库 Schema 对比、预发 Server、Worker/Client 回归、灰度 Server、观察、全量”的顺序进行。跨不兼容大版本时,官方建议新旧 Server 与数据库环境并存,逐个 App 迁移 Worker,验证后再关闭旧调度环境。直接让新版本 Server 指向唯一生产库,会把数据库迁移和应用兼容风险压到同一时刻。
版本升级前至少核对三处信息:Release notes、目标版本的 Schema 与升级目录以及官方升级手册。数据库备份存在不等于能够恢复,切换方案需要包含回滚触发条件和旧环境保留时间。
适用场景与替代方案
| 需求重心 | 更值得考虑的方向 | 关键判断 |
|---|---|---|
| 多个 Java 应用需要统一任务治理、跨节点执行、Map/MapReduce 或 DAG | PowerJob | 接受维护调度中心、数据库、网络和权限体系 |
| 单个应用只有少量定时方法 | Spring @Scheduled 或 Quartz | 组件更轻,但跨应用治理与可视运维需要自行补齐 |
| 团队主要需要中心化定时任务与简单执行器 | XXL-JOB 等同类调度平台 | 对比执行模型、权限、日志、迁移与社区版本,而不只比较功能数量 |
| 任务天然是独立容器,并运行在 Kubernetes | Kubernetes CronJob 或工作流系统 | 与集群调度、镜像和资源模型更一致,业务内 Spring Bean 调用不再直接 |
| 流程包含人工节点、补偿事务和长周期业务状态 | 专用工作流或流程引擎 | PowerJob DAG 偏任务依赖编排,不承担完整业务流程语义 |
采用 PowerJob 前最有效的下一步,是挑一个可回滚、可重复、能观察结果的真实批处理任务,在预发环境完成四项验证:一台 Worker 离线时怎样恢复,处理器重复执行是否幂等,日志和结果增长是否可控,Server/数据库故障后怎样恢复。四项结果比功能表更能说明 PowerJob 是否适合当前团队。
版本与验证边界
本文基于 PowerJob v5.1.2、固定提交 332179d,核对日期为 2026 年 8 月 31 日。仓库采用 Apache-2.0 许可证,GitHub 语言统计以 Java 为主;最新公开 Release v5.1.2 发布于 2025 年 8 月 17 日。
研究过程读取了中英文 README、官方产品手册、Release、Compose、Maven 模块、Server/Worker 配置、处理器 SDK 与示例、客户端接口、权限初始化、OpenAPI 鉴权、数据库 Schema 和升级脚本。没有构建或执行 PowerJob 源码,没有启动容器、连接数据库、登录在线试用环境或验证生产性能。文中的命令、默认值与机制属于固定来源和静态核对,不是运行时测试结论。
主要入口包括仓库主页、官方产品手册、快速开始、Server 部署、Worker 初始化、处理器开发和OpenAPI。官方手册与固定源码出现差异时,本文优先采用 5.1.2 固定提交,并把动态文档作为操作说明来源。