时间序列数据库-Time Series Database(TSDB)
2022-08-22 09:35:16 阿炯

时序数据库是针对采集、处理和存储带有时间戳数据进行优化过的数据库。此类数据可能包括来自服务器和应用程序的参数指标、来自物联网传感器的读数、网站或应用程序上的用户交互、以及金融市场上的各种交易活动。时序数据是基于时间的一系列的数据。在有时间的坐标中将这些数据点连成线,往过去看可以做成多纬度报表,揭示其趋势性、规律性、异常性;往未来看可以做大数据分析,机器学习,实现预测和预警。时序数据库就是存放时序数据的数据库,并且需要支持时序数据的快速写入、持久化、多纬度的聚合查询等基本功能。维基百科上对于时间序列的定义是一系列数据点按照时间顺序排列:时间序列数据就是历史烙印,具有不变性、唯一性、时间排序性


对比传统数据库仅仅记录了数据的当前值,时序数据库则记录了所有的历史数据。同时时序数据的查询也总是会带上时间作为过滤条件。时序数据是基于时间的一系列的数据。在有时间的坐标中将这些数据点连成线,往过去看可以做成多纬度报表,揭示其趋势性、规律性、异常性;往未来看可以做大数据分析,机器学习,实现预测和预警。时序数据库就是存放时序数据的数据库,并且需要支持时序数据的快速写入、持久化、多纬度的聚合查询等基本功能。

此处的时序数据通常具有如下属性特征:
1).每个数据点都包含了用于索引、聚合、以及采样的时间戳。此类数据往往是多维的、且相关的。
2).它们主要以高速写入(或称:摄取)的方式,来捕获高频的数据。
3).数据的汇总视图(例如:降采样、聚合视图或趋势线)可以提供比单个数据点更多的洞见。例如,考虑到网络的不稳定性、或传感器读数可能出现的异常,我们需要为在一段时间内,针对超过预定阈值的某些平均值设置警报,而并非仅针对单个数据点。
4).通常需要获取在一段时间内访问某类数据(例如,获取过去一周内的点击率数据),以供深入分析。

虽然其他类型的数据库,也可以在一定程度上处理时序数据,但是TSDB可以在设计上,针对上述数据特性,更有效地处理那些随着时间的推移,而开展的各类数据摄取、压缩、以及聚合活动。时序数据库是专门处理时序数据的数据库,因此其相关概念是和时序数据紧密联系的。

时序数据的主要数据属性如下:每个数据点都包含用于索引、聚合和采样的时间戳。该数据也可以是多维的和相关的;写多读少,需要支持秒级和毫秒级甚至纳秒级高频写入;查询通常是多维聚合查询,对查询的延迟要求比较高数据的汇总视图(例如,采样或聚合视图、趋势线)可能比单个数据点提供更多的洞察力。例如,考虑到网络不可靠性或传感器读数异常,可能会在一段时间内的某个平均值超过阈值时设置警报,而不是在单个数据点上这样做;分析数据通常需要在一段时间内访问它(例如,统计过去一周的点击率数据)。时序数据库是专门用于存储和处理时间序列数据的数据库,支持时序数据高效读写、高压缩存储、插值和聚合等功能。

下面是时序数据库的一些基本概念。
metric: 度量,相当于关系型数据库中的table。
data point: 数据点,相当于关系型数据库中的row。
timestamp:时间戳,代表数据点产生的时间。
field: 度量下的不同字段。比如位置这个度量具有经度和纬度两个field。一般情况下存放的是会随着时间戳的变化而变化的数据。
tag: 标签,或者附加信息。一般存放的是并不随着时间戳变化的属性信息。timestamp加上所有的tags可以认为是table的primary key。

