滴滴专车业务与技术流程


written by Alex Stocks on 2015/11/20,版权所有,无授权不得转载

0 引言

近日读到文章《揭秘全球最大一站式出行平台的技术真相》,对其中一些内容颇感兴趣。

然原文错字连篇,SDCC2015的ppt也没有放出来,没有相关业务背景的人读起来可能味同嚼蜡。现结合原文,根据个人的理解,重新把相关内容整理如下,文中斜体字段是个人的理解或补充。

囿于个人水平有限,如有错误,欢迎指出。

1 滴滴的市场占有情况

2 滴滴平台背后的技术体系

一个是在线业务系统,另一个是大数据平台(个人理解,应该包含了离线业务系统)。

用户与滴滴平台维持一个长连接,实时上报位置信息,每天能产生10T的位置数据供大数据平台分析。同时用户也可以通过http与后台进行业务交互,如进行订单、计价、券系统、支付、分账,每日有上千万的订单。在线业务系统包含了服务、坐标流、弹性定价(“知道以什么样的定价更合适”)和分单(“怎么招到最合适乘客和司机”)等子系统。

大数据平台任务之一就是spam,防止用户“刷我们的奖励和我们的券”。

大数据平台任务之二是进行用户画像(听着貌似是离线数据分析),了解用户的偏好。

3 用户打的或者使用专车详细流程

3.1 打开app时的平滑移动功能

乘客准备要出发了,他打开了我们的App,首先看到的是我们的一堆车标,有时候调头了,这是平滑移动的功能,如果是滴滴的老用户的话,应该了解到在出租车的时候,其实是没有这个功能的。

乘客app与后台维持一个长连接,每5s向后台上报一次位置信息,位置信息大概有{方向、速度、精度(疑应为经度)、维度(疑应为纬度)}。出租车每3秒向后台上报一次位置,通过两次数据上报就能获取到方向、速度,可以预测车头的方向,滴滴后台每天能够收到数十亿次上报请求。

3.1.1 平滑移动详细流程

3.2 用户发单时的定价功能

3.2.1 弹性定价的原因

滴滴虽然是出行平台,但是本质来说我们是综合交易的交易平台!我们提供一个交易引擎,更多的是希望交易更好达成。但是如果有一些经济学原理的知识的话就会了解到,其实价格才是调节市场供需的杠杆!

正常的情况是我们对于价格的定价,逐渐调整价格,达到一个平衡点,这时候乘客愿意叫车,司机愿意提供运力!但是有一些极端的情况,暴风雪天气,或者整个会场要结束的时候,大家同时要回家,需求是同时爆发的,但是供给不一定马上给上。以极端情况为例,一个是堵车,另外一个是暴风雪,司机不愿意出来拉活,乘客能不能寻找到一些替代品?比如说他不再打车,他去做顺风车或者地铁,提高价格之后也会刺激司机的接单的积极性,达成新的平衡。

3.2.1 由大数据后台辅助的弹性定价

乘客的App要发单了,定单请求到我们的在线业务系统,把这个定单的需求专发到动态的模块,大数据平台会考虑当前的供给和需求,综合考虑以下几个情况:

我们会借助在线学习的方法来更好更快速的得到合理的定价(个人感觉有点吹牛了,估计就是根据LBS位置附近的天气情况、乘客数量/司机数量之比、距离、随机权重等几个参数算出一个值而已)。

3.2.2 弹性定价的效果

在正常的情况下,动态条件下可以使我们的应答率提高两个点,但是应答量只有一个点。

在极端的天气情况下,动态调价可以使我们的平均应答率提升10个点以上,应答量的损失只有两个点。在整个车速过程中有一个特别极端的例子,是在武汉,一次暴雨的天气动态调价没有上之前和上之后的调价是惊人的,在动调的逻辑上线之前只有53%,我们把动调的危机打开了以后成交率达到85%。这部分乘客是什么样的表现呢?被调价了以后,这些乘客更愿意留在平台!他比没有调价的用户留存率会提高17个点,这足以证明大家到这个平台上来更多的期许是能够打到车,也许会贵一两块钱,但是最重要的目的是能打到车,这是刚需,他的第一需求。

3.3 发单

动调这个环节乘客已经把定单发出来了,订单到了整个平台这里,平台需要把整个定单分配出去,就是发单。

3.3.1 挑战

在一个热点的城市,它的在线司机可能有数万这样体量,需要分配的订单可能有几千上万,针对这样的分配实际是二元组的矩阵,这个矩阵的节点数有十亿!

3.3.2 初始解决方案

我们第一版的时候是外包开发的产品,分单引擎或者模型非常的简单,一个订单来了,我们检索到周边的司机,做好分配,这个分配信息先写到数据库,司机来了以后,直接查找数据库,就能找到对应的定单信息了。这是出租车的1.0!

提到这一点,更多的想说作为一个创业的企业,需要的是更快的速度,至于架构怎么用?或者说有多好?可以慢慢的来!最重要的是我们的迭代速度。

