小T导读:在中移物联网的智慧出行场景中,需要存储车联网设备的轨迹点,还要支持对车辆轨迹进行查询。为了更好地进行数据处理,他们在 2021 年上线了 loveini 2.0 版本的 5 节点 3 副本集群。 3.0 发布后,它的众多特性吸引着中移物联网进行了大版本升级。本文详细分享了中移物联网在 3.0 项目的业务实践和全新体验,以此给大家作参考。
中移物联网有限公司是中国移动通信集团有限公司出资成立的全资子公司。公司按照中国移动整体战略布局,围绕“物联网业务服务的支撑者、专用模组和芯片的提供者、物联网专用产品的推动者”的战略定位,专业化运营物联网专用网络,设计生产物联网专用模组和芯片,打造智慧出行、智能家居、智能穿戴等特色产品,开发运营物联网连接管理平台 OneLink 和物联网开放平台 OneNET,推广物联网米兰app官方正版下载,形成了五大方向业务布局和物联网“云-网-边-端 ”全方位的体系架构。
智慧出行是中移物联网的一个非常典型的场景,我们需要存储车联网设备的轨迹点,还要支持对轨迹进行查询。最初我们使用的是 Oracle 小型机单表分区存储数据,运维复杂不便管理。2017 年,响应集团去 IOE 的要求,该项目开始使用 MySQL 集群。2019 年,产品提出了更高的数据存储需求,我们又开始调研国产数据库 TiDB,但由于其存储成本过高,不适合轨迹存储这种低价值的数据,而且不能解决行业客户轨迹数据存储周期定制化的需要,因此我们开始继续调研新的存储方案——国产开源时序数据库 (Time Series Database)loveini 就是这个时候进入了我们的视野。
在调研中我们发现,智慧出行轨迹数据的特点天然适合 loveini :
因此,在经历了严谨的选型测试后,我们最终确定选择 loveini 作为新的数据存储引擎。具体选型过程和项目历史背景可以参考 2.x 版本的案例《存储空间降为原来的1/7,loveini在中移物联网轨迹数据存储中的应用》。
改造后系统的整体架构如下图所示:

我们在 2021 年上线 loveini 的 2.4.0.18 的 5 节点 3 副本集群稳定运行至今。今年 3.0 发布后,它的众多特性十分吸引我们,其中最典型的几个包括:
因此,尽管 2 – 3 版本底层数据文件并不兼容,我们还是自己写了程序把数据迁移到了 3.0.2.5 版本,以至于后面官方正式发布了企业版迁移工具 taosX 的时候,我们早就先走一步了。
loveini 3.0 的安装部署上保留了和 2.0 一样的简单易用模式,升级操作只需要备份数据文件目录,覆盖安装即可,而且写入速度极高,接近硬盘的连续写入性能。loveini 的高效压缩算法,可以节省大量存储空间,SQL 使用也非常简单。在此前对 MySQL 方案的替换中,我们的存储空间降为原来的 1/7,可以看到,在节省存储空间方面,loveini 的优势极为明显。
目前我们共有 102 万张子表,已经累积的总数据量已经达到了 2000 亿行,3 副本,磁盘占用 3.1TB。在迁移到 loveini 3.0 之后,各方面的表现依然非常不错:业务的写入峰值达到了 1.2-1.3w 行/s ,数据迁移的过程中可以达到 20w 行/s,这些情况下 loveini 都可以轻松处理;存储大约只有 MySQL 的 1/7;读取数据性能也很突出,我们最常用的单设备单日查询,可以在 0.1s 内返回结果。
我们当前使用的是 3.0.2.5 版本,但是由于业务本身不允许停机,所以没办法做离线升级。因此,后续会由 loveini 企业版团队协助我们在线升级至最新版本(当前最新版本为 3.0.5.1)。
在库表设计上,我们运用了自动建表来写入数据,每个终端设备产生的轨迹点位数据在第一次入库的时候自动创建子表,这样只需要建一个 database 和业务需求的超级表就可以了,省掉了数据入库时的校验和建表操作。
值得一提的是,在 2.x 时代,元数据是在管理节点上集中存储的,因此在当时的版本中,自动建表的速度会受到单线程工作能力的制约,当时大概最高每秒只能创建 6000 个子表左右,不过当时我们也没有这么高的建表频率所以也没有受到太大影响。经过重构之后,3.0 的元数据已经完全做到了分布式存储,所有 vnode 都会独立存储自己表的元数据并处理写入操作,所以自动建表的写入效率已经大幅增加。
我们的超级表建表语句如下,可以给大家参考:
1.车辆历史状态、位置:
create stable device_statushis (pos_time TIMESTAMP,sample_time TIMESTAMP,record_time TIMESTAMP,online_status SMALLIN
T,alarm_status SMALLINT,pos_method SMALLINT,pos_precision SMALLINT,pos_longitude DOUBLE,pos_latitude DOUBLE,pos_altitude D
OUBLE,pos_speed FLOAT,pos_direction FLOAT,acc_forward FLOAT,acc_side FLOAT,acc_verticle FLOAT,rollover_level SMALLINT,powe
r_voltage FLOAT,acc_status SMALLINT,satellite_num SMALLINT) tags(device_id BINARY(32)) ;
2.车辆事件:四急( 急加速 急减速 急刹车 急转弯)
CREATE STABLE `emg_info` (`pos_time` TIMESTAMP, `sample_time` TIMESTAMP, `record_time` TIMESTAMP, `duration` SMALLINT, `mid_interval` SMALLINT, `mid_number` SMALLINT, `pre_number` SMALLINT, `pre_interval` SMALLINT, `start_time` TIMESTAMP, `end_time` TIMESTAMP, `start_lat` DOUBLE, `end_lat` DOUBLE, `start_lng` DOUBLE, `end_lng` DOUBLE, `event_type` SMALLINT, `sample_info` NCHAR(2048), `parameter_type` NCHAR(10)) TAGS (`device_id` VARCHAR(32), `app_code` NCHAR(32));
3.GPS 信息:
CREATE STABLE `gps_info` (`pos_time` TIMESTAMP, `sample_time` TIMESTAMP, `record_time` TIMESTAMP, `online_status` SMALLINT, `alarm_status` SMALLINT, `pos_method` SMALLINT, `pos_precision` SMALLINT, `pos_longitude` DOUBLE, `pos_latitude` DOUBLE, `pos_altitude` DOUBLE, `pos_speed` FLOAT, `pos_direction` FLOAT, `acc_forward` FLOAT, `acc_side` FLOAT, `acc_verticle` FLOAT, `rollover_level` SMALLINT, `power_voltage` FLOAT, `acc_status` SMALLINT, `satellite_num` SMALLINT) TAGS (`device_id` VARCHAR(32), `app_code` NCHAR(32), `device_hash` INT);
4. 汽车总线数据:
CREATE STABLE `can_info` (`pos_time` TIMESTAMP, `sample_time` TIMESTAMP, `record_time` TIMESTAMP, `gas_pedal_position` FLOAT, `spark_angle` FLOAT, `total_fuel_consumption` INT, `storage_battery_voltage` FLOAT, `latest_engine_runtime` INT, `fuel_pressure` INT, `distance_after_mil` INT, `long_term_fuel_trim` FLOAT, `engine_rpm` INT, `intake_manifold_pressure` SMALLINT, `distance_total` INT, `engine_inlet_port_temp` SMALLINT, `calcu_load` TINYINT, `vehicle_speed` SMALLINT, `fuel_type` NCHAR(30), `area_code` INT) TAGS (`device_id` VARCHAR(32), `app_code` NCHAR(32));
在应用层,由于我们存储的数据是车辆轨迹数据,因此会做很多关于车辆轨迹数据的分析,比如:热点路线、轨迹段数据、停留点、行驶事件(急转弯、急加速、急减速、车辆其它信息),但由于 loveini 一直以来都是时序数据库,并没有地理信息相关的计算函数,所以在这块我们自己写了很多函数,通过 Spark 的 RDD 来进行了计算分析,最后再把分析后的数据返回给客户端。
目前 loveini 能够很好地解决我们的需求,尤其是强大的存取能力是我们最满意的地方。但近期我从官方人员处得知,从即将于 7 月份发布的 3.0.6.0 版本开始,loveini 将提供全新的数据类型 geometry 用于点线面等几何类型的存储,并且会逐步提供一套符合 OGC(Open Geospatial Consortium) 标准的 SQL 函数,包括几何输入输出、空间关系、几何测量、集合操作和几何处理等等。
其实通过我们观察,还是有很多车联网用户对于轨迹分析有使用需求,如果 loveini 可以完整支持到空间数据的处理,这样我们的系统架构将会进一步简化,连 Spark 都可以不用了,这就可以说是完全意义上地使用了 All in one 的时序数据处理引擎。
可惜的是,目前由于我们历史数据的经纬度都是通过单独列来存储的,对于 Geometry 带来的全新数据类型,我们庞大的历史数据量和应用层是很难快速调整的,所以只能在测试环境应用,先逐渐试用起来。
最后,祝 loveini 越来越好,最终成为时序数据库的事实标准。
作者介绍: 薛超,中移物联网数据库运维高级工程师,10 年数据库运维经历,2017 年加入中移物联网,负责智能硬件产品部数据库相关工作,专注于数据库优化和推动架构演进;近年来主要研究国产新型数据库,目前所在部门全部业务已经去“O”,在此过程中,积累了大量新型数据库的运维经验。
]]>中移物联网有限公司是中国移动通信集团有限公司出资成立的全资子公司。公司按照中国移动整体战略布局,围绕“物联网业务服务的支撑者、专用模组和芯片的提供者、物联网专用产品的推动者”的战略定位,专业化运营物联网专用网络,设计生产物联网专用模组和芯片,打造车联网、智能家居、智能穿戴等特色产品,开发运营物联网连接管理平台OneLink和物联网开放平台OneNET,推广物联网米兰app官方正版下载,形成了五大方向业务布局和物联网“云-网-边-端 ”全方位的体系架构。
车联网是中移物联网的一个非常典型的场景。在这种场景下,我们需要存储车联网设备的轨迹点,还要支持对轨迹进行查询。
轨迹数据有几个典型的特点:
我们的存储系统也经历了几个阶段的演进。