下面又是时序数据库的一些基本概念。
* 度量 Metric:Metric 类似关系型数据库里的表(Table),代表一系列同类时序数据的集合,例如为空气质量传感器建立一个 Table,存储所有传感器的监测数据。
* 标签 Tag:Tag 描述数据源的特征,通常不随时间变化,例如传感器设备,包含设备 DeviceId、设备所在的 Region 等 Tag 信息,数据库内部会自动为 Tag 建立索引,支持根据 Tag 来进行多维检索查询;Tag 由 Tag Key、Tag Value 组成,两者均为 String 类型。
* 时间戳 Timestamp:Timestamp代表数据产生的时间点,可以写入时指定,也可由系统自动生成;
* 量测值 Field:Field描述数据源的量测指标,通常随着时间不断变化,例如传感器设备包含温度、湿度等Field;
* 数据点Data Point: 数据源在某个时间产生的某个量测指标值(Field Value)称为一个数据点,数据库查询、写入时按数据点数来作为统计指标;
* 时间线 Time Series :数据源的某一个指标随时间变化,形成时间线,Metric + Tags + Field 组合确定一条时间线;针对时序数据的计算包括降采样、聚合(sum、count、max、min等)、插值等都基于时间线维度进行;


可以看到时序数据库需要解决以下几个问题
1).时序数据的写入:如何支持每秒钟上千万上亿数据点的写入。
2).时序数据的读取:又如何支持在秒级对上亿数据的分组聚合运算。
3).成本敏感:由海量数据存储带来的是成本问题。如何更低成本的存储这些数据,将成为时序数据库需要解决的重中之重。

数据写入的特点

写入平稳、持续、高并发高吞吐:时序数据的写入是比较平稳的,这点与应用数据不同,应用数据通常与应用的访问量成正比,而应用的访问量通常存在波峰波谷。时序数据的产生通常是以一个固定的时间频率产生,不会受其他因素的制约,其数据生成的速度是相对比较平稳的。
写多读少:时序数据上95%-99%的操作都是写操作,是典型的写多读少的数据。这与其数据特性相关,例如监控数据,你的监控项可能很多,但是你真正去读的可能比较少,通常只会关心几个特定的关键指标或者在特定的场景下才会去读数据。
实时写入最近生成的数据,无更新:时序数据的写入是实时的,且每次写入都是最近生成的数据,这与其数据生成的特点相关,因为其数据生成是随着时间推进的,而新生成的数据会实时的进行写入。数据写入无更新,在时间这个维度上,随着时间的推进,每次数据都是新数据,不会存在旧数据的更新,不过不排除人为的对数据做订正。

数据查询和分析的特点
按时间范围读取:通常来说,不会去关心某个特定点的数据,而是一段时间的数据。
最近的数据被读取的概率高。
历史数据粗粒度查询的概率搞。
多种精度查询与多维度分析。

数据存储的特点

数据量大:拿监控数据来举例,如果我们采集的监控数据的时间间隔是1s,那一个监控项每天会产生86400个数据点,若有10000个监控项,则一天就会产生864000000个数据点。在物联网场景下,这个数字会更大。整个数据的规模,是TB甚至是PB级的。
冷热分明:时序数据有非常典型的冷热特征,越是历史的数据,被查询和分析的概率越低。
具有时效性:时序数据具有时效性,数据通常会有一个保存周期,超过这个保存周期的数据可以认为是失效的,可以被回收。一方面是因为越是历史的数据,可利用的价值越低;另一方面是为了节省存储成本,低价值的数据可以被清理。
多精度数据存储:在查询的特点里提到时序数据出于存储成本和查询效率的考虑,会需要一个多精度的查询,同样也需要一个多精度数据的存储。


数据的存储可以分为两个问题,单机上存储和分布式存储。

单机存储

如果只是存储起来,直接写成日志就行。但因为后续还要快速的查询,所以需要考虑存储的结构。传统数据库存储采用的都是B tree,这是由于其在查询和顺序插入时有利于减少寻道次数的组织形式。磁盘寻道时间是非常慢的,一般在10ms左右。磁盘的随机读写慢就慢在寻道上面。对于随机写入B tree会消耗大量的时间在磁盘寻道上,导致速度很慢。SSD具有更快的寻道时间,但并没有从根本上解决这个问题。

对于90%以上场景都是写入的时序数据库,B tree很明显是不合适的。业界主流都是采用LSM tree替换B tree,比如Hbase, Cassandra等NoSQL中。LSM tree包括内存里的数据结构和磁盘上的文件两部分,分别对应Hbase里的MemStore和HLog;对应Cassandra里的MemTable和sstable。其操作流程如下:
1).数据写入和更新时首先写入位于内存里的数据结构。为了避免数据丢失也会先写到WAL文件中。
2).内存里的数据结构会定时或者达到固定大小会刷到磁盘。这些磁盘上的文件不会被修改。
3).随着磁盘上积累的文件越来越多,会定时的进行合并操作,消除冗余数据,减少文件数量。

