背景介绍
随着城市打车需求量和在线司机数的增加,基于城市进行派单的技术架构就会逐渐成为瓶颈,单台服务器无法承担住一个城市的订单流量。而这其中,实时单和预约单派单流程不分离,更加剧了单服务器的压力。
从打车的业务场景出发,实时单和预约单本就是两个完全不同的打车流程,主要体现下在如下几个方面:
- 找车范围: 实时单主要找周边的司机,预约单会从更大的范围或者全城来找司机。
- 接单方式: 实时单一般不征求司机的意见直接派单,预约单一般都是让司机自己决策是否抢单。
- 策略差异: 实时单和预约单派单策略差异非常大,无论是订单和司机的筛选策略,还是订单和司机的匹配策略,都是完全不同的两套策略。
既然如此,为什么预约单和实时单的派单流程没有从一开始就隔离呢?
追溯合理性
实时单和预约单从业务流程上貌似没有共同点,两个业务流程可以很好的分离。但是,我们仔细深究一下两个流程的共用资源就会发现问题,实时单和预约单都会派送给司机,如果两个流程各自独立就会引发共用资源冲突,示例如下:
比如:实时单派单流程中订单A派到司机D,同时预约单流程中订单B也派到司机D,由于是两个独立流程,如果司机D在服务订单A和订单B时出现时间冲突,那么如何在两个流程中控制好这个冲突。由于是并发问题,对共用资源司机占用时就要进行加锁,同时要控制好抢占司机的优先级,是谁先抢占给谁,还是实时单优先预约单,这些技术问题都会增加派单流程的复杂性。
如果实时单和预约单在一个派单流程中进行处理,就不会出现以上问题。因为在一个流程中控制,司机派了实时单还是预约单,这个上下文的数据是可以共享的,你也可以控制策略让司机优先派给实时单,没有实时单时再派给预约单,这样就从根本上解决了司机冲突的问题。
还有一个更重要的原因是: 公司初期实时单和预约单的流量都很小,策略也都很简单,合并在一个流程里,既能够满足业务的要求,又能够减少技术的复杂性。对于初期来说,这就是一个合理的架构设计。
解决方案
基于业务对实时单和预约单各自策略复杂性的发展,两个流程再进行耦合会导致技术的复杂性越来越高,再加上背景中说明的原因,实时单和预约单派单流程分离势在必行。
那如何解决上面公用资源司机冲突的问题?
- 对于离当前时间超过2小时的预约单,和实时单可以不进行冲突校验。因为99.9%的实时单服务时间不会超过1小时,中间还有1个小时的缓冲时间去服务预约单,冲突的概率太低。
- 对于离当前时间小于等于2小时的预约单,需要在两个独立流程中,分别进行冲突校验。
- 实时单派单流程: 对司机增加分布式互斥锁。判定司机身上是否有预约单?
- 否: 无需检查
- 是: 判定预约单是否已经进行过检测
- 是: 跳过
- 否: 进行检测
- 预约单派单流程: 对司机增加分布式互斥锁。判定司机身上是否有实时单?
- 否: 无需检查。
- 是: 进行检测
- 司机正在实时单的派单中,则进行过滤
- 司机正在服务实时单,则直接推送给司机,司机自行选择。
- 实时单派单流程: 对司机增加分布式互斥锁。判定司机身上是否有预约单?