Hyperf 多进程定时任务需确保有且仅有一个实例执行,核心是统一调度、分布式锁与进程感知;推荐 Redis 分布式锁,配合哈希取模或服务发现实现动态分片,并注意时区统一、协程 sleep、日志隔离与超时兜底。

Hyperf 多进程环境下执行定时任务时,若不加协调,容易出现多个 Worker 同时触发同一任务,造成重复执行、资源争抢甚至数据异常。真正的“负载均衡拆分执行”,不是简单让多个进程各自跑一套 crontab,而是让任务在集群中**有且仅有一个实例执行**,同时支持横向扩展和故障转移。核心在于:统一调度 + 分布式锁 + 进程感知。
用 Redis 分布式锁保障单例执行
这是最常用也最稳妥的方式,适用于绝大多数业务场景。Hyperf 的 @Crontab 支持原生 mutex 配置,只需启用 Redis 并正确设置即可:
- 确保已配置好 Redis 客户端(
config/autoload/redis.php) - 在定时任务类中声明
$mutex = ['type' => 'redis'] - 可选增强:指定
key和ttl,避免锁残留 - 注意:Redis 连接必须是共享的(非每个进程独占),推荐使用连接池
按进程 ID 或主机名做静态分片(适合固定节点数)
当任务本身可拆分(如批量处理用户数据),且节点数量稳定时,可用“哈希取模”方式将不同子集分配给不同进程:
- 在
execute()中获取当前进程标识:getmypid()或$_SERVER['SERVER_NAME'] - 对总数据量或 ID 范围取模,例如:
where('id % 4', $pid % 4) - 优点:无外部依赖、执行轻量;缺点:扩缩容时需重算分片逻辑,不自动适应
结合服务发现实现动态任务分片(高可用进阶)
在 VPC 或 Kubernetes 等环境中,节点 IP 和数量常变动,此时应借助服务治理能力动态协调:
- 利用
hyperf/service-governance注册所有 Worker 实例 - 任务启动前,通过 Consul/Nacos 获取当前全部健康节点列表
- 用一致性哈希(如
md5($taskName . $nodeId))决定哪个节点负责该任务 - 配合
singleton = true+mutex双保险,防止网络分区导致误判
避免踩坑的关键细节
多进程定时任务不是开箱即用,几个易忽略点直接影响稳定性:
-
时区必须统一:所有节点系统时区 +
crontab.php中timezone配置保持一致(如'Asia/Shanghai') -
不要依赖
sleep()模拟调度:协程环境下sleep会阻塞整个协程,改用co::sleep() - 日志隔离很重要:不同进程写同一日志文件易混乱,建议按 PID 或主机名命名日志文件
-
任务超时要兜底:长时间运行的任务需设
set_time_limit()或手动检查执行耗时,防止堆积阻塞后续调度


