LSM tree核心思想就是通过内存写和后续磁盘的顺序写入获得更高的写入性能,避免了随机写入。但同时也牺牲了读取性能,因为同一个key的值可能存在于多个HFile中。为了获取更好的读取性能,可以通过bloom filter和compaction得到。


分布式存储

时序数据库面向的是海量数据的写入存储读取,单机是无法解决问题的。所以需要采用多机存储,也就是分布式存储。分布式存储首先要考虑的是如何将数据分布到多台机器上面,也就是分片(sharding)问题。下面我们就时序数据库分片问题展开介绍。分片问题由分片方法的选择和分片的设计组成。

分片方法
时序数据库的分片方法和其他分布式系统是相通的。
哈希分片:这种方法实现简单,均衡性较好,但是集群不易扩展。
一致性哈希:这种方案均衡性好,集群扩展容易,只是实现复杂。代表有Amazon的DynamoDB和开源的Cassandra。
范围划分:通常配合全局有序,复杂度在于合并和分裂。代表有Hbase。

分片设计
分片设计简单来说就是以什么做分片,这是非常有技巧的,会直接影响写入读取的性能。结合时序数据库的特点,根据metric+tags分片是比较好的一种方式,因为往往会按照一个时间范围查询,这样相同metric和tags的数据会分配到一台机器上连续存放,顺序的磁盘读取是很快的。再结合上面讲到的单机存储内容,可以做到快速查询。进一步考虑时序数据时间范围很长的情况,需要根据时间范围再将分成几段,分别存储到不同的机器上,这样对于大范围时序数据就可以支持并发查询,优化查询速度。


时序数据库遇到的挑战

很多人可能认为在传统关系型数据库上加上时间戳一列就能作为时序数据库。数据量少的时候确实也没问题,但少量数据是展现的纬度有限,细节少,可置信低,更加不能用来做大数据分析。很明显时序数据库是为了解决海量数据场景而设计的。

可以看到时序数据库需要解决以下几个问题
时序数据的写入:如何支持每秒钟上千万上亿数据点的写入。
时序数据的读取:又如何支持在秒级对上亿数据的分组聚合运算。
成本敏感:由海量数据存储带来的是成本问题。如何更低成本的存储这些数据,将成为时序数据库需要解决的重中之重。

常用时序数据压缩编码算法浅析

- 时序数据的概念和特点 -
时序数据是指时间序列数据,是按时间顺序记录的数据列。时序数据可以是时期数,也可以时点数。对于数据库而言,时序数据一般是一系列带有时间戳和数据值的数据点,且各列数据值类型相同、数值随时间戳递增(减)或在有限区间内波动。

- 时序数据常用压缩编码方式 -
从时序数据的特点来看,通用的压缩算法和按行压缩并不能很好的压缩时序数据,因此时序数据库大多都针对不同类型的数据按列采用不同压缩编码方式来减少数据存储的空间占用,提高存储空间利用率。

Delta
差分编码又称增量编码,编码时,第一个数据不变,其他数据转换为与上一个数据的 Delta。该算法应用广泛,如需要查看文件的历史更改记录(版本控制、Git 等)。在时序数据库中,很少单独使用,一般搭配 Simple8b 或者 Zig-Zag 一起使用,压缩效果更好,下面举例说明 Delta 时间戳压缩:

时间戳一般采用 int64 类型进行存储,需要占用 8byte (64bit) 存储空间。最直接的优化就是存储时间戳的差值,这里需要起始时间戳和 Delta 的最大范围阈值。有两种常用的实现思路:

1. 存储相邻两个时间戳差值 Delta (n) = T (n) - T (n-1)

Unix时间戳

Delta

1571889600000

0

1571889600010

10

1571889600025

15

1571889600030

5

1571889600040

10



2. 存储与起始时间戳的差值 Delta(n) = T(n) - T(0)

