如何高效存储海量GPS数据

发布于 2018-10-22 | 作者: 少强 | 来源: 阿里云 | 转载于: 阿里云

基于部标JT/T808协议及数据格式的GPS服务器开发

最近几年,移动设备已经非常普及,对GPS的使用也越来越常见,比如快车专车产品中的实时位置和历史轨迹图,运动App中的跑步,骑行轨迹等,很多研发人都遇到了如何设计系统架构来高效存储和查询GPS数据的问题。

对于一个互联网产品,要面对大流量,突发大压力,要保证低延时,高稳定性,还要考虑以后的实时扩展性,作为负责人的话,还需要考虑成本。这样,设计一个满足这些需求的系统就不怎么简单了,比如下面这些应用。

在这篇文章中,我们将通过设计一个骑行类App的GPS功能来说明多种使用场景及其区别。

产品功能

我们先明确这款骑行产品需要具备的基础功能:

  1. 用户骑行过程中,App记录GPS轨迹
  2. 用户在骑行过程中可以在手机App中看到自己当前的位置,历史骑行轨迹以及最大时速,平均时速,骑行时间等统计值
  3. 用户在骑行完成后,可以查看自己历史的骑行记录
  4. 给好友、家人或恋人实时共享当前轨迹
  5. 运营需要分析用户轨迹某个维度的特征

存储系统

首先,我们来看一下此类产品的特点:

  1. 用户数大,比较有名的产品可能会有百万,甚至更多的用户。
  2. 有明确的高峰低谷,比如早晨,傍晚是高峰期,凌晨是低峰期。
  3. 存储的数据量比较大,数据量和场景,用户量极度相关。
  4. 产品可能会有爆发发展期,系统需要有非常快速的扩展能力。
  5. 跟时间相关,需要按时间查询范围,或者需要在不知道起始时间和结束时间情况下查询轨迹点。
  6. 成本低。
  7. 稳定性高,尤其是写。

总结下就是:

  1. 高并发写入,尤其是写:具有每秒处理千万请求的能力,且性能不能随着数据增大而下降。
  2. 按量付费
  3. 单表大容量存储,最好不限表大小:PB级别。
  4. 实时水平扩展能力。
  5. 支持范围查询。
  6. 低成本
  7. 高稳定性:SLA保障。

表格存储(Tablestore)是由阿里云自主研发的基于共享存储的NoSQL数据库,是一款专为海量数据高性能存取而设计的存储系统,10G以下免费。

表格存储可以完全满足上述所有要求,另外,还提供多版本,TTL递增ID,增量通道等功能。
确定了存储系统后,我们再来看方案。

方案

表结构设计

表格存储最多支持四个主键,每个主键都支持三种类型,字符串,二进制和长整型,属性列是schema free的,可以自由修改。

在当前方案中,表格存储的表格可以这么设计:

主键顺序 名称 类型 备注
1 partition_key string md5(user_id)前四位 为了负载均衡
2 user_id string/int 用户id 可以是字符串也可以是长整型数字
3 task_id string/int 此次轨迹图的id 可以使字符串也可以是长整型数字
4 timestamp int 时间戳 使用长整型,64位,足够保存毫秒级别的时间戳

如何存

设计好了表结构后,我们可以看一下轨迹数据如何存:
比如原始数据是:

2017/5/20 10:10:10的时候小王在杭州西湖断桥上骑自行车,速度5m/s,当时风速2m/s,温度20度,已经骑行了8公里。

在表格存储中存储的是(10列);

part_key user_id task_id timestamp longitude latitude speed wind_speed temperature distance
01f3 000001 001 1495246210 120.1516525097 30.2583277934 5 2 20 8000

