小 T 导读:车联网业务是中通科技配送全链路业务中非常重要的一环,在实际的项目需求中,需要实时查询车辆最新位置状态,达到车辆运营可视化管理。中智车联服务平台选择了用 TDengine 来高效处理从车辆上实时采集的时序数据。
业务背景
目前,中通科技拥有一支千人规模的研发团队,在数字信息科技研发方面以“互联网+物流”的理念,自研的软件系统和数字化工具已达百余个,赋能覆盖快递业务全场景,同时为快运、国际、云仓、优选、金融、商业等生态圈业务提供全方位的研发支持,建立起完善的互联网产品研发体系,全场景、全链路的数字化、互联化和智能化的业务地图愈发成熟。
2021 年年底,中通快递已完成了总部园区的实景三维模型,通过接入园区内的在线传感器,根据现有园区各功能区的区位布局,基于此三维模型开展园区内生产规划、调度运行和维护管理的全过程应用,从而实现园区内人、车、物在精准运行、资源优化和配置服务中的全过程精益化管理。
随着生产设备的小型化和智能化,快递企业也将更快地进入空间地理信息数据生产领域,有包裹流动的地方,就会有时空数据服务的需求。
这里先给大家介绍一下配送全链路业务,这是指包裹从商家仓出来一直到用户手上的这段派送履约链路,它包含 4 个主要的实操流程,分别是分拨实操、运输实操、站点实操和快递员实操。把 4 种实操管理放到三个系统里面,这三个系统分别是分拨管理、运输管理、末端站点实操管理。具体如下图所示。
其中车联网业务也是非常重要的一环,通过人、车、货、场全链条覆盖的车联网设备应用,实现物流运输全链路感知。在实际的项目需求中,我们需要实时查询车辆最新位置状态,达到车辆运营可视化管理,也就是我们的中智车联服务平台。
技术选型
在上述业务过程中,我们使用了 TDengine 来完成这个目标。
在选型时,我们对比了 Prometheus 和 TDengine 这两款很有代表性的时序数据库(Time-Series Database)。 相对而言,TDengine 的“一个设备采集点一张表”的底层设计,自带的降采样和窗口函数的优秀性能,都十分契合车辆网场景。其列式存储带来的压缩比也更好。所以我们选择了 TDengine。
技术架构
我们在每辆车上都安装了部标机(即卫星定位汽车行驶记录仪),来实时采集车辆的行驶速度、时间、里程以及与车辆行驶相关的其他状态信息。采集到的数据,通过我们的 IoT service 这层应用来处理。然后数据经由 MQ (消息队列)层由 JDBC-RESTful 的方式写入 TDengine 集群,以供上游平台使用,而部标机产生的其他类数据则通过别的途径供上游平台使用。
我们使用了三节点三副本的模式落地了 TDengine 集群。
建表很简单,我们选择了一类数据对应一张超级表,超级表下根据车牌号划分子表,表结构如下图所示。目前还是项目初期,所以只接入了 700 余辆车,后续会逐步增加接入车辆。也正因为这套环境接入设备不多,写入方面并无压力,远远达不到 TDengine 的写入极限。
具体应用
我们要通过数据的变化来实时得到车辆的很多信息,比如是否有停留、超速、缓行、离线等事件发生。有些功能可以通过 TDengine 的查询功能实现,有些不方便实现的暂时通过应用来完成。
下面我们通过几个例子来看看目前业务中使用比较频繁的查询:
1.获取车辆的最新位置
SQL 语句如下。
select last_row(longitude,latitude),deviceId from ioc_gps.vehicle_location groupby deviceId where device_id = #{deviceId} and ts >= #{startTime} and ts <= #{endTime}
业务需要快速查询每辆车的最新坐标,这里用到了 TDengine 提供的 last_row 函数。除了查询单独某辆车,经常还会根据 groupId 或者一批 deviceId 去查询一批车辆的最新坐标。
系统界面如下图所示。
2. 车查轨迹信息查询:
select ts,device_id as deviceId,longitude,latitude,altitude,speed as speed,direction,alarm as warnBit,status as statusBit,mobile,mileage,speed2,rssi,satellites,signal_status as signalStatus,gmt_create as gmtCreate,create_ip as createIp,kind,oil,message_id as messageId,device_name as deviceName,plate,device_group_id as deviceGroupId,device_group_name as deviceGroupName,acc, device_code as deviceCodefrom ioc_gps.vehicle_locationwhere device_id = #{deviceId}and ts >= #{startTime}and ts <= #{endTime}
通过指定时间范围和具体的车牌号,就可以立刻获得该车辆的轨迹数据并渲染出轨迹图像。如果知道子表名的话,还可以直接查询子表,这样会减少超级表中对于标签的检索。
系统界面如下图所示。
未来规划
通过项目初期的表现,可以知道 TDengine 能够轻松满足我们的业务需求。未来我们还有其他的使用规划,比如在我们的表字段中,有个 ACC 字段,1 表示点火,0 表示熄火,要求能够计算点火驾驶行程,由于 TDengine 当前还没有直接支持 GIS 计算,暂时不能通过坐标算出直线距离(当前所用的 TDengine 2.0 版本可能需要使用自定义的 UDF 实现),但是应该可以通过状态窗口+加权平均速度+开火时间算出车辆每次点火的驾驶路程,就想这样:
select time*speed from (select elapsed(ts,1s)as time,twa(speed) as speed,acc from t1 state_window(acc)) where acc =1 ;
而每次 ACC 开火熄火的起始点和结束点信息,可以通过 state_window 配合 first/last 函数来实现,比如:
select last(*),first(*) from t2 state_window(charge);
除此之外,我们也需要电子围栏计算,需要快速计算新轨迹点是否进入某电子围栏之中,或者需要快速计算(1s 内)位于某行政区划(省份/城市)边界内的所有车辆的数量。这类查询都需要等 TDengine 继续完善才能实现。
后续我们接入的车辆会达到几万辆,对于部标机产生的相关时序数据的使用也会越来越多。期待 TDengine 可以继续为车联网场景下的查询提供更为多样性的支持,产品越来越好。
想了解更多 TDengine Database的具体细节,欢迎大家在GitHub上查看相关源代码。