Unix时间戳

Delta

1571889600000

0

1571889600010

10

1571889600025

25

1571889600030

30

1571889600040

40



假设起始时间戳为 1571889600000,Delta 的最大范围阈值为 3600s,每个 Delta 的数值需要 13bit 可以存储。因此以上时间戳数据共占用空间为 64 + 13 * 4 = 116bit。思路 1 的优势是不需要对块内数据依次遍历,但是相比思路 2 可能需要更为频繁地更换起始时间,根据实际需求选择合适的压缩方案。

Delta of Delta
又名二阶差分编码,是在 Delta 编码的基础上再一次使用 Delta 编码,比较适合编码单调递增或者递减的序列数据。例如 2,4,4,6,8 , Delta 编码后为 2,2,0,2,2 ,再 Delta 编码后为 2,0,-2,0,0。通常也会搭配 Simple-8B 或者 Zig-Zag 一起使用。

Facebook Gorilla 有详细阐述 delta-of-delta 编码的计算方式,针对不同时间跨度的数据给出了一种较为通用的处理方案(a+b=c, a 表示存储标识位占用 bit,b 表示存储 data 需要的 bit)。


依然通过一组时间戳数据来直观感受下 delta-of-delta 编码的压缩效果:



依然假设起始时间戳为 1571889600000,delta 的最大范围阈值为 3600s,占用存储空间对比如下:

Delta 算法: 64 + 13 * 7 = 155bit 。
Delta-of-delta 算法: 64 + 9 * 4 + 1 * 3 = 103bit 。可以看出 delta-of-delta 算法相比 delta 算法进一步获得了更高的压缩率。在实际应用场景中,海量时序数据的时间戳都是密集且连续的,绝大部分都满足 delta-of-delta=0 的条件,这样可以大幅度降低时间戳的存储空间。

Zig-Zag
在一些情况下,我们使用到的整数,往往是比较小的。比如,我们会记录一个用户的 id、一本书的 id、一个回复的数量等等。在绝大多数系统里面,他们都是一个小整数,就像 1234、1024、100 等。而我们在系统之间进行通讯的时候,往往又需要以整型(int)或长整型(int64)为基本的传输类型,为了传输一个整型(int)1,我们需要传输 00000000_00000000_00000000_00000001 32 个 bits,除了一位是有价值的 1,其他全是基本无价值的 0。

对于正整数来讲,如果在传输的时候,我们把多余的 0 去掉(或者是尽可能去掉无意义的 0),传输有意义的 1 开始的数据,那我们就可以做到数据的压缩了,比如:00000000_00000000_00000000_00000001 这个数字,我们如果能只发送一位 1 或者一个字节 00000001,就将压缩很多额外的数据。

zigzag 给出了一个很巧的方法:补码的第一位是符号位,他阻碍了我们对于前导 0 的压缩,那么,我们就把这个符号位放到补码的最后,其他位整体前移一位:


但是即使这样,也是很难压缩的,因为数字绝对值越小,他所含的前导 1 越多。于是,这个算法就把负数的所有数据位按位求反,符号位保持不变,得到了这样的整数:


而对于非负整数,同样的将符号位移动到最后,其他位往前挪一位,数据保持不变。


正数、0、负数都有同样的表示方法了,我们得到了有前导 0 的另外一个整数。不过他还是一个 4 字节的整数,我们接下来就要考虑怎么样将他们表示成尽可能少的字节数,并且还能还原。

比如:我们将 1 转换成 (00000000_00000000_00000000_00000010)zigzag 这个以后,我们最好只需要发送 2bits(10),或者发送 8bits(00000010),把前面的 0 全部省掉。因为数据传输是以字节为单位,所以,我们最好保持 8bits 这样的单位。zigzag 引入了一个方法,就是用字节自己表示自己。举个例来讲:


先按照七位一组的方式将上面的数字划开:


1. 将它跟 (~0x7f) 做与操作的结果,高位还有信息,所以把低 7 位取出来,并在倒数第八位上补一个 1(0x80):11001111

2. 将这个数右移七位:(0000-0000000-0000000-0000000-0001111)zigzag

