场景需求
在移动对象轨迹监控与分析的项目中,收集了数十万的车辆信息,每个车辆会定时的上报当前位置、事件、状态等信息,每天约数亿条轨迹点,需要能够存储。且前端用户在查询时,要能快速返回目标船舶的信息。
入库需求:
轨迹数据,每日新增10亿条左右,包括时间点、经纬度坐标、对象当前的属性信息
基本不涉及到数据的修改(不断的追加数据)
查询需求:
- 区域回放:根据时间和空间范围两个维度共同查询。例如:查询东经110°~120°,北纬25°~35°空间范围内,2019.3.1~2019.3.10时间范围内的所有轨迹点。
- 轨迹线查询:根据某个移动对象的id,查出某段时间内的轨迹。例如:查询编号为"205073000"的船舶在2019.3.1~2019.3.10时间范围内的所有轨迹点。
要求:
- 要能支撑每日10亿量级的写入,要能承载千亿轨迹规模的存储
- 时空查询(区域回放)要能在秒级响应,轨迹线查询要能在百毫秒级响应
技术调研
关系型数据库
现有的关系型数据库如Oracle、MySQL、PostgreSQL都提供了Spatial的插件,尤其是PG的空间引擎PostGIS,使用率较高,具有丰富的空间处理算法,适合做空间关系判断与分析等。但众所周知,关系型数据库的强项在于OLTP,即适合数据更新、查询等,但对于大规模数据的存储则需要分库分表等操作,操作相对繁琐,因此对于上述需求来说,暂不考虑关系型数据库。(这里提一下,除了阿里云PG Ganos外,都没有时空处理)
NoSQL数据库
NoSQL适合处理海量数据的存储与查询,如Cassandra、HBase、MongoDB、Redis等,都支持海量数据的水平扩展。但在时空方面都没有一个完善的方案,比如MongoDB、Redis虽然都提供了空间处理的算法,但总体来说只能实现Within等操作,即空间范围查询操作。
阿里云已经发布了基于HBase的时空引擎HBase Ganos(参考:https://help.aliyun.com/document_detail/87287.html?spm=a2c4g.11174283.6.619.3c693c2e29oyDM),不仅可以处理空间查询,还可以处理时空查询场景。因此,本文基于HBase Ganos时空引擎对上述场景进行测试。
实例规格
HBase Ganos具有高吞吐特点,本着节省的原则,我们以最小规格配置为基础(约2000元+/月,成本与HBase相同),来看看是否能够支撑上述需求。具体配置如下:
- master节点:2核4G
- core节点:4核8G(数量可动态扩展)
- 磁盘:高效磁盘(500G,可动态扩展)
具体实施
访问接口
HBase Ganos支持RESTful和GeoTools两种接口访问形式,前者通过HTTP协议可以方便的使用任何一种编程语言访问;而GeoTools接口基于Java语言,较为通用。本文采用该接口方式,这里封装了一个Ganos Client工具,可以直接下载使用(附案例代码连接)
数据模型表
通过GanosSchemaUtil工具类创建SimpleFeature(Point类型),并添加了对象id(为其建立索引)、速度、事件、状态、时间(默认建立索引)等信息,具体如下:
GanosSchemaUtil ganosSchemaUtil = new GanosSchemaUtil();
ganosSchemaUtil.addField("objId", "String", true);
ganosSchemaUtil.addField("speed", "Double", false);
ganosSchemaUtil.addField("event", "Integer", false);
ganosSchemaUtil.addField("status", "Integer", false);
ganosSchemaUtil.setGeometry("Point", null);
ganosSchemaUtil.setDate("dtg");
SimpleFeatureType sft = ganosClient.createSFT(schemaName, ganosSchemaUtil.toString(),"zstd");
ganosClient.createSchema(sft);
数据构造
上述字段的值采用随机生成方式(按照真实数据规则模拟),数据构造方法为:
- 时间窗口:2019-02-25 00:00:00~2019-03-05 00:00:00
- 空间窗口:经度范围 115.37465076~120.37465076, 纬度范围:26.23923772~31.23923772
- 移动对象数量(可理解为车、船的数量):100万
- 其他属性数据:速度、状态、事件等,均采用随机生成方式
数据导入
启动10个线程并发写入
导入方法:
- 启动10个线程写入,每次批量写入1000条。
- 这1000条数据中,随机选取多个移动对象,同时随机生成该移动对象的时间点、空间位置以及其他属性信息。比如这1000条轨迹点可属于N个对象,每个对象的轨迹点个数也不相同。
代码参考:
数据查询
- 启动10个线程查询,查询场景包含两种:a、区域回放(时空查询);b、单条轨迹查询(id+时间)
- 每次从一百万个移动对象中随机选取一条,同时随机选取查询的时间窗口,考察系统吞吐、RT等
代码:参考
性能
- 写入性能:存储层的IO可达8万+/s,在构建三张索引表的情况下,可理解为每秒能支撑3万个轨迹点的导入,完全能够满足一天10亿级的写入需求。
- 查询性能:
区域回放(时空查询):每次查询返回数据量在几百条左右,缓存为命中情况下,耗时在1秒钟以内;若缓存命中情况下,在100ms左右。
轨迹线查询:每次返回数据量在几百条左右,耗时在800ms以内。
总结
HBase Ganos不仅能够支持空间查询、还能够支持“时间+空间”的查询,以及轨迹线(时序)查询。在2个4核8G的节点配置下,能够支撑每日10亿量级的数据写入,且性能维持在秒级以下,适合海量轨迹的存储和查询场景。