2017年,时序数据库突然火了起来。第一年2月,Facebook开源了beringei时序数据库;4月,基于PostgreSQL的时序数据库TimeScaleDB也开源了。租户的分布式时序数据库产品TSDB已成为支撑其在制造、交通、能源、智慧城市等工业领域发展的核心产品,也成为百度工业物联网战略发展的标志性事件。时序数据库是物联网方向非常重要的服务。业界频频发声,表明各家企业已经迫不及待地拥抱物联网时代的到来。本文将从时序数据库的基本概念、使用场景和解决方案入手。最后,将从深入分析如何解决时序数据存储的技术难题入手。一、背景百度无人车在运行过程中需要监测各种状态,包括坐标、速度、方向、温度、湿度等,并且需要记录每时每刻的监测数据,以进行大数据分析。每辆车每天收集近8T的数据。如果只存不查询还好(虽然已经是很大的成本了),但是如果需要快速查询“2点后昌村路上时速超过60km/h的无人车有哪些”今天下午?”对于纬度分组和聚合查询,时序数据库会是一个不错的选择。2.什么是时序数据库?先介绍一下什么是时序数据。时间序列数据是基于时间的一系列数据。将这些数据点在时间坐标上连成一条线,可以做一个多纬度的过去报告,揭示其趋势、规律和异常;未来可以做大数据分析、机器学习,实现预测预警。时序数据库是存储时序数据的数据库,需要支持时序数据的快速写入、持久化、多维聚合查询等基本功能。与传统数据库只记录数据的当前值相比,时序数据库记录了所有的历史数据。同时,时序数据的查询总会带上时间作为过滤条件。时序数据示例p1-2015年北京、上海、广州气温变化p2-北京、上海、广州当前气温实时显示下面介绍时序数据库的一些基本概念(不同的时序数据库有略有不同的名称)。metric:指标,相当于关系数据库中的一张表。datapoint:数据点,相当于关系数据库中的row。timestamp:时间戳,代表数据点产生的时间。field:度量下的不同字段。例如,位置测量有两个字段:经度和纬度。一般来说,它存储随着时间戳变化而变化的数据。tag:标记,或附加信息。一般存储不随时间戳变化的属性信息。timestamp加上所有的tag可以认为是表的主键。如下图,measurement是Wind,每个数据点都有一个timestamp,两个字段:direction和speed,两个tags:sensor和city。它的第一行和第三行存储传感器编号为95D8-7913的设备,属性城市为上海。随着时间的推移,风向和风速都发生了变化,风向从23.4级变为23.2级;风速从3.4级变为3.3级。p3-时序数据库基本概念图3.时序数据库场景所有时序数据的产生都需要展示其历史趋势、周期性、异常性,并进一步对未来进行预测分析,这些都适用时间序列数据库的场景。在工业物联网环境监控方向,百度天工的客户就遇到了这样的问题。由于行业要求,需要存储工况数据。客户每个厂区有20000个监控点,采集周期500毫秒,共20个厂区。这相当于每年惊人的26万亿个数据点。假设每个点为50Byte,则数据总量将达到1P(如果每台服务器有10T的硬盘,那么一共需要100多台服务器)。这些数据不仅需要实时生成并写入存储;还支持快速查询,可视化展示,帮助管理者分析决策;并可用于大数据分析,发现深层次问题,帮助企业节能减排,增加效益。最终,客户采用了百度天工的时序数据库解决方案,帮助其解决了问题。在互联网场景中,也会产生大量的时序数据。百度有大量内部服务使用天宫物联网平台的时序数据库。例如,为了保证用户体验,百度内部服务会将每一个用户的网络卡顿和网络延迟记录到百度天宫的时间序列数据库中。技术产品分析时序数据库直接生成报表,尽早发现问题,尽早解决问题,保障用户体验。4.时序数据库遇到的挑战很多人可能认为在传统的关系型数据库中加入时间戳列就可以作为时序数据库。数据量小的时候确实没有问题,但是数据量小就表现出纬度有限,细节少,置信度低,不能用于大数据分析。显然,时序数据库就是为解决海量数据场景而设计的。可以看出,时序数据库需要解决以下几个问题l时序数据的写入:如何支持每秒千万级数据点的写入。l时序数据读取:如何支持秒级亿级数据的分组聚合操作。l成本敏感:海量数据存储带来成本问题。如何以更低的成本存储这些数据,将成为时序数据库的重中之重。这些问题不是一篇文章可以涵盖的,每个问题都可以从多个角度进行优化和解决。这里我们只尝试从数据存储的角度来回答如何解决大量数据的写入和读取。5.数据存储数据存储分为单机存储和分布式存储两个问题。如果单机存储只是存储,可以直接写成日志。但是因为后续要快速查询,需要考虑存储结构。传统的数据库存储使用B树,因为它的组织形式有助于减少查询和顺序插入期间的查找次数。我们知道磁盘寻道时间很慢,一般在10ms左右。磁盘的随机读写在寻道上很慢。对于B树的随机写入,会花费大量的时间在寻盘上,导致速度非常慢。我们知道固态硬盘的寻道时间更快,但是并不能从根本上解决问题。对于写了90%以上场景的时序数据库,B-tree显然不适合。业界主流是用LSM树代替B树,比如Hbase、Cassandra等nosql。下面我们详细介绍一下。LSM树包括两部分:内存中的数据结构和磁盘中的文件。对应Hbase中的MemStore和HLog;对应Cassandra中的MemTable和sstable。LSM树的运行过程如下:1.写入和更新数据时,首先写入内存中的数据结构。为了避免数据丢失,也会先写入WAL文件。2.内存中的数据结构会每隔一定时间或达到固定大小时刷新到磁盘。这些磁盘上的文件不会被修改。3、随着磁盘上积累的文件越来越多,会定期进行合并操作,以消除冗余数据,减少文件数量。p4-HbaseLSMtree结构介绍(注1)可见LSMtree的核心思想是通过内存写入和后续的磁盘顺序写入来获得更高的写入性能,避免随机写入。但同时也牺牲了读性能,因为同一个key的值可能存在于多个HFile中。为了获得更好的读取性能,可以通过bloomfilter和compaction来获得,这里限于篇幅不再详细展开。分布式存储时序数据库面向海量数据的写入、存储和读取,单机无法解决问题。因此需要采用多机存储,即分布式存储。分布式存储首先要考虑的是如何将数据分布到多台机器上,也就是分片的问题。接下来介绍时序数据库分片问题。分片问题包括分片方法的选择和分片的设计。分片方式时序数据库的分片方式与其他分布式系统相同。Hashsharding:这种方式实现简单,平衡性较好,但集群不易扩展。Consistenthashing:该方案平衡性好,易于扩展集群,但实现复杂。代表包括亚马逊的DynamoDB和开源的Cassandra。范围划分:通常与全局排序结合使用,复杂点在于合并和拆分。代表Hbase。碎片化设计碎片化设计就是如何处理碎片化。这是非常有技巧性的,会直接影响写作和阅读的表现。结合时序数据库的特点,按照metric+tags分片是一种比较好的方式,因为往往是按照一个时间范围进行查询,这样相同metric和tags的数据会分配到一台机器上进行连续存储,顺序磁盘读取获取很快。结合上面提到的单机存储内容,可以实现快速查询。此外,我们考虑时间序列数据具有较长时间范围的情况。需要根据时间范围划分成若干段存储在不同的机器上,这样大规模的时间序列数据才能支持并发查询,优化查询速度。如下图,第一行和第三行的tag相同(sensor=95D8-7913;city=Shanghai),所以分配到同一个shard。虽然第五行也有相同的标签,但可以根据时间范围进行更改。段被分成不同的分片。第二、四、六行属于同一个标签(sensor=F3CC-20F3;city=Beijing),同理。p5-时序数据分片说明6.真实案例下面我将使用一批开源的时序数据库来说明。InfluxDB:一个非常优秀的时序数据库,但是只有单机版是免费开源的,集群版是收费的。从单机版可以窥见它的存储方案:在单机上InfluxDB采用了类似LSM树TSM的存储结构;而分片方案InfluxDB首先通过+确定ShardGroup(其实也是加了retentionPolicy),再通过+确定hashcode到具体的shard。这里的timestamp默认是7天对齐的,也就是说7天的时序数据会在一个shard里。p6-InfluxdbTSM结构图(注2)Kairosdb:底层采用Cassandra作为分布式存储引擎。上面说了LSM树是在单机上使用的。Cassandra有两级索引:partitionkey和clusteringkey。分区键是它的分片ID,使用一致性哈希;而集群键保证在分区键中排序。Kairosdb利用Cassandra的特性,使用++<数据类型>+作为分区键,数据点在时间戳上的时间偏移量作为聚簇键。它的顺序便于按时间范围查询。partitionkey中的timestamp是3周对齐的,也就是说21天的时序数据会在一个clusteringkey下。3周的毫秒数为18亿,刚好低于Cassandra的每行和每列20亿的限制。OpenTsdb:底层使用Hbase作为其分布式存储引擎,也使用LSM树。Hbase采用范围划分的sharding方式。使用行键进行分片以确保其全局顺序。每个行键下可以有多个列族。每个列族下可以有多个列。上图展示了OpenTsdb的行键组织。与其他时序数据库不同的是,由于Hbase的rowkey是全局有序的,所以增加了一个可选的salt来实现更好的数据分布,避免热点。然后列限定符由带有时间戳的偏移量和数据类型组成。它的时间戳是小时对齐的,也就是说一个行键最多可以存储一个小时的数据。另外需要将构成rowkey的metrics和tags转换成对应的uid,以减少存储空间,防止Hfile索引过大。下图是一个真实的行键示例。p7-opentsdb的rowkey示例(注3)七、结论可以看到,各个分布式时序数据库的存储方案虽然略有不同,但基本相同。一方面采用更适合高吞吐量写入的单机存储结构,在分布式方案上根据时序数据的特点精心设计。目标是设计一种便于时序数据写入和读取的分片方案,同时使分布更加均匀,尽可能避免热点的产生。数据存储是时序数据库设计中非常小的一部分,但也可以看出时序数据库在设计之初就必须考虑时序数据的特点。稍后我们会从其他角度进行讨论。
