在 8 月 13 日的 TDengine 开发者大会上,涛思数据创始人陶建辉进行了题为《高性能、云原生的极简时序数据处理平台》的主题演讲。在本次演讲中,他不仅分享了时序数据库现阶段的技术痛点,还深入阐释了打造 TDengine 3.0 的原因以及实践思路。本文根据演讲内容整理而成。
在 2017 年刚开始做时序数据库(Time Series Database,TSDB)时,学物理的我想当然地认为做好数据库没有大家说的那么难,但做了 5 年后才发现,这真的不是一件很容易的事。下面我具体说说难在哪里:
- 水平扩展性(Scalability)问题。在 TDengine 刚开发没多久时,我用一台 128 核的机器对 TDengine 进行了测试,结果性能远远没有达到预期,这件事情也让我清楚地意识到,理想的水平扩展能力很难实现。
- 没有真正的云原生化。我个人特别坚信云是未来,数据库也一定要走向云原生(Cloud Native),但在深度研究市面上的数据库产品后,我发现大部分数据库都不是云原生,而仅仅是“云就绪”(Cloud Ready),即数据库服务提供商在转售云平台。真正的云原生数据库应该具备存算分离、计算和存储能力弹性扩张、能够在云上部署、自动化部署等特点。
- 复杂性(Complex)问题。2016 年我看到很多人在处理一些简单的时序数据时,要把整个 Hadoop 系统搬过来,要加 HBase 层,还要把 Flink、Spark 等等全部加上,这对于研发人员来讲就是个灾难。但时至今日,这个复杂性也并没有随着时序数据库的发展得到充分的解决,只有打造一个集 Kafka、Flink、Spark、Redis 等第三方工具功能于一体的极简时序数据处理平台,这一问题才有望充分解决。
- 数据分析能力跟不上。诸如 InfluxDB、Prometheus 等较为流行的 Time-Series Database,由于不支持 SQL,导致很多正常的数据服务、数据仓库的分析方法都用不上。结合我过往不断跨界的经验,我发现了这个问题,所以 TDengine 早就支持了 SQL,不过仍然需要优化和加强。
发现并解决上述的问题,便是我们打造 TDengine 3.0 的初衷。从去年 6 月开始,在 40 多个研发一年多的努力下,TDengine 3.0 终于在今天正式和大家见面了。
下面我们就一起看看 TDengine 3.0 是什么样子的。
云原生时序数据库
水平扩展
打造云原生时序数据库,第一个要素就是必须是分布式架构。其实 TDengine 以前也是分布式架构,但为了实现云原生的种种特性,我们在此架构基础上引入了一个新的节点——计算节点 Qnode。
通过云原生如何解决可扩展性问题?还是通过分片分区来解决,数据切分的方法我们没有做太多改动,TDengine 一开始就是这么做的,在时间轴上以天或周为单位对数据进行切分,同时将定量设备的数据分配给每个区(Vnode)进行处理。
跟 2.x 相比,3.0 最大的不同就是元数据的管理也变成了完全分布式的。这也是我在此前版本中吸取了一个教训而做出的改变,最开始我没想到元数据的管理如此之难。
有一次我们和涂鸦聊合作,他们要测五千万个设备的数据,TDengine 2.0 在测试中就出现了高基数问题。在 2.x 的设计中,我们的元数据统一存放在 mnode 中,这在此次测试中就成为了一个瓶颈——在进行聚合操作时,光是把五千万个设备中的标签数据拉出来就需要很长时间,聚合速度可想而知。也因此,高基数成为了我们在 3.0 版本中解决的首要问题。
现在的 TDengine 管理节点不再存储每个设备或每张表的元数据了,而是把这些元数据还有时序数据完全存储在 vnode 里,之后会用 B+ 树、一致性哈希来处理。这样一来,我们在插入一个数据到任何一个片或者一个区时都不再需要经过任何中间节点,彻底解决了高基数的问题。
经过测试,TDengine 3.0 完全能够支持 10 亿个设备、100 台服务器节点,同时整个启动时间也很快,不到一分钟整个集群就能启动。尽管此前的 2.6 也能支持五千万的设备数,但启动时间就大概要三四十分钟,设备数量多的时候不太给力。
中国智能电表至少要有十亿台,给十亿台电表做聚合操作可以说相当不容易,解决高基数问题是很重要的,TDengine 发展到 3.0 版本才算是真正把这个问题解决了。
弹性
云原生里面一个很重要的东西就是弹性,它跟水平扩展的弹性还略有不同,首先一定要把计算和存储分离,我上面说 3.0 新增了一个计算节点 Qnode,它是专门用来做计算的,但简单查询 Vnode 就可以直接操作了,如果牵扯到 group by、order by 等复杂查询,就需要在 Qnode 上进行了。
Qnode 的优点就是操作者可以动态地启动、停止,也就是说它的计算资源可以动态地进行操控,这样就实现了存算分离。同时 Vnode 也可以进行拆分或合并,保证存储也可以弹性伸缩。
如果系统不能做到真正的弹性伸缩,就一定不是云原生的,很多企业打着云原生的幌子,但实际上连云原生是什么都说不清楚。在我看来,云原生就是要充分利用云平台的优势,即计算资源、存储资源、网络资源,且要完全弹性,你想要就马上给你,不想要就马上释放,这样才能真正实现成本的节约。
韧性
云原生里还有一个重要概念叫韧性,简单来讲就是高可靠、高可用。TDengine 在设计之初就考虑到了这一点,其高可用就是用多个副本来实现,但后面发现以前的同步算法还是存在漏洞,因此 3.0 就完全采用了标准 RAFT 协议来实现数据复制,以此保证数据一致性。
除了高可用,合格的韧性还要保证系统的高可靠,保证机器即使宕机了依然还能重启,且还能继续工作,数据也不会丢失。
部署、维护
我们以前都是建议用户到 Kubernetes 上部署,但并没有出详细的自动化流程,3.0 版本给出了详细的 Kubernetes 部署文档,只需修改两个配置文件,马上就能部署整个集群,极其简单。
除了更加理解云原生,3.0 给我带来的另一个收获就是对于可观测性的理解,可观测性其实远远不只是监控,它包括了 logging、tracing、metrics,我们在 3.0 上实现了整个架构,让用户对 TDengine 所有集群的运行状态都能真正监测到,让系统维护变得更加简单。在维护上,还有关键一点就是要做到自动化,一切都要脚本化,减少人工手动操作的成本。
极简的时序数据处理平台
在 TDengine 创建之初,打造一款极简的时序数据处理平台就是我的初衷。要知道,一个通用的架构往往是要先把采集数据送到 Kafka 或者各种消息队列里,消费之后一部分数据再送到 Spark 或者 Flink 里做流计算处理,一部分数据送到数据库做直接存储,还有一部分则会传输到 Redis 做缓存,这样一个数据处理平台,里面要集成很多软件,维护起来相当困难。
要打造一款极简的时序数据处理平台,首先要解决的问题就是缓存,因为缓存对于物联网、车联网来讲都是极其关键的,TDengine 早就具备了缓存功能,这个也是很多用户特别喜欢的功能,非常方便。
TDengine 的数据订阅实现机制
对于 TDengine 3.0 来说,还有一个很大的改进是重构并优化了数据订阅功能。TDengine 是用 WAL 来做的订阅,技术人员应该都知道,WAL 本身就可以看作一个队列,完全按照数据到达顺序来追加写入。在 TDengine 3.0 中,既可以订阅一个数据库,也可以订阅一个自带标签的“超级表”,直接实现过滤,比如只想订阅功率超过多少的智能电表数据,直接就能实现。订阅完成后无需再拿到应用端去过滤,极大提升了数据传输的效率。
我们做产品的目的就是要让大家用起来简单,因此在做消息队列功能时,API 全部对标的都是 Kafka,现在不光是初始化和每条命令,连测试都完全一样。以前经常有友商会对标 TDengine,提出性能要超出 TDengine 一百倍之类的观点,但标准就是自己定义的,甚至都没有公开。但我们只采用国际通用的测试标准来测,包括消息队列,直接用 Kafka 公开的 benchmark 进行测试,我们认为这样才有说服力,才是客观的。欢迎大家体验。
TDengine 3.0 还有一个很大的改进就是继续优化了流计算功能。之前 TDengine 就已经支持一个连续查询的流计算,这种周期性的查询流计算还是很有用的,但是功能覆盖却还不够。在 IoT 场景下做数据清洗、过滤时,要做一些实时的触发,必须使用事件驱动的流计算,经过一年多的努力,TDengine 3.0 终于升级了这一流计算功能。
TDengine 3.0 所支持的流计算功能是非常典型的,如上面的架构图所示,数据源要先进入 Input Queue,再进入流计算的 Task,再输出到另外一个列。而且流计算可以嵌套,一层一层形成一个数据的 pipeline。从方便用户使用的角度出发,TDengine 的流计算语法就是 SQL,里面做了 windows 等扩展,可以在数据写入时触发,也可以在窗口结束触发。
此外, TDengine 3.0 对 UDF 的支持也进行了优化。3.0 对 UDF 进行了重新实现,加上时间驱动的流计算,我觉得至少在时序数据的场景下,TDengine 已经能够完全代替 Spark 和 Flink。
极简的时序数据处理平台
但在此我需要再重申一下,我们优化 TDengine 的缓存、消息队列、流计算等功能,并不是想代替 Flink、Spark、Kafka 这类通用型的消息队列软件、流计算软件,只是想简化这款基于时序数据场景做的数据库软件,更加便于大家使用,通过降低系统复杂度来真正降低运维和存储成本,这也是我们搭建极简时序数据处理平台的原因。
便捷的数据分析
TDengine 3.0 还有一个较大的改变就是重新设计了计算引擎,现在像 Planner、优化器、执行器等都具备了。对于数据来说,查询是非常重要的,数据存储好之后,用户最重要的就是要从中挖掘数据价值,TDengine 对 SQL 的支持已经做的很好了。
但是 SQL 这个概念也很复杂,我们不可能像 Oracle 一样支持那么多详细的复杂查询,3.0 的查询对标的是 Hive,Hive 能做的所有的分析 TDengine 已经都能做了。此外,TDengine 也有很多针对时序数据的特有函数,比如说移动平均、时间加权平均等等。
重构查询引擎的 TDengine 3.0 已经成为了一个很好的查询工具,再辅以下面的这些手段,足以让查询变得更有效:
- 超级表适合做多维度分析
- 计算与存储分离
- 数据分片、分区
- 流处理
- 历史数据和实时数据统一分析
- 来自控制台的临时查询
- Python Pandas,数据框支持
- Grafana,用于可视化的谷歌数据工作室
TDengine 3.0 的最后一个更新功能叫作 taosX,它充分利用了 TDengine 的数据订阅功能来解决增量备份、异地容灾,即把一个集群的数据复制到另外一个地方去,以实现边云协同。众所周知,边云协同在物联网里面很重要,如果说工厂的数据想要同步到集团,就需要一个边云的盒子一层接一层做同步,而这个需求,在 TDengine 中就靠 taosX 解决了。
此外除了技术上的种种进步外,今天我还要给大家同步一个好消息。为了方便工业场景下大量的 Windows 客户,TDengine 3.0 的 Windows 版本也正式发布了,包括客户端和服务器。同时,大概在 10 月 1 日,TDengine 的 Mac 版本也将正式对外发布,大家敬请期待。
目前 TDengine 3.0 的代码已经在 GitHub(https://github.com/taosdata/T...) 上公开,大家可以完全参照我们的 readme 文件来编译,也可以到 TDengine 的官网去下载。如果你是一个开发者,觉得 TDengine 这个项目有意思,可以选择加入我们的开发者社区,学习源代码,甚至是贡献代码。如果你是一个物联网或者工业互联网应用的开发者,那欢迎你把 TDengine 应用起来,你可以加入我们的用户群,我们很乐意回答你的问题。如果你是个 DBA,那欢迎你马上下载,去体验我刚才讲的各种功能。
中国的开源软件特别需要大家的支持和使用,我经常跟销售团队起争论,比如在决定哪些功能必须放在企业版时,我就表示所有的核心功能都必须同步在开源版本上,而绝不能只放在企业版里。为什么?因为想要做好开源就一定要给用户带来价值,我希望有越来越多的人能够成为 TDengine 的布道者。
结语
我特别喜欢丘吉尔的这段名言,翻译成中文就是“成功不是终点,失败不是终结,唯有你继续前行的勇气最为关键”。从创建 TDengine 到现在,我们已经走过了 5 个年头,开源也已经走过了 3 年,在这个过程中取得了一些小小的成功,但是我们前面的路还很漫长,我已经做好了再战 5 年、10 年的准备。希望我在七八十岁的时候还能继续写代码,和大家一起讨论问题,度过真正有价值的一生。
想了解更多 TDengine Database的具体细节,欢迎大家在GitHub上查看相关源代码。