在车联网场景下,GPS 产生的时序数据量级通常都达到了亿级,高效写入、存储和快速查询是最基本的数据处理要求,但在具体实践上这却不是一件容易实现的事情。最近某企业就遇到了这样一个问题:服务端接收存储 GPS 相关数据,按 1 次/30 秒的上传频率,一天的数据条数估计在 1.2 亿条,其想要实现后台的实时监控和历史轨迹查询,一般用什么样的数据库进行存储?NoSQL(Redis、MongoDB)?MySQL?还是 HBase?
相信上述企业的数据库选型问题并不是个例,选择到一款合适的数据库,对于打造一个适合业务发展的数据架构至关重要。为了找到该问题的最优解,涛思数据解决方案架构师从数据本质出发进行分析,结合具体实践输出本文,给到大家参考。
先谈 NoSQL 数据库
不管是 Redis/MongoDB/ElasticSearch 当中的哪一个,在面对上述场景时都会面临同一个问题:压缩率。在车联网当中,按照国标 30s 的采样间隔可以计算得到单台车的采集量为 2880 rows/day,在 10W 车辆规模下,就是 2.88 亿/天。假设单台车辆采集 250 个信号,每个信号 8 Bytes(相当于 Double),即每行 2000 Bytes,那么 1 天就会有 562.5 GB 的数据量,1 年会有约 200TB 的数据。
在这样的数据规模下,压缩率即使是 50%,也需要 100TB 的空间。而这样的空间规模,通常都需要 10 个节点以上的 NoSQL 集群(用 Redis 的话就更可怕了,需要内存 100TB 的集群)。这个结论的底层原理,就在于 NoSQL 是使用非结构化的方式来存储结构化数据的,这种模式导致了压缩效果差、存储成本高、节点规模大的劣势。
再谈 MySQL/PostgreSQL
本来这两款数据库作为 SQL 类数据库,存储结构化数据是很合适的。但是,我们看一下每秒的写入量:平均 10W/30 = 3333 rows/s,最大值 10W rows/s,由于车联网本身会出现“车机在一段时间内断网补传数据”、“车机上传按时钟定时”等特点,会有一定概率触发最大值写入量,甚至超过最大值。因此选用的数据库必须具备高吞吐能力,而且还得留有余力供后续扩容。用过 MySQL 的开发者都会有体验,在没调优的情况下,这种 2KB 的行写入,1k tps 基本把单个节点打满了。
另外一方面,我们一般都会建立索引,至少建立时间戳的索引用于按时间段查找数据。而当我们用 B+ 树存储索引,在单表数据量达到 2000W 行时,索引的维护会导致写入速度的下降,单从这一点看就很难运维,更不要说在建立更多索引的情况下。
再者,MySQL 的横向扩展只能靠中间件来实现,没有更好的方式了,这种分布式的横向扩展能力也为其打了个折扣。正是基于此,PostgreSQL 才会单独出了一个分支来存储时序数据。
接下来谈 HBase
HBase 单从诞生的背景看,就不是为了时序数据而设计的。很多程序员通过设计 rowkey 的方式,变相实现了 HBase 对时序数据的存储,其中 OpenTSDB 就是一种开源的实现方式。在 5、6 年前,分布式存储还是 Hadoop 一枝独秀的时代,大家也就自然而然地用上了 HBase/OpenTSDB 这一类数据库。但是从产品设计上看,其设计目标是为了服务爬虫存储这样的场景——支持几千亿行的表(超大表),并且支持随时添加新的列(列族)。从这样的设计里面,我们可以推导出来下面几个问题:
- 存储率不高:因为 HBase 里用了 Byte 的类型,以 Column Family 为单位做列存,因此压缩率也上不去。但是比 NoSQL 好一些。
- 运维复杂:用 HBase 就得先上 HDFS/ZooKeeper/MR 这一系列组件,安装运维就是个问题。本来只是为了存储数据,结果倒腾起大数据的组件来了。
- 计算慢:哪怕是 OpenTSDB 这个基于 HBase 做的时序数据库(Time Series Database),在做一些常见的降采样、排序计算、时间段检索上,都不是特别快。其背后的问题还是在于 HBase 节点本身不提供时序的计算函数,因此查询时都得汇聚到 1 个OpenTSDB 节点来进行,并发度很有限并且会消耗大量的网络 IO 成本。
综上所述,HBase 也并非很适应车联网场景。
最后谈 TDengine
TDengine 在设计的初期就定位要做物联网场景下的数据库,也就是时序数据库。至于上述场景的数据问题,TDengine 已经从实践层面就给出了回答。
在狮桥集团的网货平台与金融 GPS 系统业务中,对于车辆轨迹收集与计算有着强需求。GPS 每日产生总量在 40 亿左右,需要为业务方提供实时末次位置查询,近 180 日行驶轨迹查询,类似车辆轨迹对比查询,以及一些风险逾期的智能分析等等。在狮桥的产品历史中,技术架构一共经历过四个版本的迭代——通过 MQ 接入厂商数据、Kudu+Impala 模式、Hbase + Clickhouse、TDengine。
第三阶段改版中,狮桥曾尝试使用 Hbase、Clickhouse 替换 Kudu,但从存储功能而言,狮桥希望能够读写兼顾、支持 SQL,同时还有合理的分区策略,这一点 HBase 肯定不能满足,Clickhouse 虽然表现还算不错,但也没有完全满足需求。从业务需求出发,狮桥开始进行时序数据库选型,最后选择了 TDengine,实现了他们“希望找到一个存储技术既可以兼并读写性能,又可以契合到自身业务场景,且还是 SQL 原生”的数据库选型诉求。
在应用 TDengine 后,狮桥的整体数据存储缩减超过 60% 以上,集群更是指数级的下线——末次位置查询的 Redis、轨迹查询的 Hbase 集群集体下掉、Clickhouse 也不再用作轨迹存储,把裸金属用在了更需要蛮力干活的地方,真正实现了降本增效。
有着同样场景的还有南京津驰。此前他们的 GPS 服务采用的存储技术方案是 Redis + MySQL + CSV,实时数据存储到 Redis 队列,经过服务消费后将原始数据存储到 MySQL,凌晨执行定时任务将前一天 MySQL 中的原始数据存储到 CSV 文件。随着业务的发展以及数据量的增长,各种问题也逐渐凸显,开始影响工作效率,出现查询效率低、数据安全性低、数据占用空间大、数据运用不够灵活等问题。在进行选型调研后,他们选择将 TDengine 搭建在 GPS 服务中,轻松抗住了业务中每秒接近 400MB 左右的写入量,并且压缩率喜人,存储空间降为原方案的 3%。
同样的车联网落地案例还有蔚来汽车、理想汽车、零跑汽车等,感兴趣可以点击链接查看,本篇文章就不多做赘述了。
而 TDengine 之所以能达到上述效果,还要从 Jeff(TDengine 创始人& CEO 陶建辉)归纳的十条时序数据处理特点说起:
- 所有采集的数据都是时序的 —— 就只处理时序数据
- 数据都是结构化的 —— 结构化是所有优化的第一切入点
- 每个数据流的数据源是唯一的 —— 在写入过程中不用过分考虑随机写入
- 数据少有更新或单条删除操作 —— 选择数据结构的重要依据
- 数据一般是按到期日期来删除的 —— 自动淘汰数据是长久运维的必需品
- 数据要优先保证写入操作,读操作为辅 —— 写入吞吐量是第一指标
- 数据流量平稳,可以较为准确的计算 —— 不像 MySQL 的业务场景,压力基本可预测
- 数据一定是指定时间段和指定区域查找的 —— 查询优化的主要入手点
- 数据多有统计、聚合等实时计算操作 —— 提供时序独有的函数
- 数据量巨大,一天的数据量就超过100亿条 —— 针对性的压缩率、横向扩展架构
从上述时序数据特点出发,TDengine 打造了以下的创新技术点:
- 创建一个设备一张表、超级表,压缩率达到到 10% 的级别
- 行式存储 + 列式存储,进一步提升压缩率
- LSM Tree 结构的引擎,SkipList 的 MemTable
- Union all + tag 的超级表语法糖
- 降采样/状态窗口/会话窗口函数
作为时序数据库引擎,TDengine 不需要基于 Hadoop 生态搭建,也不需要拼装 Kafka、Redis、HBase 等诸多组件,它将数据处理中的缓存、消息队列、数据库、流式计算等功能都统一在了一起,这样轻量级的设计不仅让它的安装包很小、对集群资源消耗很少,同时也在一定程度上降低了研发、运维成本,因为需要集成的开源组件少,因而系统可以更加健壮,也更容易保证数据的一致性。
下面延伸一个话题,分享一下我总结的数据库选型原则,以此帮助大家更好地进行数据库选型。
讲讲数据库的选型原则
1. 如果是事务的:
- 单机扛得住的,MySQL/PG 都可以选择
- 单机扛不住,但是好分片的,同上一条
- 不好分片,那可以考虑 TiDB 这种分布式事务的 HTAP
2. 对于非事务,基本上就是各种 MPP 型的 OLAP:
- 多维分析为主,不知道自己什么已知维度的分析,就用 ClickHouse/Doris 这种通用的 OLAP
- 有场景特色的,就选场景通用的,例如 TDengine 做时序场景,Neo4j 做图计算
3. 分布式数据库,看几点:
- Sharding + Partition 策略:这一点基本上决定了性能的上下限
- 分布式架构:这一点影响系统的容量上限/瓶颈模块
- 计算函数:这一点决定好不好用,能不能减轻业务开发的工作量。不然都只有读写没计算,啥计算都自己写肯定是不合适的。
结语
事实证明,专用的比通用的更能打,大家可以移步到 https://docs.taosdata.com/ 去了解 TDengine 的更多技术细节。如果你也面临时序数据处理难题,欢迎加入 TDengine 用户交流群,和更多志同道合的开发者一起探讨解决。