派单是代驾系统的调度核心
用户下单后,系统要在几秒内从成百上千个司机里选出“最合适的那几个”推送订单。派单慢,用户等待流失;派单不准,司机不愿意接。本文拆解一套开源代驾系统的智能派单链路。
源码地址:
https://gitee.com/zhoujian6666/biaoma-ride-car-service
派单要解决的三个问题
- 找得到:怎么快速知道用户附近有哪些在线司机
- 排得准:附近司机里,先推给谁
- 转得动:第一个没接怎么办,怎么自动流转
一、附近司机检索:为什么用 Redis GEO
如果每次都查数据库算距离,高并发下数据库扛不住,且实时性差。系统让所有在线司机的实时位置写入 Redis:
- 司机端通过 Netty WebSocket 长连接每隔几秒上报 GPS 坐标
- 服务端用 Redis 的 GEO 数据结构(GEOADD)存“司机 ID → 经纬度”
派单时用 GEOSEARCH(或 GEORADIUS)按“用户上车点 + 半径”一次性取出附近在线司机,操作是内存级的,延迟在毫秒级。
同时用 Redis 记录司机在线状态,离线或心跳超时的司机不会进候选集。
二、排序:不是只看距离
取出附近司机后,要综合多个维度打分排序:
- 距离:离上车点越近优先级越高(接驾时间短)
- 司机评分:历史服务星级、好评率
- 服务分/完单率:取消率低、完单稳定的优先
- 司机当前状态:是否有未完成订单、是否设置忙碌
实践中常用“加权打分”或“先硬过滤再排序”:先用硬性条件(在线、空闲、证件有效)过滤,再按距离和评分加权排序。
三、推送与流转
排序后的候选司机不是同时推送,而是分轮:
- 取 Top N 司机,通过 Netty 通道定向推送订单(含预估里程与收入)
- 设置接单超时窗口(如 15 - 30 秒)
- 有人抢单:订单锁定,通知其他司机该单已结束
- 无人接单:扩大搜索半径或降低条件,进入下一轮推送
- 多轮失败:订单进入“调度失败”状态,后台可介入改派或通知用户
抢单并发控制
多个司机同时点“抢单”时,必须保证只成功一个。系统用分布式锁(Redis)或数据库乐观锁:以订单 ID 为锁键,第一个抢到的司机拿到锁、更新订单状态,其余抢单请求直接返回“已被接”。
派单和计价、推送的联动
- 下单时先调用高德路径规划算预估里程,配合计价引擎给出预估价
- 推送内容带上预估价,司机决策更清晰
- 派单结果、状态变更通过领域事件触发 Netty 推送和 RabbitMQ 异步通知
性能与稳定性细节
- 位置上报有节流:坐标变化太小或时间间隔太短不上报,减轻写入压力
- Redis 操作设超时与降级:缓存异常时可降级为数据库粗筛
- 推送失败可补偿:关键派单消息配合 MQ 做可靠投递
项目其他模块
除智能派单外,系统还包含:订单状态机、Netty WebSocket 实时推送、计价引擎、微信/支付宝支付、分润对账、管理后台。后端 + 管理后台已开源(Java 17 + Spring Boot 2.7 + Vue),可直接部署。
源码:https://gitee.com/zhoujian6666/biaoma-ride-car-service
欢迎评论区交流派单与 LBS 相关设计,觉得有用欢迎 Star。