3. 再取出最后的七位,跟 (~0x7f) 做与操作,发现高位已经没有信息了(全是 0),那么就将最后 8 位完整的取出来:00001111,并且跳出循环,终止算法

4. 最终就得到了两个字节的数据 [11001111, 00001111]

解压过程:对于每一个字节,先看最高一位是否有1(0x80)。如果有,就说明不是最后一个数据字节包,那取这个字节的最后七位进行拼装。否则,说明就是已经到了最后一个字节了,那直接拼装后,跳出循环,算法结束。最终得到 4 字节的整数。

Simple-8B

Simple-8B 编码方式是 2010 年墨尔本大学一博士在论文中提出的,在 simple 8b 中,一组整数会被存在一系列固定大小的数据块中。每个数据块里,每个整数都用固定字长来表示,这个固定字长由数据块中最大的整数来表示。而每个数据块的第一位用来标记这个数据块字长。

使用这个技术可以让我们只需要在每个数据块中只记录一次字长,而不是去记录每个整数的字长。而且因为每个数据块的字长是一样的,我们也可能推算出来数据块里中存储了多少个整数。

Bit-Packing

这种算法是把文本用需要的最少的位来进行压缩编码。

比如八个十六进制数:1,2,3,4,5,6,7,8。转换为二进制为:00000001,00000010,00000011,00000100, 00000101,00000110,00000111,00001000。每个数只用到了低 4 位,而高 4 位没有用到(全为 0),因此对低 4 位进行压缩编码后得到:0001,0010,0011,0100,0101,0110,0111,1000。然后补充为字节得到:00010010, 00110100,01010110,01111000。所以原来的八个十六进制数缩短了一半,得到 4 个十六进制数:12,34,56,78。

对于 bool 类型,占用一个字节(8bit),但其实际有效的只有最后 1bit 的 0 或 1,因此,在对 bool 类型进行压缩时,使用 bit-packing 压缩率很高:8 个 bool 值,原先占用 8byte(64bit),使用 bit-packing 压缩后只需要 1byte(8bit),压缩率高达 12.5%。

XOR

XOR 编码方式是 Gorilla 内存数据库一篇论文中提出的,其主要针对时序数据(时间戳 + 测量值的键值对),对时间戳和测量值分别编码达到压缩效果。

针对时间戳采用前述 delta of delta 处理,针对测量值采用如下方法进行压缩:

1. 第一个测量值不压缩(64bit)。

2. 对于后续的测量值,如果当前值跟前一个值的 XOR 结果为 0,即值相等,仅存储一位‘0’。

3. 如果 XOR 结果不是 0,计算 XOR 中前导零和尾随零的个数,存储位’1’后接 a) 或 b):

a). 使用‘0’作为控制位,如果有意义位块落在前一个有意义位块中,即前导零和后导零的数量至少与前一个值相同,使用该信息作为块位置,只存储有意义的 XOR 值。

b). 使用'1'作为控制位,将前导零数的长度存储到下 5 位,然后将有意义的 xor 值的长度存储到下 6 位。最后存储 XOR 值的有意义的位。


(截图自 Gorilla: A Fast, Scalable, In-Memory Time Series Database)

在上述图例中,块头后是第一条数据的时间戳跟块头基准时间戳的 delta 值,以及第一条数据的测量值(64bit),接下来是压缩后的键值对序列,第二条数据时间戳的 d&d 值为 -2,位于‘10’标记的区间,则存储‘10’,后跟 7 位的‘-2’,第三条数据的时间戳 d&d 值为 0,直接存储一位‘0’。

第一个测量值存储的是原值 12(64bits),第二个测量值跟第一个测量值 XOR 结果为 0,存储的是一位‘0’,第三个测量值跟第二个测量值 XOR 结果 0x0010000000000000,转换为二进制有 11 个前导 0(0x001==> 000000000001),因此使用‘11’(2bits)作为控制位,后跟 5bit 存储前导零个数,接下来 6bit 存储有意义的 XOR 结果值 1(6bits),然后 1bit 存储有意义值的位数(只有一位有意义),合计 64+1+2+5+6+1=79bits,原值 64*3=192bits,综合考虑原值:64x2x3=384bits,压缩后:103+64(head)=167bits,压缩率 0.435。


