云原生时序数据库

云原生时序数据库

云原生数据库 (Cloud Native Database) 是指充分利用了云计算平台以及分布式系统的优势而设计的数据库。云原生数据库提供了按照实际使用资源量来计费的能力,以降低运营成本。此外,它提供了快速开发原型、研发、测试以及部署新的应用的能力,可以大大缩短新的应用从设计开发到进入市场的时间。

作为一个云原生,而不只是能在云上运行的时序数据库(Time Series Database),TDengine 具备云原生数据库的几大特点:水平扩展性(Scalability)、弹性(Elasticity)、韧性(Resiliency)、可观测性(Observability)以及运维自动化(Automation)。

在我们讨论这些特性之前,可以先简单了解一下 TDengine 的分布式设计。

分布式设计

TDengine 的逻辑结构图如下:

云原生时序数据库-TDengine Database 3.0 Design logic

一个完整的 TDengine 系统运行在一到多个物理节点(一台服务器、虚拟机或容器)上的。逻辑上,它包含数据节点(dnode)、TDengine 应用驱动(taosc)以及应用(app)。系统中存在一到多个数据节点,这些数据节点组成一个集群(cluster)。应用通过 taosc 的 API 与 TDengine 集群进行互动。下面对每个逻辑单元进行简要介绍。

数据节点(dnode): dnode 是 TDengine 服务器侧执行代码 taosd 在物理节点上的一个运行实例,一个工作的系统必须有至少一个数据节点。dnode 包含零到多个逻辑的虚拟节点(vnode),零或者至多一个逻辑的计算节点(qnode),零或者至多一个逻辑的管理节点(mnode)。

虚拟节点(vnode): 为更好地支持数据分片、负载均衡,防止数据过热或倾斜,数据节点被虚拟化成多个虚拟节点(vnode,图中 V2,V3,V4 等)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表(数据采集点)的数据,包括时序数据和元数据。一个 vnode 就是一个片 (shard)。

计算节点(qnode):计算节点仅仅负责计算。当一个查询执行时,依赖执行计划,调度器会安排一个或多个 qnode 来一起执行。qnode 能从 vnode 获取数据,也可以将自己的计算结果发给其他 qnode 做进一步的处理。一个集群里允许有多个 qnode,它的启动和停止完全由 mnode 根据系统资源和性能要求来决定。通过引入独立的计算节点,TDengine 实现了存储和计算分离。

管理节点(mnode): 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中 M)。同时,管理节点也负责元数据(包含用户、数据库,但不包含表、静态标签等)的存储和管理,因此也称为 Meta Node。一个集群里只有一个管理节点,但为提高管理节点的高可用性,允许有三个副本。

taosc:taosc 是 TDengine 给应用提供的驱动程序(driver),负责处理应用与集群的接口交互,提供 C/C++ 语言原生接口,内嵌于 JDBC、C#、Python、Go、Node.js 语言连接库里。应用都是通过 taosc 而不是直接连接集群中的数据节点来与整个集群交互的。

水平扩展性(Scalability)

TDengine 是通过数据采集点以及时间两个维度,对大数据进行切分,实现水平扩展的,它既支持分片,也支持分区。

云原生时序数据库-TDengine Database 3.0 PartitionSharding

分片:在 TDengine 的设计与实现里,一个集群有多个数据节点,每个数据节点可以有一个或多个虚拟节点(vnode),每个虚拟节点里存储了一定数量的数据采集点的数据,而一个数据采集点的时序数据和元数据永远只存放在一个 vnode 里。这样如果有很多数据采集点,通过一致性 Hash,这些数据采集点的数据将会分布在多个 vnode 上,分布在多个节点里。

分区:除将数据分片之外,TDengine 还将一个 vnode 里存储的时序数据按照时间段进行切分。每个时间段的数据都一定保存在一起,不同时间段的数据不会有交集,时间段可以是一天,几天,一周,由用户自己定义。按照时间段切分时序数据有很多好处,查询数据时,根据时间段,可以直接定位要查找的文件,从而加快查询速度。另外一方面,可以高效地实现数据保留策略。超过最长保留时间的数据,直接删除一个时间段对应的文件即可。而且按照时间段切分数据,还可以方便实现多级存储,冷热数据放在不同存储介质上,进一步降低存储成本。

高基数:在 TDengine 的设计中,每个数据采集点的元数据没有存放在中心点,而是分布在各个 vnode 里。当应用要将数据插入到一张表或对一张表做查询操作时,基于表名的 hash 值,插入或查询请求将被直接发送到对应的 vnode,由于没有中心点,不会有任何瓶颈。对于多个点的聚合计算,查询的请求将被同时发往相关的 vnode,每个 vnode 都会执行对应的聚合操作,然后将结果返回给 taosc 或 qnode,做进一步的聚合。