3.3.3 改进方案1.0

后来发现查找数据库这个事情不靠谱,一个订单来了以后我直接通过步行推送出去,后面分配的效率不够高,我们需要对相应的定单和周边的司机做一个全局的优化,同时在分配效益上面能够类似于一个电梯的调度上,先聚一会,大概几百豪秒或者一秒的时间,先聚在一起,通过我们的策略进行优化订单。

司机的App通过长链接服务把它的IT信息放到我们的池子里,通过在线的系统把我们订单信息放到池子里,依据这个池子里当前的司机和订单的特定信息,通过策略计算找到合适的订单和司机的消息然后分发出去!好处是不需要分片,单机就可以计算!

随着定单量的逐渐提升,这种模式下面分单这个模块成为了一个瓶颈,为什么呢?因为它需要去池鱼里拿到ID信息,从特征服务里把每一个订单、每一个司机的特征全部拉回来,做一个矩阵的计算。计算完了以后分配出去,再把分配的结果保存下来!它能成为瓶颈。

3.3.4 再改进方案2.0

我们开始2.0的改进,2.0的时候,我们没有去调整分单,我们的想法是把分单的模块做分期部署,然后将订单和运力做一个切片,这都是在一个城市里所有的信息。

运力和定单都做了切片(个人理解,一个切片就是一个池子)以后,现在性能没有问题了,但是我们会发现因为这种切片会对整个策略的分配情况是有影响的。主要还是在分片的边缘,如果是指派的情况下,我分配只能在分片里进行分配,分配的时机未必是最合适的时机,如果在这种分配的情况下造成司机并不愿意接单,如果有四个切片的话,对于我们应答率的影响是将近一个点!但是,如果把分片切成八个,我们应答率损失在三个点以上,这是巨大的损失。而且它的效率虽然提升了,但是并没有太好,如果说是有5万的在线司机和一两千的订单同时分配的话,它的分配时间大概要在2.5秒左右!这并不够高效,我们希望整个分配在1——2秒就能完成,同时支撑更大的数据量。

3.3.5 目前方案3.0

大概10月份上线的分单引擎总的思路是不再做分片,把整个城市的订单和运力同时放在一个池子里,在分单的环节做分布式的计算。先从池子里把所有司机的ID和订单的ID全部拿过来做分配,分配到不同的分布式的处理器上,自己去拉取特征信息,做小的矩阵计算,所有的矩阵汇聚到一起,作为一个预算,最后得到大的预算,全局的矩阵。针对这个矩阵其实就是定单和司机二元组的关系,我们把它分配出去,分配完了以后需要将结果记录到我们的存储里面,以便于进行下一次的分配!这几个改造历时了一个半月左右,最后达到的效果还不错,如果十万个司机在线,一万的订单,我们可以在1.7秒以内把整个分配做完。

3.4 坐标流服务

订单分配出去了,司机接单了,用户可以通过App向它行使过来。这个过程中把司机的坐标收集起来,然后给乘客一个更好的呈现,这是一个坐标流服务,。

乘客和司机将坐标信息传递到坐标流里面,首先把坐标存储起来,在坐标存储的过程中,分为持久存储(做后面大数据挖掘和客户查询相应的坐标轨迹)和缓存,整个后端会维护着司机和乘客的对应关系,当乘客上报坐标的时候就能知道司机的坐标,司机上传坐标的时候就了解乘客的位置。

3.5 地址围栏与营销活动

地址围栏是我们做营销活动的时候,你要去机场给你派一个机场券,接送机的券,再做活动,针对活动的人群做特殊的撤销。

3.5.1 坐标流与地址围栏

用户上报坐标流的时候,会顺带一些业务状态,数据库存储LBS信息的时候也会存储一些业务状态的编码信息,它的数据结构是一个跳表,支持读写的并发处理,可以支持我们的节点的超时管理。整个数据在内存中是保证安全性的,相应的扩展性、各方面都挺好。如在五公里的范围内,如果节点密度超过几万的话,我们一次查询时间在一毫秒就可以完成。整个检索服务的集群可以承载的数据节点可以超过一亿点。

地理围栏是判定一个围栏形成一个事件,服务器收到用户上报的坐标流的时候,如果坐标在围栏内,就把他放到消费队列里共各个业务方去调阅。

3.5.2 营销实例

有这样的一个场景,我们要针对北京机场的用户去派一张接送机的券。首先运营的同学围着手机机场画一个圈(地址围栏),然后会设定地址围栏500米外面的预警圈。等到坐标上传的过程中,到预警区的时候写一个事件放到消费队列里面,业务系统订阅了这个消息,就知道这个时候乘客已经到了首都机场周边500米了,这个时候会触发一个行为,发一个短信或者弹窗提醒,告诉我们的用户我们有这样的活动,或者这样的促销。用户到了围栏的时候,是另外一个事件,只有在围栏里面才允许他使用这样的券,这也是基于反作弊的考量。

