当前位置:网站首页 >> 生活

Go語言打車軟件后端系統算法與實踐

时间:2019-04-30 23:53:36 来源:互联网 阅读:1次

社區導讀:各位,本篇為大家介紹如何構建一個打車軟件,使用Go語言和相干后端算法。類似于滴滴或Uber,包括在內存中保存出租車的行進動態,如何以動畫形式將行進路線顯示、路徑優等算法。

概述

这个故事的起源是在2015年,我的设计课题就是开发一款移动端软件,叫做“移动打车运用”。在这款应用中,可以实时显示出租车/或共享汽车的行驶和移动状态。

类似于下面的界面:

我想让用户在屏上实时监测到汽车的行驶动态。但是会遇到一些挑战:

缺乏数据。我们需要15秒钟就要取得汽车的新的位置。我们不能只缩减更新时间间隔。

由于当司机端程序上行数据时,同时需要获得当前定单和下一个订单,另外还有报警功能(给司机使用的一个SOS按钮,当司机有难按下此按钮时,其它的司机会收到后来帮助他)。

另外,如果我们只是减少更新间隔,后端系统承载的流量会变大。

到底有多大,我心里也没底。

因而我开始做一些尝试。

步开始尝试,我做了如下处理:

1、处理请求,保存汽车的坐标

2、创建另一个请求并为汽车创新动画

大家在Uber、滴滴、易到之类打车软件所看到的,汽车画面是动态的。

因为我们取得的机动车坐标比较粗糙,时间也比较长,泡车们可以跑在田野,森林或者开在河里,甚至开在小区的楼顶,想象一下这是一群什么神奇的车?如下画面:

我开始为此问题寻觅解决方案。我找到并使用一款被称为开放街景线路机器OSRM(OpenStreetMap Routering Machine)的工具来规划路线,以改善我们的算法。这里,我们仍然使用同样的时间间隔设置。

如下步骤:

1、发起请求

2、获取坐标

3、把坐标发送到服务器

4、通过OSRM规划线路

5、返回数据给客户端

通过上面增加的线路规划体系,现在仿佛可以工作了。

但是我们又面临着单向道路的问题:

比如,一位司机和车是停在红点中的十字路口。因为设备位置的精确性不够准确,数据标记在十字路口的对面或者旁边。客户端获取到地址信息坐标,发送给服务器后端。接着OSRM开始规划一个看似完全无暇的线路出来,再返回给客户端。

因为汽车一直在移动,且移动速度很快,这个路线规则的起点位置就不正确,所以造成的结果也肯定是错误的。

这个场景和在中国使用百度、高德地图很相似,因而这位老司机被规划的线路整蒙圈,结果可能绕了远或走错了路。

我们用较简单的方式来解决此问题:检查两点之间的短距离,并且不建立距离小于20米的线路计划。使用这样的算法,经过几天测试后,我们决定发布更新我们的应用,以获得用户的反馈。

接着,我进行第二次的产品迭代。以下:

1、车费交易的结算。放在司机客户端完成,这样避免无用的要求发送,可勤俭更多服务端资源。另外,在安全、完整性方面考虑,我们要会将交易数据复制并保存。

2、从使用场景上看,当用户打开客户端查看车辆信息后,因为15秒的地址上报时间原因,他需要等15秒后才能看到车的移动。

3、另外,在司机端的GPS模块也存在诸多问题,可能和司机的也有一定关系。

4、,我们想在屏幕上对车的移动加入动画渲染效果。

我们还想解决以下之问题:

1、从司机端收集更多的数据

2、在屏幕上显示车移动的动画轨迹

3、如何节省端流量

4、能够每秒收集一次数据

我们再谈谈关于节省带宽流量的事儿。在白俄罗斯,出租车价格很低廉,就像我们坐公交车一样便宜。比如,从某城市的东边跑到西边大概也就需要2欧元,大概合14.5元人民币,这和中国的二三线城市的出租车价格差不多。

但是和中国一样,的流量费用也不低,如果我们每秒节约100字节,那我们就为公司节省大概20000美金以上。