根据国际知名网站DB-Engines数据,时序数据库在过去24个月内排名高居榜首,且远高于其他类型的数据库,可见业内对时序数据库的需求迫切。相应的时序数据库产品近年来也快速发展,各大互联网企业包括谷歌、阿里巴巴、亚马逊都推出自己的时序数据库,业界使用较多的时序数据库主要有如下几种:

1、InfluxDB

InfluxDB是一款用Go语言编写的开源分布式时序、事件和指标数据库,无需外部依赖。该数据库现在主要用于存储涉及大量的时间戳数据,如DevOps监控数据,APP metrics,loT传感器数据和实时分析数据。


作为目前开源排名最高的时序数据库,InfluxDB支持数据存储策略(RP)和数据归档(CQ),能够实时查询,数据在写入时被索引后就能够被立即查出,内置HTTP接口,安装管理很简单,并且读写数据非常高效。于2013年被首次发布的InfluxDB,是TSDB领域的领导者。与许多开源(OSS)数据库类似,InfluxDB不但能够为单个节点提供MIT许可,而且提供了InfluxDB Cloud付费计划,以及为企业级用户提供了集群、以及生产环境就绪(production-ready)等功能。在2019年发布InfluxDB 2.x之前,InfluxDB平台是由TICK技术栈所组成,即:Telegraf(收集和报告参数指标的代理)、InfluxDB、Chronograf(从InfluxDB处查询数据的接口)、以及Kapacitor(实时数据流的处理引擎)。InfluxDB 1.x主要通过社区和集成,收集、存储和查看来自服务器和Web应用的时序数据指标。2.x从本质上简化了整体架构。它将TICK栈捆绑到了单个二进制文件中,并且引入了一些新的功能,来执行收集(如:原生的Prometheus插件)、组织(如:各种组织和存储桶)、可视化(如:数据浏览器)数据、及其Flux语言。

总的来说,在面向基础设施和应用监控的需求时,InfluxDB能够与各种数据源无缝地集成。如果时序数据能够与标签集模型非常吻合的话,那么InfluxDB是一个不错的选择。可见,InfluxDB的优缺点可以被归结为:
优点:无模式摄取、庞大的社区、与流行工具相集成。
缺点:具有高基数、自定义查询/处理语言的数据集。

2、Kdb+

kdb+/q被官方称为世界上最快的时间序列数据库,它使用统一的数据库处理实时数据和历史数据,同时具备CEP(复杂事件处理)引擎、内存数据库、磁盘数据库等功能。列式存储的特性,使得对于某个列的统计分析操作异常方便。

与一般数据库或大数据平台相比,kdb+/q具有更快的速度和更低的总拥有成本,非常适合海量数据处理,主要被用于海量数据分析、高频交易、人工智能、物联网等领域。在延迟性上有着苛刻要求的金融领域,kdb+有着独特的优势。

3、Prometheus

Prometheus是一套开源的系统监控报警框架,由工作在SoundCloud的Google前员工在2012年创建,作为社区开源项目进行开发,2015年正式发布,并在次年正式加入Cloud Native Computing Foundation。

作为新一代的监控框架,Prometheus具备强大的多维度数据模型,有多种可视化图形界面,使用pull模式采集时间序列数据,可以采用push gateway的方式把时间序列数据推送至Prometheus server端。

4、 Graphite

Graphite是一个开源实时的、显示时间序列度量数据的图形系统。Graphite并不收集度量数据本身,而是像一个数据库,通过其后端接收度量数据,然后以实时方式查询、转换、组合这些度量数据。

Graphite支持内建的Web界面,它允许用户浏览度量数据和图。它由多个后端和前端组件组成。后端组件用于存储数值型的时间序列数据,前端组件则用于获取指标项数据并根据情况渲染图表。

5、TimescaleDB

TimescaleDB是唯一支持完整SQL的开放源代码时间序列数据库,已针对支持全面SQL的快速提取和复杂查询进行了优化。它基于PostgreSQL,并且为时间序列数据提供了最好的NoSQL和Relational世界。