3.5.3 特殊情况--多个地址围栏之间的交接

地址围栏可以是自定义的多边形,也可以是行政区域任意的组合,多个地址围栏之间可能有交接。如果某个地域有几千几万几百万这样的围栏,一个坐标来了之后我需要知道到底属于哪个围栏?需要做一个预盼和筛选!我们的做法是这样的,针对围栏区域设置内聚型和外聚型,快速判定他是否属于这个围栏,从而优化我们查询的速度!关于围栏内部的监测是基于一个比较常规的方法,针对多边形的边区引入一些射线出来,判定这个射线的焦点是奇数还是负数,当前我们单机实力可以支撑水平的扩展。

3.6 专车计价

出租车有一个计价器,不需要记价,到终点的时候司机告诉你是十块还是二十块,大家直接拿出微信支付或者支付宝直接支付就完了,不用无线支付就用现金进行线下支付就完了,使用专车的时候计价就是挑战,专车没有记价器!

3.6.1 挑战

我们面临的挑战是到底在乘客端计价,还是司机端上计价,还是其他什么方法?

无论乘客还是司机,手机的 GPS芯片很差 ,被 安全软件拦截 了没有办法进行上传和定位,上传的数据质量也不是太高, 精度问题和定位漂移问题,尤其是一辆车停下来以后,整个坐标上传的结果在周边不停的跳动!

还有移动网络的不可靠,到地下通道的时候没有网络了,坐标没有办法上传!这都是针对计价准确性的挑战。

还有企业用车,根据不同的时段计价又不一样!他去机场和火车站定价又不一样,这是产品形态的多变,会在灵活性和对于整个架构和复杂度带来的提升。

3.6.2 精确定位

司机端每一秒会去做定位,十秒形成一个包,将这个包通过长链接的服务上传上来,上传到实时计价模块,需要解决两个事情,一个是降噪,另外是补偿器。(两个包上传的坐标的距离)在30米以内我们会采用这个点,如果精度在30米以外我们会抛弃掉,会通过地图的API的接口做数据补偿!经过模块处理了以后,这基本上是一个比较准确的数据线路。

3.6.3 防作弊

在反作弊的环节会考虑这样的事情,根据现实情况可以给出以下防作弊规则:

3.6.4 灵活性处理

关于计价系统的灵活性,更多的是依赖规则引擎,它是通过一条规则,在规则引擎里进行解析,最后得到一个结果。针对我们各种各样的活动,不同的产品形态,还有不同的乘客的画像,这次出行的起点在哪里?终点在哪里?什么时候出发的?多个维度定义出一条规则来?通过规则引擎做解析以后得到一个计价ID,这就确保了一个计价的灵活性。

3.6.5 支付

计价完了乘客可以选择多种支付渠道、支付宝和手Q、微信支付、待充值这样的支付方式,这次出行就结束了。这是当前针对出行过程中的核心系统的概况。

4 运维问题

4.1 挖掘机风险

我们接下来或者当前比较急迫的是需要进行跨机房的过程,它面临的问题是网络、机房可能不靠谱,一旦建筑工人一铁锹挖下去光缆就断了,我们在10月份的时候就有过一次机房的网络瘫痪了,终止服务了一段时间。

4.2 跨机房解决方案

针对整个跨机房的解决方案,我们构想是这样的,前面有一个Proxy来解决,到底是机房1还是机房2,北京是一个围栏,上海是另外一个围栏,北京部署在机房1,上海部署在机房2。对应着这样的部署。所有的业务流程往走,但是到存储节点的时候,会把数据信息囤到相应的机房。这是我们急切或者正在做的动作。(没有看到ppt,这段个人就不发挥或者想象了,否则会有误导)。

4.3 自动化运维平台

另外是关于自动化运维平台的构想!数据收集平台会收集各种各样的数据信息,全部收集起来,它就形成了数据支撑,在自动化的运维平台里要去关注对于机器的管理,对于预警的处理和容量的管理,以及容灾处理。容量的管理这一部分更多的是为了应对我们不定期的促销活动,可能一个决策信息或者是一次快乐周末的大促,我们需要评估当前的容量是否能够支撑?有一个容量的评估模型?快速的判定哪些模块需要改造的?哪些需要扩容的?经过自动化部署把扩容这个事情做了,针对线上出现的灾难,比如光缆被建筑工人刨断了,有相应的降低预案,通过监控的处理和预制判断,制度的流程和平台的切换,最终会产生一个解决方案,通过配置和更改的方式,影响到了我们在线业务系统。

5 关于坐标流的一些补充

司机的坐标流是三秒一次,只要他在线,这个坐标就会不断上传,这个时间轴上,可以做很多事情:

当订单需要分配的时候,我们的乘用模块通过检索找到一个时间切片,当前这个时间切片或者司机是空闲的做一些筛选就可以完成自己的订单分配。


参考文档:

Payment

于雨氏

于雨氏在原文基础上扒粪后有此新作。2015/11/20,于金箱堂。