缘起
2021 年 10 月,我偶然读到 Jeff(涛思数据创始人陶建辉)所作的一篇讲述父亲的文章,言辞之恳切,也让我回想起了自己和父亲的种种过往,于是在 TGO(鲲鹏会)微信群中加了 Jeff 的微信。彼时恰逢我们技术选型之时,在和他的寒暄之中,我了解到了时序数据库 TDengine,我和 Jeff 一拍即合。带着业务上的场景和问题,我们约见了一次,他的热情及对 TDengine 的精妙设计深深吸引了我,对于我所提出的一些细节问题,他甚至拿出来初写的代码为我讲解,吃惊之余也让我非常感动。
和 Jeff 的这次会面让我更加了解了 TDengine,也让我看到了国产开源产品的希望。经过审慎的思考,我们选择将 TDengine 接入到系统之中,在一切尘埃落定后我整理出了这篇文章,对 TDengine 的技术架构特点、我们自身业务的实践思路及应用效果进行了相关阐述,希望能帮到有需要的朋友。
业务背景
狮桥集团的网货平台与金融 GPS 系统,对于车辆轨迹收集与计算有着强需求。狮桥大数据团队自研星熠平台采用国标 JT808 协议前置接收数据,通过 Flink 实时计算写入到多个存储模块,终利用络绎大数据 GPS 平台进行业务呈现,支撑集团多个业务系统的风控、贷前、反欺诈等模块。GPS 每日产生总量在 40 亿左右,需要为业务方提供实时末次位置查询,近 180 日行驶轨迹查询,类似车辆轨迹对比查询,以及一些风险逾期的智能分析等等。
从系统架构的迭代看业务需求
纵观狮桥集团的产品历史,技术架构共进行过四个大版本的迭代。
阶段一
初构建系统时,由于工期、团队规模以及服务器资源的限制,实现上非常粗糙,仅能够完成基本的功能。架构大概如下:
在此模式下,我们通过 MQ 接入厂商的数据,利用非分布式的实时计算能力传输到系统当中,仅仅实现了实时的位置查询以及一些非常基础的功能。
阶段二
与此同时,GPS 的轨迹数据在业务中开始使用,这就要求我们必须有存储的方案,需求是实时写批量读,即可以高效插入数据的同时还能够快速扫描大量数据。我们终采用了 Kudu 进行存储,同时利用 Impala 在应用层进行 SQL 解析与加速,方便应用同学进行开发。此外,我们还需要留存 GPS 的数据,会将其进行压缩并写入到 HDFS 中。
阶段三
由于 Kudu+Impala 的模式是一个存储和解释引擎分离的架构体系,优雅与否放在一边,更重要的是, Impala 毕竟是运行在 OLAP 平台上的解释引擎,不适合在生产环境里做高并发的查询引擎,这违背 Impala 的设计初衷。随着不断深入的调研,我们尝试使用 Hbase、Clickhouse 替换 Kudu。此时系统架构演变为了计算引擎逐渐固化、存储引擎不断迭代的形态。
从存储功能而言,我们希望能够读写兼顾、支持 SQL,同时还有合理的分区策略,这一点 Hbase 肯定不能满足,因此我们寄希望于 Clickhouse。在这个阶段中 Clickhouse 的表现确实也不错,但还是没有完全满足需求。
阶段四
此前,我们对 ClickHouse 进行了一系列的测试,虽然效果还算不错,但对于某些场景而言仍然存在问题,以轨迹查询(一般是对单个车辆的轨迹进行查询)为例,虽然列式存储有着天然的优势,但如果 HBase 的 rowkey 设计的更精巧一些,那使用 Hbase 进行时间周期的轨迹查询将会更加直接高效,然而 HBase 天然又对 SQL 非常不友好。因此我们一直在思考一个问题,是否有一个存储技术既可以兼并读写性能,又可以契合到我们的业务场景,且还是 SQL 原生的?
本身 GPS 的数据就类似于设备产生的数据,即时序数据,因此我们开始基于时序数据库赛道进行了一轮筛选。因为同处 TGO“大家庭”中,Jeff 所创立的 TDengine 自然而然地走进了我的视线中,殊不知,这次遇见让我们跳过了千辛万苦,直接触碰到了时序数据库赛道的“天花板”。
为什么我会选择 TDengine?
TDengine 有着非常精妙的架构设计,它是基于物联网典型业务场景和数据特性所设计和优化的时序数据库产品。下面我把一些打动我的优雅设计策略为大家进行下分享。
Device = Table
对于狮桥来讲,如果我们有 50 万辆车跑在路上,那么就需要构建出 50 万张表。乍一听,好像有点不可思议,但是抛开固有思路,这样做的个优点就是解决了我们在上述架构演变的第三阶段中希望解决的问题,即我们希望一个设备在一个时间范围内的数据是连续存储且可以整块获取的,这样基本上歼灭了磁盘的随机访问,类似于 Kafka 的顺序读写机制,可以获得高的效率,TDengine 在这一点上完全解决了我们的痛点。
同时,这个新型概念也让时序数据的写入速度有了非常大的提升,你可以用 Kafka 的顺序写入的思路去理解。
在表级别上做了“继承”
科学的逻辑单元划分
物理节点(Pnode),代表物理(机)节点,通俗来说即裸金属节点 数据节点(Dnode),代表运行实例,也是数据存储的组合单元 虚拟节点(Vnode),是真正负责数据存储与使用的小工作单元,Vnode 组合而成 Dnode
Mnode 的两个精妙之处
在上面的解释中,我特意避开了 Mnode 的说明,下面我要单独讲解。
我们在 TDengine 上的实践
轨迹数据存储与查询
鉴于 TDengine 的特性,用它来存储轨迹数据非常合适。我们在 JT808 协议平台后挂上了 Kafka,通过 Flink 直接把数据写入到了 TDengine 中。在和 TDengine 的小伙伴进行探讨与优化的过程中,我们惊奇地发现,TDengine 写入时的 driver 多采用堆外内存的读写策略,对数据缓存和写入做了极大的优化,写入效率非常高。
末次位置查询
此前,我们需要使用 Flink 把数据打入到 Redis 集群中,进行末次位置的存储与查询。而 TDengine 中的“新热数据缓存”的策略恰恰契合到了我们的需求,Redis 集群就可以直接省略了。当我们研究到这个功能时,简直热泪盈眶——这不是针对某一个业务的帮助,而是在对一整个行业进行了透彻的洞察之后所设计出来的灵魂级的功能。
自动化的分区与数据保存策略
上文中我们讲到过 TDengine 的分片机制,那分区又是如何做到的?在我们使用时发现,TDengine 可以设置 days 的参数进行数据存储,以时间范围对数据进行分区。简单来说,我们的场景是搜索过去 180 天内的轨迹数据,但是更多的场景都是以月的纬度来搜索,那我们我们可以把 days 设置成 30,这样数据就是以每个月分块,搜索的时候也是整体捞出,效率非常高。
使用 TDengine 后的效果
从时序数据量大的特点出发,TDengine 有着一系列非常高效的压缩手段。大家可能都知道 ES 中的 FOR 或者 RBM 等压缩算法,我猜想 TDengine 中应该也使用了类似的压缩方式,使得整体数据轻巧且有序。
写在后
作者简介
杨路,前狮桥集团大数据团队负责人,深耕大数据平台架构与三高应用平台建设,标准技术控一枚。InfoQ 连载《大画 Spark》作者。
来源 https://www.modb.pro/db/388765