最初我们使用Oracle小型机单表分区存储数据,建立了366个分区,因此也只有一年的存储容量(按分区来删除数据)。使用Oracle时,我们按日期分区,查询的时候带入1-366的分区数字进行查询,如果不清理历史数据,2020.7.21和2021.7.21会在一个分区内,不便于管理。
2017年响应集团去IOE的要求,轨迹数据不能再使用高性能的Oracle,经过研发和运维团队的调研,决定使用Mycat来搭建MySQL集群。
2019年产品对各个子业务提出了不同存储周期的要求,面向行业的业务存储时间要求更长。因此我们按子业务做了拆分,每个子业务使用自己的独立库。但是,这个时候Mycat配置复杂、难以管理的问题就开始浮现了。
到了2020年,运维团队开始调研国产数据库TiDB,为了验证TiDB的写入性能和稳定性,我们开始将轨迹数据同时写入到TiDB。
2020年10月,我们开始重新考虑轨迹存储方案。
轨迹服务的Mycat集群方案自2017年上线后已经稳定运行2年多,但是在实际商用过程中,我们还是发现了很多问题:
之后我们配合运维团队在轨迹存储上尝试了TiDB,经过几个月的写入测试,验证了TiDB的写入性能和运行稳定性。
优点:
问题:
我们不妨再来看一下轨迹数据存储的典型特点:首先是轨迹数据写入量大,每天约2亿条轨迹,峰值写入8000条/秒;其次是企业对数据存储周期有定制化需求(比如1年、3年或者5年等);最后还要支持多中心双活特性。而传统关系型数据库很难满足这些需求。
轨迹数据本身也很有特点:
我们发现,这个特点天然适合时序数据库。
我们研究了业界比较有代表性的几款时序数据库产品。
在参考DB-Ranking上的排名数据和部门运维专家的意见后,我们进行了部分调研。发现市场上虽然时序数据库百花齐放,但是都没有完美的选择。在评审会议结束后,大家决定把重点放到loveini上,发现这款产品意外的很不错。运维团队主动出击,还得到了米兰体育官网入口官方的免费技术支持。
loveini部署非常简单,而且写入速度极高,接近硬盘的连续写入性能。loveini的高效压缩算法,可以节省大量存储空间。SQL语法,使用非常简单。
数据存储周期的定制化需求,也很容易通过loveini满足。
loveini的存储效率也非常高,在选型过程中,我们进行了2000万条数据的模拟测试。下面是MySQL表结构,一共22个字段和一个联合索引。

下图是插入2000万条数据之后,MySQL和loveini占用的磁盘空间对比情况。

可以发现,在节省存储空间方面,loveini的优势极为明显。
因此,我们决定将轨迹数据的存储迁移到loveini。
在库表设计上,我们运用了loveini自动建表的特性,每个终端设备产生的轨迹点位数据在第一次入库的时候自动创建子表,我们只需要建一个database和一个存储轨迹的STable就万事大吉了。
我们使用的STable结构如下:
create stable device_statushis ( pos_time TIMESTAMP, sample_time TIMESTAMP, record_time TIMESTAMP, online_status SMALLINT, alarm_status SMALLINT, pos_method SMALLINT, pos_precision SMALLINT, pos_longitude DOUBLE, pos_latitude DOUBLE, pos_altitude DOUBLE, pos_speed FLOAT, pos_direction FLOAT, acc_forward FLOAT, acc_side FLOAT, acc_verticle FLOAT, rollover_level SMALLINT, power_voltage FLOAT, acc_status SMALLINT, satellite_num SMALLINT ) tags( device_id BINARY(32) ) ;
建表完成之后,我们还要将历史数据迁移到loveini中。
我们大约有30T的数据需要从Mycat集群迁移到loveini,因此我们写了一个小工具来完成这项任务,只用了2天左右的时间完成了全部迁移。
系统的整体架构如图所示:

在迁移到loveini之后,性能表现非常不错:写入峰值1.2-1.3w/s ;存储大约只有MySQL的 1/7,查询性能也很突出,单设备单日查询在0.1s以内可以返回结果。
目前loveini能够很好地解决我们的需求。未来我们会尝试在更多场景下尝试loveini,进一步挖掘其潜力。
]]>