需要跟踪的数据

1、司机(车)的位置(经度,纬度)

2、司机的会话信息。如司机登录后,后端给到司机端的sessionid

3、订单记录,包括订单ID(Order Id)和车费(Trip Cost)

我们说过,要在每次反馈的信息上小于100字节。那末,我们就在传输协议上来找寻求解决方案。

TCP/IP协议栈的几个协议:

1、HTTP

2、Web Socket

3、TCP

4、UDP

从性能、速度等综合因素考量,我们决定选择UDP。原因如下:

1、我们只发送数据报文

2、不需确认是否投递

3、极精简

4、能够保存更多数据

5、只有20个字节开销

6、在我们国家没有阻挡该协议

数据格式采用序列化方式。我们从以下格式中选择:

1、JSON

2、MsgPack

3、ProtoBuff

我们选了ProtoBuff,由于它对小数据非常有效。如之比较图:

从上面图中,你可以看到后两种格式的长度是ProtoBuff的2倍。

那么我们的数据包有多少数据?

数据一共仅有42个字节

+ 20个字节的IP头

=每次跟踪仅有62个字节。

当我们取得到数据,需要存储它,对吗?

需要存储的数据

数据需要持久化存储。我们要保存哪些数据:

1、司机同志的会话信息(Session Id)

2、车辆的车牌号

3、订单号(Order Id)和计费记录

4、每次查询后的位置

5、第N次的位置以计划路线

用什么数据库系统保存

1、使用Perconna数据库做持久化存储

2、使用了Redis做为缓存

3、使用ElasticSearch做为地理编码查询

如上所述,比如有600个司机同时,在这些地方搜索数据并不方便,因此需要geo地理信息索引。

我们观察到有两个地理索引算法:

1、KD树

2、R树

我们对地理索引的需求:

1、我们需要搜索N个近的点

2、我们需要一个平衡树,以便在差的情况下提供的搜索

KD树

关于KD树,请看下图:

我们评估了KD树,因为它不是一个平衡树,并不合适我们的需求。虽然可以在KD树上实现k-nearest邻居算法。但是我们其实不需要再重复造一个轮子,由于R树已解决了这个问题。

如下图:

如你所见,它们长得是这个模样的。这样我们就可以执行搜索N个近点,且它是一个平衡树。因此我们选择了它。

你可以点击查看详情找到用Go语言实现的源码包。

以下是我们的存储结构:

1、我们将所有数据存储在内存中

2、使用R-tree来搜索近的司机

3、因此,我们用了两张检索图上,分别对应车牌号搜索与按会话Session进行搜索。

完整的算法

以下介绍后端使用的终算法。

1、使用UDP协议获得数据

2、尝试从持久化存储中取得司机数据

3、如果存储不存在,则从Redis缓存获取

4、检查并验证数据的完整性与有效性

5、将司机数据持久化存储

6、如果不存在,则初始化LRU

7、更新 R-tree

HTTP接口与结点

我们实现了以下结点并集成到系统中:

1、返回近的司机

2、通过车牌号或会话(session id)在存储中删除司机

3、获取行程信息

4、获得司机信息

小结

我们实现的打车软件界面如下:

总结一下打车软件后端的几点:

1、使用UDP+ProtoBuff精简数据来节省带宽

2、使用内存数据库存储

3、使用R-tree(R树)来获取近的司机

4、使用LRU 缓存用来存储的N个位置

5、使用OSRM来匹配地图和定制化行进线路

相关样例,可以到以下地址获取:

代码看似简单,但本篇文章的大多数功能在里面均已实现。

作者:21CTO社区 综合编译

说明:若转载请注明出处。技术原创类文章请注册21CTO站发表

来源:

肝癌会导致传染吗
残胃癌有哪些信号
与胃癌晚期能活多久相关的因素有什么

相关文章

一周热门

热点排行

热门精选

友情链接: 综合 数码 微信小程序推广 技术资讯
媒体合作:

Copyright (c) 2011 八零CMS 版权所有 Inc.All Rights Reserved. 备案号:京ICP0000001号

RSS订阅网站地图