Webman 本身不内置调度算法,但可通过独立进程(如 DispatchProcess.php)、协程 I/O、Redis 预计算与原子操作支撑高并发派单;HTTP 接口仅负责订单提交与状态查询,调度逻辑严禁塞入 onRequest,须用定时器驱动、Redis Geo/Lua/Sorted Set 加速匹配,并通过 GatewayWorker 实时推送结果。

Webman 本身不内置调度算法,但能撑住高并发派单压力——关键在你怎么用它组织进程、封装协程 I/O、隔离状态计算。
Webman 怎么跑调度服务而不卡住 HTTP 接口
调度逻辑不能塞进 HTTP 控制器里执行。一旦在 onRequest 中做骑手匹配、路径计算、批量更新状态,整个 Worker 进程会被阻塞,后续请求排队等待。
- 把调度任务拆成独立进程,放在
app/process下,例如DispatchProcess.php - 该进程启动时调用
onWorkerStart初始化 Redis 连接、加载骑手缓存、设置定时器(如每 500ms 扫描一次待派订单) - 用
Swoole\Timer::tick()触发调度循环,避免while(true)占满 CPU - HTTP 接口只负责“提交订单”和“查询状态”,调度结果通过 Redis Pub/Sub 或数据库字段变更通知前端
为什么不能用 PDO::query 做实时骑手匹配
同步数据库查询在调度高频场景下会拖垮性能。比如扫描 1000 个骑手 + 计算 Haversine 距离 + 更新状态,PDO 每次 execute() 都要等网络往返,协程无法挂起,等于白开。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 改用
Swoole\Coroutine\Mysql,连接复用且 query 调用自动协程挂起 - 距离计算必须前置:骑手位置用 Redis Geo 存储,用
GEORADIUS快速圈出 3km 内活跃骑手,再在 PHP 层做精细加权评分 - 避免在调度循环中反复查订单表,用 Redis Sorted Set 按
created_at维护待派队列,ZRANGE拿头部 N 条 - 状态更新用 Lua 脚本原子执行,防止多个调度进程同时抢同一个骑手
加权调度模型怎么在 Webman 里落地
权重公式本身是业务逻辑,Webman 只提供执行环境。难点在于数据获取的时效性与一致性。
- 骑手实时位置从 GatewayWorker 的 WebSocket 连接中上报,存入 Redis Hash(
rider:1001),带updated_at时间戳 - 历史效率指标(如平均送达时长)存在 MySQL,但不能每次调度都查——改用定时任务每 5 分钟聚合一次,写入 Redis Hash 字段
- 负载因子(
current_load / max_load)直接从 Redis 读,确保和实际接单数一致 - 评分函数封装成独立类,输入是骑手 ID 和订单对象,输出 float 分数;不依赖全局状态,方便单元测试
- 最终选中的骑手,用
SETNX rider:1001:locked 1 EX 30加锁,防止重复派单
真正容易被忽略的是调度决策的“可见延迟”。哪怕算法再快,如果骑手端 3 秒才收到推送,用户看到的就是“下单后没人接”。Webman + GatewayWorker 的组合必须打通,让 dispatch() 结果立刻推送到对应骑手的长连接通道,而不是等轮询或消息队列消费。


