TimescaleDB使开发人员和组织能够更多地利用其功能:分析过去,了解现在和预测未来。在查询层面统一时序数据和关系数据可消除数据孤岛,并使演示和原型更容易实现。可扩展性和完整的SQL接口的结合赋予员工提出数据问题。与PostgreSQL的兼容性是TimescaleDB的最大卖点。TimescaleDB能够完全支持所有的SQL功能(如:连接、二级和部分索引),以及诸如PostGIS之类流行的扩展。作为PostgreSQL的扩展,TimescaleDB不但提供诸如Azure Database for PostgreSQL与Aiven之类的云托管选项,也提供了针对虚拟机或容器的各种自管理选项。其最初是针对物联网平台,使用InfluxDB来存储它们的传感器数据。由于网络不稳定性,导致了物联网时序数据经常会出现拥堵和失序,因此TimescaleDB在高基数方面具有如下三个特点:
1).超级表(Hypertables):TimescaleDB基于时间列、以及其他“空间”值(如:设备的UID、位置标识符、或股票代号),来将其超级表划分成块。用户可以通过配置这些块,将最新的数据保存到内存中,并按照时间列,将数据异步压缩和重新排序至磁盘(并非摄取时间),以及在节点之间,以事务的方式进行复制和迁移。
2).持续聚合(Continuous 2)Aggregation):通常,物联网数据在汇总时更为实用,因此我们无需在每个汇总查询中去扫描大量的数据。由于支持数据的持续聚合,TimescaleDB能够快速地计算出诸如:小时平均值、最小值和最大值等关键指标(如,计算出下午3点到4点之间的平均温度,或是下午3点时刻的确切温度)。这将有助于创建高性能的仪表板与分析结果。
3).数据保留(Data Retention):在传统关系型数据库中,大量的删除操作往往代价高昂。然而,由于TimescaleDB是以块的形式存储数据的,因此它提供了一种drop_chunks的功能,可以在同等开销下,快速地删除旧的数据。由于旧数据的相关性会随着时间的推移而降低,因此TimescaleDB可以通过与长期存储(如,OLAP或Blob存储)一起使用,来移走旧的数据,节省磁盘空间,进而为新的数据上提供优异的性能。

总体而言,TimescaleDB非常适合那些寻求显著性能提升,而不想通过大量重构来迁移现有SQL数据库的团队。尽管TimescaleDB相对较新(于2017年首次被发布),但是许多物联网初创公司已在使用它作为中间数据存储,以快速提取横跨数月的聚合参数指标,并将旧的数据移至长期存储处。如果已经在Kubernetes集群上运行着 PostgreSQL,那么安装TimescaleDB和迁移数据的任务都会相对比较容易。总的来说,TimescaleDB的优缺点可以被归结为:
优点:与PostgreSQL兼容性,可以很好地扩展数据基数,并提供各种部署模型。
缺点:结构模式固定,而且在摄取之前增加了复杂性和数据的转换工作。

6、QuestDB

对于那些既希望利用InfluxDB内联协议的灵活性,又熟悉PostgreSQL的人来说,QuestDB(YC S20)作为一个较新的时序数据库,可以满足开发者的这两个要求。它是一个用Java和C++编写的开源TSDB。从原理上说,QuestDB是利用内存映射文件,在数据提交到磁盘之前,实现快速读写的。


QuestDB通过使用Java和C++,来从头开始​​构建数据库,其主要特征体现在:

性能:解决摄取过程中,特别是在处置高基数的数据集过程中的瓶颈。同时,它还通过顺次存储的时分数据(即,在内存中的混洗),以及仅分析请求的列/分区,而并非以整张表的方式,来支持快速的数据检索。此外,QuestDB还会运用SIMD指令,实现并行化操作。
兼容性:QuestDB支持InfluxDB的内联(inline)协议、PostgreSQL wire、REST API、以及CSV上传的方式,来摄取数据。那些习惯了其他TSDB的用户,可以轻松地移植他们的现有应用程序,而无需进行大量的重写工作。
通过SQL进行查询:虽然能够支持多种摄取机制,但是QuestDB也会使用SQL作为查询语言,因此用户无需额外地学习Flux之类的特定域语言。

