通过对比,能加深对这两个系统的理解,方便后续架构选型时作出正确决定。他们的设计思路有很多值得借鉴的地方,虽然工作中需要用到这些知识的地方不多,但是了解他们的设计细节能极大满足我的好奇心。
Prometheus
需求
- 用于云原生场景下集群监控数据的收集、即席分析(Ad Hoc)和报警
- 处于 Kubernetes 生态,需要能很方便与之集成,被收集对象(target)的种类和数量会动态变化
- 可扩展:能应对集群规模逐步变大的场景:从成百到上千台机器,上万容器的规模
- 追求单机模式下极高的写入吞吐和查询速度,比如支持每秒百万采样数据的写入。
场景特点
- 因为生态中已经有服务发现组件,而且是内网环境,所以它会定期、批量拉取数据,需支持高并发写入。
- 需要存储的指标序列(metric series)数量级会很大。比如一个 Kuberntes 集群中500台机器,每台机器上有几十上百个目标,每个目标里20个指标。这样会有 500*100*20 = 1,000,000,一百万个序列。
- 数据写入和读取的形式完全不同:数据写入按照指标维度,而读取是按照时间区间。最终查询时涉及的区域以时间为横轴,指标不同维度为纵轴的矩形。
- 序列翻腾(Series Churn)问题:随着时间推移,一些指标序列会进入非活跃状态,即再也不会接收到新的数据,而新的序列会出现。这在云环境,尤其是 Kuberntes 这种环境下非常常见:主机粒度、服务实例粒度、容器粒度都会弹性伸缩。
TDengine
需求
- 想要一站式解决目前国内物联网大数据平台的问题:使用互联网的Kafka、HBase、Cassandra、MongoDB、Redis等太重了,研发、运维效率低,定位问题链条太长
- 希望轻松搞定私有化部署
- 能适用于物联网中嵌入式设备和系统
场景特点
- 写入的都是结构化数据,数据 Schema 是事先能确定的
- 写多读少,写入数据都带时间戳
- 写数据流量平稳且可预期。根据设备数量和采集频次,可以预测。比如有100个设备,每30s采集一次数据,那写入最高约3000次每秒。不会像互联网的To C 流量,会受营销的影响。
- 嵌入式设备,存储、算力资源受限,而且设备有利旧的情况
他们的需求和场景有一些共同点:
- 写入数据都带时间戳,一次写入,多次读取,写入的数据不会有更新的需求。
- 查询都是基于连续的时间区间,聚合都是基于更小的时间窗口。比如查询某指标在最近30分钟里,5分钟为窗口的平均值
- 需要提供即席查询(Ad Hoc)能力,即支持用户自定义查询条件。不需要支持跨不同类型的表进行聚合查询的情况。
面向的场景不同
- Prometheus 专注于运维(operation)需要的指标数据,特点是存储的就是一个数值,数据附带了很多维度信息,作为标签(lable)。比如 cpu_total_seconds :
{timestamp=2020-09-05-21-27, host="192.168.1.10", type="idle"}=3551341
;而 TDengine 类似传统数据库,用于存储工业中某类传感器设备采集的指标,所以数据类型多样,如浮点,字符串等。
- TDengine 面向工业物联网时序场景,写入数据的设备数量比较稳定,可预测。而 Prometheus 要拉取的目标是动态变化的。
- TDengine 的场景之一是嵌入式,所以追求无依赖,安装包小,内存占用小。
- TDengine 面向工业物联网,这个领域不像互联网那样人才充沛,IT化程度低,所以 TDengine 想减少维护成本,做全栈,有一部分缓存(无需Redis)、消息队列(无需Kafka)、实时计算能力
- Prometheus专注于单机性能,用于存储最近一段时间数据,没有长期持久化的考虑,弱化分布式集群功能,由其他组件(如Thanos)来完成高可用。
- TDengine 希望通过分布式集群来提供可扩展性、高可靠和高性能,避免单点故障,收费版就是提供集群能力,有持久化多级存储在不同设备上的能力。
使用方式不同
- Prometheus 不需要提前建表,而 TDengine 是关系型数据库模型,需要提前定义好表结构。Promtheus 里写入的数据需要自带描述,包含很多不同维度的标签(lable),这些都是动态的。
- 查询语句:TDengine 使用 SQL 语句。而 Prometheus 有自己的一套 DSL:PromQL
- TDengine 一个采集点一张表,所以一张表不会并发写入。而 Promtheus 为了避免存储的采样数据产生很多小文件,是以块为单位存储指标的
- Prometheus 里 lable 会有字符串,所以查询语句支持文本检索:与、非条件组合
架构、实现方案不同之处
- TDengine中集群功能非常复杂,它需要考虑很多分布式系统里常见的问题:集群成员管理(membership management)、成员通信、数据分片(sharding)、数据分区(partition)、成员选主(leader election)、数据同步(replication)、负载均衡(load balance),防止数据过热或倾斜,
- 上文提到 Prometheus 没有聚焦在解决分布式高可用。它的核心组件是自研的时序数据库 TSDB。通过学习Facebook的开源时序数据库 Gorilla 中的采样数据压缩算法,号称能把一个16字节的采样数据压缩到约1.4字节。
- TDengine 使用 C 来实现,为了避免对其他库有依赖和较量高效,自己实现了定时器,RPC,内存管理等机制。
共同的设计目标
都在追求高性能、低资源占用率,都希望充分利用数据的使用特点:最近写入数据优先。
类似的架构、实现方案
- 写入时,数据都是先写入内存,之后批量刷到磁盘,尽量减少磁盘的写频率。为了防止在此期间的宕机,都使用了提前写(Write-ahead-log)日志
- 为了尽量减少数据的内存和磁盘占用,都会根据数据特点进行压缩。
- 数据都按照时间维度进行分块(chunks),块与块之间独立。这样查询时可以多个块并发查询,然后进行合并。而且后续数据回滚(retention),可以以块为粒度进行,简单高效。
- 如果查看他们的架构图,会发现都需要有存储引擎、计算引擎。
本文中还有很多方面没有涉及,比如 TDengine 集群模式及存储引擎方面的细节。由于 TDengine 存储引擎无文档,目前还不知道是如何设计的,改日读读源码,后续逐步写文章阐明。
通过学习这些系统,会发现技术领域也有经典招式,存在了很多年,威力巨大。比如 WAL,Master slave 同步机制, Raft协议、Quorum 机制,SSTable 等。
- 我为何要开发一个专用的物联网大数据平台,还开源它?
- PromCon 2017: Storing 16 Bytes at Scale
- Writing a Time Series Database from Scratch