lyan094 2019-05-21 2593浏览量
目前出行市场主要分为传统和新兴两个阵营:私家车、公共交通、出租车和长租车为传统出行提供服务,共享单车、网约车以及分时租赁共享汽车则是最近几年兴起的出行方式。
_图1 出行方式分析_
出行者往往是在成本和出行便捷之间权衡选择出行方式。从出行距离来看,在0~10公里以内,共享单车、网约车以及出租车兼具了低成本以及灵活性两个优势,所以往往是出行者的首选。超过100公里以上,私家车以及长租车则会显现其便捷性。但是在10~100公里之间,则存在一个出行服务真空市场。另外,在一二线城市中,10公里以上的出行需求还是非常大的,加上近几年国家的政策导向,国内出现了很多共享汽车租赁平台。按照罗兰贝格估算,2025年有600万辆分时租赁汽车,每辆车每天3-4单,日订单量约2000万单。这个行业还是具备很大的潜力。
本文主要介绍如何基于Tablestore的Timestream来快速实现共享汽车管理平台的数据存储。
_图2 共享汽车管理平台需求_
对于出行者来说,使用共享汽车的流程主要是租车、用车以及还车:
对共享汽车管理平台来说,其核心功能则是车辆管理和订单管理:
另外,作为管理平台,还需要对订单以及车辆的业务数据进行分析,调度车辆来更好的满足出行者的需求,最大化车辆使用率,比如说什么区域出行需求很大,经常导致供不应求需要提供更多的车辆等。
从上面的分析可以看到,共享汽车管理平台主要需要存储车辆和订单两部分数据,其中车辆包含了元信息(车牌、车型、颜色等)、行车轨迹、状态(车速、是否使用中等),订单则包含了车辆、用户、时间、状态等信息。下面对这些数据进行分析:
从上面的分析可以看到,为了满足海量的订单以及车辆监控数据的存储需求,极高的写入吞吐、海量存储规模、可控的存储成本成为必须要解决的问题。
_图3 传统解决方案_
上面是共享汽车平台的传统解决方案,用MySQL来存储车辆基本信息,订单信息、轨迹以及状态数据由于数据规模比较大,其存储是经过流计算分析后写入到hbase中,在同步到solr提供数据检索能力。这个架构存在以下不足之处:
在这个场景中,主要包含了三个数据存储需求:关系型数据、大规模时序数据以及大规模数据检索,在传统解决方案中,使用了三种不同的服务来满足业务需求,但Tablestore作为一款阿里自研的分布式NoSQL服务,提供多元索引支持丰富的查询需求,支撑超大规模的并发访问和低延迟的性能,可以很好的满足这三个需求。
_图4 基于Tablestore解决方案_
上图则是基于Tablestore的系统架构,数据直接写入到Tablestore,在通过通道服务将数据增量流出到函数计算进行事件监测,以及流到流计算系统进行后计算,再将计算之后的结果写回到表格存储中。相比传统架构,该架构有以下优势:
前面分析过在共享汽车管理平台中,核心数据包含了车辆元数据、轨迹&状态数据,以及订单数据。其中订单数据的实现可以参考:《基于Tablestore打造亿量级订单管理解决方案》。
另外,车辆元数据、轨迹&状态数据的存储适用于用Timestream模型来快速高效的实现。Timestream是表格存储推出的最新数据模型,这个模型针对时序数据、轨迹数据、溯源数据,定义了一套简单清晰易用的API,细节可以参考《Tablestore Timestream:为海量时序数据存储设计的全新数据模型》。
车辆元数据,顾名思义,就是Timestream模型中的元数据(Meta),车辆轨迹&状态数据则是Timestream的Data数据点。
从上面的Timestream介绍文章可知,Timestream拥有几个核心概念,分别是:Name, Tag, Attribute, Timestamp, Point(Fields)。我们罗列一个表格,展示怎么将车辆的相关数据映射到Timestream的模型中,如图所示:
图5 数据模型映射
接下来我们通过一个可以运行的Demo,向大家展示怎么使用Timestream API快速实现车辆轨迹、状态管理功能。
写入
查询
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>tablestore</artifactId>
<version>4.11.2</version>
</dependency>
对于一些固定且有特殊索引需求的字段,我们在创建Meta表的时候需要单独指定,比如续航、地理信息、状态数据等。
以下示例只是给了部分元数据字段,用户可以根据自己的需求设置更多的索引字段。
public void createMetaTable() {
db.createMetaTable(Arrays.asList(
new AttributeIndexSchema("地区", AttributeIndexSchema.Type.KEYWORD),
new AttributeIndexSchema("车型", AttributeIndexSchema.Type.KEYWORD),
new AttributeIndexSchema("车牌", AttributeIndexSchema.Type.KEYWORD),
new AttributeIndexSchema("颜色", AttributeIndexSchema.Type.KEYWORD),
new AttributeIndexSchema("座位", AttributeIndexSchema.Type.LONG),
new AttributeIndexSchema("续航", AttributeIndexSchema.Type.LONG),
new AttributeIndexSchema("状态", AttributeIndexSchema.Type.KEYWORD),
new AttributeIndexSchema("当前位置", AttributeIndexSchema.Type.GEO_POINT)
));
}
这个比较简单,只需要设定表名即可。因为我们是Schema Free的体系,不需要预先指定列,在写入的时候指定即可。
public void createDataTable() {
db.createDataTable(dataTableName);
}
车辆元数据写入包含两个部分,第一个是车辆接入平台时,将完整的信息写入;第二个是后续状态数据发生变化时,按需更新元数据中的最新状态。
public void writeMeta() {
TimestreamIdentifier identifier = new TimestreamIdentifier.Builder("*滴")
.addTag("ID", carNo)
.build();
// 插入车辆信息
TimestreamMeta meta = new TimestreamMeta(identifier)
.addAttribute("地区", "杭州")
.addAttribute("车型", "奇瑞EQ1")
.addAttribute("车牌", "浙AD75138")
.addAttribute("颜色", "白")
.addAttribute("座位", 4)
.addAttribute("续航", 120)
.addAttribute("当前位置", getRandomLocation())
.addAttribute("状态", "闲置");
metaWriter.put(meta);
// 更新车辆元数据的最新状态
meta = new TimestreamMeta(identifier)
.addAttribute("当前位置", getRandomLocation())
.addAttribute("状态", "使用中");
metaWriter.update(meta);
}
public void writeData() {
TimestreamIdentifier identifier = new TimestreamIdentifier.Builder("*滴")
.addTag("ID", carNo)
.build();
TimestreamDataTable dataWriter = db.dataTable(dataTableName);
Point point = new Point.Builder(1546272000, TimeUnit.SECONDS)
.addField("位置", "30.1457580736,120.0563192368")
.addField("车速", 30)
.addField("续航", 100)
.build();
dataWriter.asyncWrite(identifier, point);
}
这里根据车辆平台、地区、当前位置,以及状态的状态检索可用的车辆。
Filter filter = and(
Name.equal("*滴"),
Attribute.equal("地区", "杭州"),
Attribute.inGeoDistance("位置", "30.1457580736,120.0563192368", 1000),
Attribute.equal("状态", "闲置")
);
Iterator<TimestreamMeta> iter = metaTable.filter(filter).fetchAll();
while (iter.hasNext()) {
TimestreamMeta m = iter.next();
System.out.println(m);
}
Filter filter = and(
Name.equal("*滴"),
Attribute.equal("地区", "杭州"),
Attribute.equal("车型", "奇瑞EQ1"),
Attribute.inRange("续航", 200, Long.MAX_VALUE),
Attribute.equal("状态", "闲置")
);
Iterator<TimestreamMeta> iter = metaTable.filter(filter).fetchAll();
while (iter.hasNext()) {
TimestreamMeta m = iter.next();
System.out.println(m);
}
TimestreamIdentifier identifier = new TimestreamIdentifier.Builder("*滴")
.addTag("ID", carNo)
.build();
Iterator<Point> iter = dataTable.get(identifier).select("位置").fetchAll();
while (iter.hasNext()) {
Point p = iter.next();
System.out.println(p);
}
https://ots.console.aliyun.com/index#/cn-hangzhou/demo/shareCar
如果您对表格存储、时序模型感兴趣,对模型使用有疑问、想探讨,欢迎加入【表格存储公开交流群】,群号:11789671。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
阿里云存储基于飞天盘古2.0分布式存储系统,产品多种多样,充分满足用户数据存储和迁移上云需求。