什么是时间序列数据
什么是时间序列(Time Series,以下简称时序)数据?从定义上来说,就是一串按时间维度索引的数据。用描述性的语言来解释什么是时序数据,简单的说,就是这类数据描述了某个被测量的主体在一个时间范围内的每个时间点上的测量值。
对时序数据进行建模的话,会包含三个重要部分,分别是:主体,时间点和测量值。套用这套模型,你会发现你在日常工作生活中,无时无刻不在接触着这类数据。
- 如果你是一个股民,某只股票的股价就是一类时序数据,其记录着每个时间点该股票的股价。
- 如果你是一个运维人员,监控数据是一类时序数据,例如对于机器的CPU的监控数据,就是记录着每个时间点机器上CPU的实际消耗值。
这个世界是由数据构成的,在这个世界上存在的每个物体,每时每刻都在产生着数据。而对这些数据的挖掘和利用,在这个时代,正在默默的改变人们的生活方式。例如通过可穿戴设备对个人健康的管理,就是通过设备不断采集你的个人健康数据,例如心跳、体温等等,收集完数据后套用模型计算来评估你的健康度。
如果你的视野和想象空间足够大,你会发现你能够挖掘并利用的数据充斥在你所生活的环境中。这些能够产生数据的对象,会包括你的手机、汽车、空调、冰箱等等。当前比较火热的物联网的核心思想,其实就是构建一个可以让所有物体生产数据并挖掘其价值的网络。而通过这个网络采集的数据,就是典型的时序数据。
时序数据用于描述一个物体在历史的时间维度上的状态变化信息,而对于时序数据的分析,就是尝试掌握并把控其变化的规律的过程。随着物联网、大数据和人工智能技术的发展,时序数据也呈一个爆发式的增长。而为了更好的支持这类数据的存储和分析,在市场上衍生出了多种多样的新兴的数据库产品。这类数据库产品的发明都是为了解决传统关系型数据库在时序数据存储和分析上的不足和缺陷,这类产品被统一归类为时序数据库。
从DB-Engines的数据库类别流行度趋势榜上可以看到,时序数据库(Time Series DB)的流行度在最近的两年内,一直都是保持一个很高的增长趋势。
接下来我会写几篇文章,分别来分析:
1. 时序数据的基本概念,包括模型、特性和基本的查询和处理操作。
2. 几个流行开源时序数据库的底层实现分析
时间序列数据的特性
对于时序数据的特点的分析,会从数据的写入、查询和存储这三个维度来阐述,通过对其特点的分析,来推演对时序数据库的基本要求。
数据写入的特点
- 写入平稳、持续、高并发高吞吐:时序数据的写入是比较平稳的,这点与应用数据不同,应用数据通常与应用的访问量成正比,而应用的访问量通常存在波峰波谷。时序数据的产生通常是以一个固定的时间频率产生,不会受其他因素的制约,其数据生成的速度是相对比较平稳的。时序数据是由每个个体独立生成,所以当个体数量众多时,通常写入的并发和吞吐量都是比较高的,特别是在物联网场景下。写入并发和吞吐量,可以简单的通过个体数量和数据生成频率来计算,例如若你有1000个个体以10秒的频率产生数据,则你平均每秒产生的并发和写入量就是100。
- 写多读少:时序数据上95%-99%的操作都是写操作,是典型的写多读少的数据。这与其数据特性相关,例如监控数据,你的监控项可能很多,但是你真正去读的可能比较少,通常只会关心几个特定的关键指标或者在特定的场景下才会去读数据。
- 实时写入最近生成的数据,无更新:时序数据的写入是实时的,且每次写入都是最近生成的数据,这与其数据生成的特点相关,因为其数据生成是随着时间推进的,而新生成的数据会实时的进行写入。数据写入无更新,在时间这个维度上,随着时间的推进,每次数据都是新数据,不会存在旧数据的更新,不过不排除人为的对数据做订正。
数据查询和分析的特点
- 按时间范围读取:通常来说,你不会去关心某个特定点的数据,而是一段时间的数据。所以时序数据的读取,基本都是按时间范围的读取。
- 最近的数据被读取的概率高:最近的数据越有可能被读取,以监控数据为例,你通常只会关心最近几个小时或最近几天的监控数据,而极少关心一个月或一年前的数据。
- 多精度查询:按数据点的不同密集度来区分不同的精度,例如若相邻数据点的间隔周期是10秒,则该时序数据的精度就是10秒,若相邻数据点的时间间隔周期是30秒,则该时序数据的精度就是30秒。时间间隔越短,精度越高。精度越高的数据,能够还原的历史状态更细致更准确,但其保存的数据点会越多。这个就好比相机的像素,像素越高,照片越清晰但是相片大小越大。时序数据的查询,不需要都是高精度的,这是实际的需求,也是一种取舍,同样也是成本的考虑。还是拿监控数据举例,通常监控数据会以曲线图的方式展现,由人的肉眼去识别。在这种情况下,单位长度下若展示的数据点过于密集,反而不利于观察,这是实际的需求。而另外一种取舍是,若你查询一个比较长的时间范围,比如是一个月,若查询10秒精度的数据需要返回259200个点,而若查询60秒精度的数据则只要返回43200个点,这是查询效率上的一种取舍。而成本方面的考虑,主要在存储的数据量上,存储高精度的数据需要的成本越高,通常对于历史数据,可以不需要存储很高精度的数据。总的来说,在查询和处理方面,会根据不同长度的时间范围,来获取不同精度的数据,而在存储方面,对于历史的数据,会选择降精度的数据存储。
- 多维分析:时序数据产生自不同的个体,这些个体拥有不同的属性,可能是同一维度的,也可能是不同维度的。还是举个监控的例子,我有个对某个集群上每台机器的网络流量的监控,此时可以查询这个集群下某台机器的网络流量,这是一个维度的查询,而同时还需要查询这个集群总的网络流量,这是另外一个维度的查询。
- 数据挖掘:随着大数据和人工智能技术的发展,在存储、计算能力以及云计算发展的今天,数据的高附加值的挖掘已经不再有一个很高门槛。而时序数据蕴含着很高的价值,非常值得挖掘。
数据存储的特点
- 数据量大:拿监控数据来举例,如果我们采集的监控数据的时间间隔是1s,那一个监控项每天会产生86400个数据点,若有10000个监控项,则一天就会产生864000000个数据点。在物联网场景下,这个数字会更大。整个数据的规模,是TB甚至是PB级的。
- 冷热分明:时序数据有非常典型的冷热特征,越是历史的数据,被查询和分析的概率越低。
- 具有时效性:时序数据具有时效性,数据通常会有一个保存周期,超过这个保存周期的数据可以认为是失效的,可以被回收。一方面是因为越是历史的数据,可利用的价值越低;另一方面是为了节省存储成本,低价值的数据可以被清理。
- 多精度数据存储:在查询的特点里提到时序数据出于存储成本和查询效率的考虑,会需要一个多精度的查询,同样也需要一个多精度数据的存储。
时序数据库基本要求
综合以上对于时序数据写入、查询和存储的特点的分析,我们可以归纳总结下对于时序数据库的基本要求:
- 能够支撑高并发、高吞吐的写入:如上所说,时序数据具有典型的写多读少特征,其中95%-99%的操作都是写。在读和写上,首要权衡的是写的能力。由于其场景的特点,对于数据库的高并发、高吞吐写入能力有很高的要求。
- 交互级的聚合查询:交互级的查询延迟,并且是在数据基数(TB级)较大的情况下,也能够达到很低的查询延迟。
- 能够支撑海量数据存储:场景的特点决定了数据的量级,至少是TB的量级,甚至是PB级数据。
- 高可用:在线服务的场景下,对可用性要求也会很高。
- 分布式架构:写入和存储量的要求,底层若不是分布式架构基本达不到目标。
结合时序数据的特点和时序数据库的基本要求的分析,使用基于LSM树存储引擎的NoSQL数据库(例如HBase、Cassandra或阿里云表格存储等)相比使用B+树的RDBMS,具有显著的优势。LSM树的基本原理不在这里赘述,它是为优化写性能而设计的,写性能相比B+树能提高一个数量级。但是读性能会比B+树差很多,所以极其适合写多读少的场景。目前开源的几个比较著名的时序数据库中,OpenTSDB底层使用HBase、BlueFlood和KairosDB底层使用Cassandra,InfluxDB底层是自研的与LSM类似的TSM存储引擎,Prometheus是直接基于LevelDB存储引擎。所以可以看到,主流的时序数据库的实现,底层存储基本都会采用LSM树加上分布式架构,只不过有的是直接使用已有的成熟数据库,有的是自研或者基于LevelDB自己实现。
LSM树加分布式架构能够很好的满足时序数据写入能力的要求,但是在查询上有很大的弱势。如果是少量数据的聚合和多维度查询,勉强能够应付,但是若需要在海量数据上进行多维和聚合查询,在缺乏索引的情况下会显得比较无力。所以在开源界,也有其他的一些产品,会侧重于解决查询和分析的问题,例如Druid主要侧重解决时序数据的OLAP需求,不需要预聚合也能够提供在海量数据中的快速的查询分析,以及支持任意维度的drill down。同样的侧重分析的场景下,社区也有基于Elastic Search的解决方案。
总之,百花齐放的时序数据库产品,各有优劣,没有最好的,只有最合适的,全凭你自己对业务需求的判断来做出选择。
时间序列数据的模型
时序数据的数据模型主要有这么几个主要的部分组成:
- 主体: 被测量的主体,一个主体会拥有多个维度的属性。以服务器状态监控场景举例,测量的主体是服务器,其拥有的属性可能包括集群名、Hostname等。
- 测量值: 一个主体可能有一个或多个测量值,每个测量值对应一个具体的指标。还是拿服务器状态监控场景举例,测量的指标可能会有CPU使用率,IOPS等,CPU使用率对应的值可能是一个百分比,而IOPS对应的值是测量周期内发生的IO次数。
- 时间戳: 每次测量值的汇报,都会有一个时间戳属性来表示其时间。
目前主流时序数据库建模的方式会分为两种,按数据源建模和按指标建模,以两个例子来说明这两种方式的不同。
按数据源建模
如图所示为按数据源建模的例子,同一个数据源在某个时间点的所有指标的测量值会存储在同一行。Druid和InfluxDB采用这种模式。
按指标建模
如图所示为按指标建模的例子,其中每行数据代表某个数据源的某个指标在某个时间点的测量值。OpenTSDB和KairosDB采用这种模式。
这两种模型的选择没有明确的优劣,如果底层是采用列式存储且每个列上都有索引,则按数据源建模可能是一个比较干净的方式。如果底层是类似HBase或Cassandra这种的,将多个指标值存储在同一行会影响对其中某个指标的查询或过滤的效率,所以通常会选择按指标建模。
时间序列数据的处理
这一小节会主要讲解下对时序数据的处理操作,时序数据库除了满足基本的写和存储的需求外,最重要的就是查询和分析的功能。对时序数据的处理可以简单归纳为Filter(过滤), Aggregation(聚合)、GroupBy和Downsampling(降精度)。为了更好的支持GroupBy查询,某些时序数据库会对数据做pre-aggregation(预聚合)。Downsampling对应的操作是Rollup(汇总),而为了支持更快更实时的Rollup,通常时序数据库都会提供auto-rollup(自动汇总)。
Filter(过滤)
如图所示就是一个简单的Filter处理,简单的说,就是根据给定的不同维度的条件,查找符合条件的所有数据。在时序数据分析的场景,通常先是从一个高维度入手,后通过提供更精细的维度条件,对数据做更细致的查询和处理。
Aggregation(聚合)
聚合是时序数据查询和分析的最基本的功能,时序数据记录的是最原始的状态变化信息,而查询和分析通常需要的不是原始值,而是基于原始值的一些统计值。Aggregation就是提供了对数据做统计的一些基本的计算操作,比较常见的有SUM(总和)、AVG(平均值)、Max(最大值)、TopN等等。例如对服务器网络流量的分析,你通常会关心流量的平均值、流量的总和或者流量的峰值。
GroupBy和Pre-aggregation(预聚合)
GroupBy就是将一个低维度的时序数据转换为一个高维度的统计值的过程,如图就是一个简单的GroupBy的例子。GroupBy一般发生在查询时,查询到原始数据后做实时的计算来得到结果,这个过程有可能是很慢的,取决于其查询的原始数据的基数。主流的时序数据库提供pre-aggregation(预聚合)的功能来优化这一过程,数据实时写入后就会经过预聚合的运算,生成按指定规则GroupBy之后的结果,在查询时就可以直接查询结果而不需要再次计算。
Downsampling(降精度),Rollup(汇总)和Auto-rollup(自动汇总)
Downsampling就是将一个高精度的时序数据转换为一个低精度的时序数据的过程,这个过程被称作Rollup。它与GroupBy的过程比较类似,核心区别是GroupBy是基于相同的时间粒度,把同一时间层面上的不同维度的数据做聚合,转换后的结果还是相同时间粒度的数据,只不过是更高的一个维度。而Downsampling是不同时间层面上把相同维度的数据做聚合,抓换为更粗时间粒度的数据,但是还是拥有相同的维度。
如图就是一个简单的Downsampling的例子,将一个10秒精度的数据聚合成30秒精度的数据,统计平均值。
Downsampling分为存储降精度和查询降精度,存储降精度的意义在于降低存储成本,特别是针对历史数据。查询降精度主要是针对较大时间范围的查询,来减少返回的数据点。不管是存储降精度还是查询降精度,都需要auto-rollup。auto-rollup就是自动的对数据做rollup,而不是等待查询时做rollup,过程与pre-aggregation类似,能有效的提高查询效率,这也是目前主流时序数据库已经提供或者正在规划的功能。目前Druid、InfluxDB和KairosDB都提供auto-rollup,OpenTSDB不提供auto-rollup但是暴露了接口支持在外部做auto-rollup后的结果导入。
总结
本篇文章主要分析了时序数据的特性、模型和基本的查询和处理操作,以及对时序数据库的基本要求。在下一篇文章中,会对当前比较流行的几个开源的时序数据库的实现做分析。你会发现,虽然目前存在那么多的时序数据库,但是在基本功能上都是大同小异的。各个时序数据库各有特色,实现方式也各不同,但是都是围绕在对时序数据的写入、存储、查询和分析这几个维度的设计方案的权衡和取舍。没有一个万能的时序数据库解决了所有的问题,在你选择用何种时序数据库的时候,需要从业务角度出发,选择一款最合适的时序数据库。
当然,如果你有兴趣,也可以基于阿里云的表格存储,研发你自己的时序数据库。欢迎扫码加入钉钉群与我交流!