主键

  1. part_key:第一个主键,分区建,主要是为了负载均衡,保证数据可以均匀分布在所有机器上,提高并发度和性能。如果业务主键user_id可以保证均匀分布,那么可以不需要这个主键。
  2. user_id:第二个主键,用户ID,可以是字符串也可以是数字,唯一标识一个用户。
  3. task_id:第三个主键,任务ID,也就是轨迹ID,表示某一次骑行任务的轨迹图,可以是字符串也可以是数字。
  4. timestamp:第四个主键,时间戳,表示某一个时刻,单位可以是秒,如果是每隔10秒记录一个GPS地址,那么相邻行的timestamp就相差10。时间戳1495246210等价于2017/5/20 10:10:10。
  5. 至此,上述四个主键可以唯一确定某一个用户的某一次骑行在某一个时间点的数据

属性列

  1. longitude:经度值。
  2. latitude:纬度值。这个(120.1516525097,30.2583277934)经纬度值表示的就是杭州西湖的断桥上。
  3. speed:骑行速度,可以是当前的瞬时值,也可以是过去10秒的平均值,也可以都记录。
  4. wind_speed:当前风速,这个值无法通过手机采集,需要特定的自行车车载模块。
  5. temperature:当前温度,可以直接取当前城市的温度值,也可以使用特定的温度传感器。
  6. distance:骑行距离,由于骑行的速度不会太快,可以用米为单位。
  7. 上面只是举了几个简单的例子,由于表格存储的属性列是schema-free的,任何时候都可以增删属性列,每一行可以有不同的属性列。甚至可以异步处理后,再回写挖掘出来的一些特征值。

下面我们来看一下各个场景:

GPS轨迹存储

关键点:

手机端:

服务器端

GPS轨迹查询

通过表格存储GetRange接口可以查询到完整历史轨迹图。

手机端:

服务器端

其他人的GPS轨迹查询

关键点:

手机端:

服务器端:

组团GPS轨迹查询

有时候,用户会组团去骑行,这时候,团员都希望可以在一张地图里面看到大家所有人的实时位置和历史轨迹图,团长也希望能通过这些值作为参考,安排大家休息地点和时间。对于这种场景,可以按下面方式实现:

关键点:

手机端:

服务器端:

团员异常路线报警

组团骑行或者组织的大型比赛中,有可能某些成员掉队或者骑错路线,这时候就需要让组织者知道,使用表格存储的stream功能就可以很容易对于异常骑行者做出报警。

关键点:

服务器端:

手机端:

粉丝围观大V骑行

有社区后就有可能会有大V,大V可以在App中搞骑行直播,旁边可以展示GPS轨迹,几十万,甚至几百万粉丝围观,打赏等

关键点:

手机端:

服务器端:

运营分析

全量分析:

增量分析:

直写方案

上述方案已经可以完全满足高并发,低延迟的需求了,那么这个技术架构是否是还可以继续优化呢?当然是可以。上述方案中,手机App其实可以直接将数据存储到表格存储,不需要经过应用服务器中转,减少对应用服务器的压力。

上述5个步骤分别是:

  1. 用户启动后,手机向应用服务器请求写表格存储的写权限。
  2. 应用服务器审批后,如果认为可以给予这个用户写权限,那么可以继续向阿里云的STS服务申请表格存储的临时写权限和授权时间。
  3. STS服务接收到请求后,生成一个临时的令牌,包括临时AccessKeyId,临时AccessKeySecret和临时token,将其返回给应用服务器。
  4. 应用服务器接收到STS的结果后,将其返回给手机端的APP。
  5. 手机端的App接收到临时令牌后,可以向表格存储开始持续写数据。等持续写了一定时间后,临时令牌会失效(失效时间用户可自定义),如果到时候还需要写入,可以继续申请新的令牌。

上述直写方案相对于原有方案,有如下一些优势:

总结

前面讲了如何用表格存储(Tablestore)存储骑行类APP的GPS数据,以及stream功能在各个重要场景中的使用。虽然讲的是骑行类APP,但是其他场景也同样适用,比如跑步类、专车类、车联网等等。这里由于篇幅问题,每个部分都还比较简单,如果大家有兴趣,针对上述的每个点后续都可以继续展开再详细讲讲。