对于具有高基数(超过1000万)的数据集,QuestDB的性能优于其他TSDB。凭借着Intel Xeon CPU,其峰值的摄取吞吐量为904k行/秒,并能够在1000万台设备上使用四个线程,且在m5.8xlarge实例上维持约640k行/秒的性能。而当QuestDB在AMD Ryzen 3970X上运行相同的基准测试时,它具有超过1百万行/秒的摄取吞吐量。

它的另一个有趣的特性是,在摄取中支持InfluxDB内联协议和PostgreSQL的wire。对于现有的InfluxDB用户可以将Telegraf配置为指向QuestDB的地址和端口。同理,PostgreSQL用户使用现有的客户端库、或JDBC,将数据写入QuestDB。当然,无论采用何种摄取方法,都可以使用标准的SQL去查询数据。值得注意的是,其API参考页面上,显著地列出了一些例外的情况。

作为该领域的新玩家,QuestDB最明显的缺点是,缺乏生产环境就绪的功能(如,复制、备份与恢复等)。同时,它虽然能与诸如:PostgreSQL、Grafana、Kafka、Telegraf、以及Tableau等流行工具相集成,但是需要花时间调试与磨合,方可达到上述其他TSDB的水平。总的说来,QuestDB的优缺点可以被归结为:
优点:快速摄取(特别是对于具有高基数的数据集),支持InfluxDB内联协议和PostgreSQL wire,可以通过标准的SQL查询数据。
缺点:在用户社区、可用集成、以及对生产环境就绪等方面,都有待改进。


关于RRD

RRD (Round Robin Database)数据库是一个环形的数据库,数据库由一个固定大小的数据文件来存放数据,此数据库不会像传统数据库一样为随着数据的增多而文件的大小也在增加,RRD在创建好后其文件大小就固定,可以把它想像成一个圆,圆的众多直径把圆划分成一个个扇形,每个扇形就是可以存数据的槽位,每个槽位上被打上了一个时间戳,在圆心上有一个指针,随着时间的流逝,取回数据后,指针会负责把数据填充在相应的槽位上,当指针转了360度后,最开始的数据就会被覆盖,就这样RRD循环填充着数据。

源数据搜集:采用一些数据搜集工具,如脚本、shell命令、SNMP等工具在一定时间间隔里把数据搜集填充到rrd数据库中,这些需要数据搜集的对象叫DS,一个DS里在一个时间里可以搜集的数据可以有多个,比如一个时间点上对网卡来说有进来的流量,也有流出的流量,所以这是2个数据成为一组数据。
临时存储:源数据获取到后是存放在一个数据库的一个临时区域,这些源数据叫做PDP
分组-聚合:RRDTool把这些PDP数据作为数据源通过分组、再利用聚合函数计算后把计算后的结果放在RRD数据库的时间槽(time slot)上,这些数据叫做CDP,CDP才是RRDTool绘图时真正打交道的数据。

在从源数据中取数据做聚合计算时会有一个挑选数据的基准,也就是说是以几个源数据为一组做聚合,根据现实需求的不同,对源数据可以很灵活的选择不同的时间段提取源数据,再聚合提取不同的聚合值,这样就产生不同组别的CDP数据,这些有以相同时间段挑选源数据及相同聚合函数计算的结果组成的数据就叫RRA,所以根据挑选源数据的标准及采用的聚合函数的不同,RRA可以有多组。

DS:Data Source 数据源,用于定义搜集数据的工具所搜集数据的一些特性
Time Solt:时间槽,用于存放通过聚合后的数据区域
PDP:Primary Data Point 主数据节点,每个时间点产生的数据,即是搜集的源数据,没有做聚合的数据
CDP(Consolidation Data Point 聚合数据节点):通过对获取的源数据分组、聚合计算后得到的数据叫CDP,
RRA(Round Robin Archive 轮转归档):以相同的分组、聚合函数计算后的CDP数据组就组成了RRA
Resolution(解析度):这是一个时间跨度,表示在做聚合计算时是以几个连续的time slot里的数据做聚合,在默认时rrd是以300秒的间隔产生一个time slot。
CF:Consolidation Function,合并函数或聚合函数,以RRDTool中有AVERAGE、MAX、MIN、LAST4种

参考来源:
Time series database