TDengine 具有超强的水平扩展能力,为获得更多的数据处理能力,只需要加入更多的数据节点即可。通过测试,我们可以验证,在 10 亿时间线,100 个数据节点的情况下,整个 TDengine 性能还能得到很好的保证。时序数据处理里的“高基数”问题完全得到了解决。

弹性(Elasticity)

在 IoT 或 IIoT 情况下,系统需要快速将最新数据返回给应用程序。例如,车队管理系统总是想知道每辆卡车的当前 GPS 位作为一个云原生数据库,TDengine 不仅提供 scale up 的能力,也提供 scale down 的能力,从而让系统具有弹性。

为支持存储的弹性,如果插入的延时已经超过一定阈值或者性能不够,TDengine 会将一个 vnode 拆分成两个,从而分配更多的系统资源给数据写入操作。另一方面,在能够保证延时与性能的情况下,TDengine 也可以把多个 vnode 合并成一个,以节省系统资源。

为支持计算的弹性,TDengine 引入了计算节点 qnode。对于简单的查询,比如获得某张表的原始数据或卷曲数据(rollup data),对应的 vnode 将完成所有的操作,无需 qnode 的参与。但对于一个需要排序、分组或其他需要计算资源的操作,查询的执行过程中,一个或多个 qnode 将被调用。在具体的部署中,qnode 可以运行在容器里,它的启停完全由 mnode 根据系统负载情况决定。

通过引入 qnode,TDengine 成为一个理想的时序数据分析平台,包括实时数据分析和批分析。在云计算的环境里,计算资源是近似无限的,但又可以弹性的伸缩。

韧性(Resilience)

TDengine 的韧性是通过其高可靠与高可用设计来实现的。

对于数据库,存储的高可靠是最高优先级的。TDengine 采用 Database 实现中传统的方法 WAL(Write Ahead Log) 来保证即使系统宕机,数据仍然可以恢复而不会丢失,从而实现数据的高可靠。在设计中,新写入的数据总是先写入 WAL,然后写入内存,转发给其他节点,再给应用发回确认的。写入流程如下图所示:

云原生时序数据库-TDengine Database 3.0 Write

TDengine 通过多副本以及 RAFT 一致性协议,保证 vnode 和 mnode 的高可用性。对于元数据,TDengine 采取的是强一致性,而对于时序数据,TDengine 采取的是弱一致性,这样保证时序数据的写入效率。

在不同数据节点上的 vnode 可以形成一个虚拟节点组。虚拟节点组里,数据是通过 RAFT 协议来保证数据一致的,一般虚拟节点组有 3 个虚拟节点。数据写入操作总是在 Leader 节点上进行,但是查询可以在 Leader 和 Follower 节点上同时进行,以提升查询能力。当 Leader 节点失败,系统将自动选择新的 Leader,只要虚拟节点组里超过半数以上的节点仍然工作,那么这个虚拟节点组就可以继续提供数据写入和查询操作,从而保证系统的高可用。

对于 mnode,为保证其高可用,整个集群会部署三个 mnode,这三个 mnode 形成一个虚拟节点组,它们之间的数据一致性通过 RAFT 来实现,而且是强一致。只要超过半数的 mnode 工作,mnode 就可对外服务。

可观测性(Observability)

TDengine 采集了各种指标来监测系统是否运行正常,这些指标包括 CPU、内存、磁盘、流量、请求次数、延时等。它提供了 Grafana 的看板 TDinsight,以实现这些指标的可视化与报警。关于更多 TDinsight 的信息,请看文档

云原生时序数据库-TDengine Database TDinsight-1-cluster-status

TDengine 还提供了一个模块 taosKeeper,它能够将采集的指标发送到其他监测工具,比如 Prometheus,这样便于将 TDengine 的监测集成到已有的可观测系统。

运维自动化(Automation)

TDengine 可以用二进制包或 Docker 镜像进行安装。TDengine 集群可以在 Kubernetes 环境通过 kubectl 命令或 helm chart 来部署。数据节点的增加或删除可以通过执行 kubectl 或 heml 命令进行。TDengine 集群的管理完全可以通过脚本自动化进行,让运营和维护变得简单。关于 Kubernetes 部署,请参考相关文档。

总结

通过分布式设计、分区分片、存储和计算分离,RAFT 一致性协议等手段,TDengine 这个时序数据处理平台具备水平扩展性、弹性与韧性。通过支持容器、Kubernetes 部署、全面的指标监测和自动化脚本,TDengine 可以方便地运行在私有云、公有云或混合云上,从而充分利用云平台的优势。因此 TDengine 是一个云原生时序数据库(Cloud Native Time-Series Database),而不只是一个能在云上运行的数据库。

更多亮点 >>