就像咱们在前一章提到的,一个时间序列是一系列数值,每一个数值都伴随着一个时间值,表明数据被记录时的时间。时间序列数据存入后就不多再须要修改了,查询时常常是查询一个连续时间段的数据,也可能查询汇总或者聚合后的数据。时间序列数据库是一种储存多个时间序列的方式,在其中检索一个或几个时间序列的某一个特定时间段的数据是特别高效的。一样地,主要用来查询一个时间段数据的应用程序也适合使用时间序列数据库来实现。像以前所解释的,本书的主题是存储和处理大规模时间序列数据,为了实现这个目标,首选技术是非关系型NoSQL数据库,好比Apache HBase或MapR-DB。数据库
为大规模时间序列数据库的实际实现提供务实的建议,是本书的目标,因此咱们须要聚焦于一些能够简化和加强真实世界中应用程序发展进程的一些基本步骤。咱们会简单看看适用于中小型数据集的方法,而后深刻探究咱们主要关注的问题:如何实现大规模TSDB。缓存
为了获得一个扎实的实现,有几种可供选择的设计方法。如何选择取决于数据的属性。有多少种不一样的时间序列?得到的数据是什么类型的?使用怎样的速度采集数据?须要存储多久的数据?这些问题的答案有助于咱们肯定最优的实现策略。微信
这一章中的主要思想路线数据结构
尽管咱们已经提处处理时间序列数据的一些主要方面,这一章会比以前更深刻地探讨存储和访问时间序列数据的基本方法。第四章会提供如何使用现有开源软件来最好地实现这些概念的建议。这两章有比较多的内容须要理解。而后你就能够记住若是将这些关键的想法集中到一块儿而不是迷失在细节中,这里是一个本章内容的一个简单路线图:架构
平面文件运维
真正的数据库:关系型数据库机器学习
真正的数据库:非关系型NoSQL数据库数据库设计
基本设计ide
可选设计工具
咱们已经回顾了主要思想,如今咱们更详细地重温一下而且解释它们的重要性。
你能够扩展很是简单的设计(好比简单的二维表),使用更聪明的文件格式来使其更先进,好比列存储的Parquet格式。Parquet是一个有效而且简单的现代化格式,能够存储时间和一些可选值。图3-1展现了两种记录时间序列数据的Parquet schema。左图中的schema适合你已经知道怎么合理使用时间序列数据的状况,它是一个特定场景的存储方案。例子中,只存了明确指定的4个时间序列的数据(一个存放时间的t和一个存放数据的tempIn组合起来,为一个时间序列。t和它对应的tempIn、pressureIn、tempOut、pressureOut即4个时间序列),若是须要增长新的,就须要修改schema。右图中的Parguet schema抽象程度更高,对你想要往文件里嵌入更多元数据的场景更适合。而且这种格式没有事先对时间序列的数量作任何限制。若是你想要构建一个给其余人使用的时间序列库,右边的格式会更合适一些。
图3-1。使用Parquet格式来存储时间序列数据的两种可能的schema。左边的schema使用固定的类型名称将问题域肯定了。在不改变schema的状况下,只能够存储4个时间序列。相反地,右边的schema更加灵活,你能够增长新的时间序列。另外它的抽象层次也更高,把几个单一的时间序列(一对time、value)按照tags分组,而后放到一个单独的block中。
这样的一种时间序列数据(特别是使用相似Parquet格式的状况)是很是有用的,但前提是你须要分析的时间序列数量相对较小,而且所感兴趣的时间范围相对于单个文件所存储数据的时间跨度很大(好比每一个文件存放一个月的数据,你查的时候也应该每次查一个月的数据,而不是每次查一天的)。
系统最初使用平面文件来实现是一种很是广泛的状况,并且不久以后这种简单的实现再也不适应快速增加的数据的状况也是很广泛的。基本问题是单一文件中的时间序列数量增长了,任何特定的查询中,真正有用的数据占所读取数据的比例就降低了,由于多数读取到的数据实际上是属于其余时间序列的。
一样地,在文件中的时间跨度比平均查询的时间范围已经长不少的状况,真正有用的数据占所被读取数据的比例又降低了,由于文件中的大部分数据已经在你感兴趣的时间范围以外了(好比数据记录了1个月的数据,而查询时通常只查某一天的,那为了定位到这一天,须要先读大量前边的实际不须要的数据)。努力解决这些问题的同时通常又会引入其余的问题。使用大量的文件来确保每一个文件中只有较少的时间序列,会使文件数量大幅增加。一样地,减小每一个文件所存储数据的时间范围会使得文件数量翻倍增加。当在一个相似Apache Hadoop中HDFS的文件系统存储数据时,大量的文件会致使严重的稳定性问题。基于Hadoop的上层系统,如MapR能够轻松处理大量的文件,但检索和管理大量的小文件也是很低效的,由于须要增长不少搜索时间。
为了不这些问题,很天然的一步是转而使用某些形式的真正的数据库来存储这些数据。选择合适的数据库的方法并非显而易见的,但基于数据库的类型和它的设计方案,你有几个选项。咱们会研究这些问题来帮助你做选择。
即便是通过良好分区的平面文件,在处理大规模时间序列数据时也会力不从心,因此你也行会考虑使用某些类型的真正的数据库。当第一次在数据库中存储时间序列数据时,使用所谓的星型模式(star schema)设计,而且将数据存放到RDBMS是个很诱人的选择。在这样一种数据库设计中,核心数据存放在事实表(fact table),就像图3-2展现的那样。
图3-2。将时间序列数据存放到RDBMS的一个事实表的设计。其中存放了时间(TIme列)、序列ID(Time series ID列)和数值(Value列)三列。序列的细节存放在维表(dimension table)中(这一对Time、Value是一个时间序列,但这个时间序列的细节,好比Value的含义是什么,存放在另外一张表中,可使用Time series ID去那个表查)。
在星型模式中,一个表存储主要的数据,而且会引用其余表(维表)。该设计一个核心假定是维表要相对小巧,并且不常变更。图3-2中的时间序列事实表里,惟一被引用的维表,就是存放这个时间序列详细信息的维表,它的内容是表中数据(Value列)的含义。好比,若是咱们的时间序列数据是从一个工厂的泵或者其余设备从采集的,咱们会但愿在获取这个泵的多个维度的数据,如入口和出口的压强和温度、泵在不一样频段的震动和泵自身的温度等。这其中的每一个泵的每个维度,都是一个单独的时间序列,每一个时间序列会有相似泵的序列号、位置、商标、型号等信息,这些信息都存放在维表中。
实际上一些应用程序已经使用像这样的星型模式来存放时间序列数据了。咱们在多数NoSQL数据库中也可使用这样的设计。星型模式解决了有大量不一样时间序列的问题,在数据点的规模达到数亿甚至数十亿的状况下也能够工做得很好。然而就像咱们在第一章中看到的,即便是19世纪的航运数据也会产生上十亿的数据点。在2014年,纳斯达克证券交易所在过去三个月就会处理十亿规模的交易量。记录一个中型计算机集群的运行环境的话,一天会产生五亿的数据点。
而且简单地将这些数据存储起来是一回事,对其检索和处理就是另外一回事了。现代的应用程序如机器学习系统甚至状态显示系统都须要每秒检索和处理上百万的数据点。
虽然RDBMS能够扩展到这些大小、速度需求的下限,但带来的消耗和引入的复杂性会急剧上升。随着数据规模的继续增加,基于RDBMS的应用程序愈来愈不适合处理这样规模的时间序列数据了。使用星型模式但转而使用NoSQL数据库的话,也没有特别的帮助,由于这个问题的核心是星型模式带来的,而不仅是数据量。
星型模式所触及的核心问题是每次测量都要使用一行。一个增长时间序列数据库中数据检索速度的技术是在每一行存储不少数值。在一些像Apache HBase或者MapR-DB的NoSQL数据库中,列的数量几乎是不受限制的,只要任何特定一行中有数据的列的数量在几十万以内。这种能力能够被用来在每行存放多个数值。这样作的话,数据点就能够被更高速地检索,由于扫描数据的最大速度部分取决于须要扫描的行的数量,部分取决于待检索数据点的总数,部分取决于待检索数据的总量。减小行的数量,就大幅减小了一部分检索开销,检索速度就提高了。图3-3展现了使用宽表来减小时间序列数据行数量的一种方式。这个技术和OpenTSDB(一个开源的数据库,咱们会在第四章详细讲到)之中使用的默认表结构很类似。须要注意这样的表设计,和那些须要提早定义详细schema的系统的表设计是很不同的。有一件事情,若是你想把schema写下来,那将异常庞大。
图3-3,在NoSQL时间序列数据库中一个宽表的使用。关键的结构是直观的,在真正的应用程序中,使用的会是一个二进制的格式,但这样顺序的属性是同样的。
由于HBase和MapR-DB都是按照主键的顺序来存储数据,图3-3中的键设计会致使每行包含一小段时间的数据在磁盘上是连续存储的(由于Row key是按时间顺序增加,HBase和MapR-DB是按列族存放数据的,Data values中的数据就会所有按照时间顺序存放在磁盘上)。这个设计意味着检索一个特定时间段的数据,涉及的主要是顺序磁盘操做,就会比数据按行分散开的状况快不少。为了从这个表结构得到性能优点,每一个时间窗口的采样点要足够富裕,这样就能够减小行的数量,从而提高检索速度。典型状况,时间窗口会被调整成每一行包括100-1000采样点的样子。
图3-3中的表设计能够继续改进,经过将一行中的全部数据压缩成一个单一的被称做blob的数据结构。Blob能够高度压缩,因此须要从磁盘读取的数据量就更少了。而且,若是使用HBase来存储时间序列数据,每行只有一列的状况会减小了每列数据在HBase所使用的磁盘文件格式上的开销,这样又进一步提升了性能。图3-4的混合式表结构中,一些行的数据已经被压缩,另外一些行没有。
图3-4。在混合模式设计中,行中的数据能够被存储成一个单一的数据结构(blob)。注意实际压缩的数据更多是二进制的格式。这里使用JSON格式显示是为了更容易理解。
图3-3中的宽表格式能够进化成图3-4的压缩格式(blob样式),只要确保那些被压缩的行对应的时间窗口不会或者不多再有新增的数据。通常地,一旦时间窗口结束后,新的数据就不属于这个时间窗口了,而后对这个时间窗口中数据的压缩就能够开始了。由于在同一行中,已压缩和未压缩的数据能够共存,若是在对行压缩以后,又有新数据过来了,能够再简单地从新压缩这一行,将新数据合并进来。
图3-5展现的是概念上的混合式时间序列数据库的数据流。
在后台将数据从旧格式转换成blob格式,会让renderer(图3-5中所显示的)检索数据并绘制出来的速度有质的提高。例如,在4个节点的MapR集群中,数据以压缩格式存放的话,3千万的数据点能够在大概20秒内被检索、聚合、绘制出来。
图3-5。混合式时间序列数据库的数据流。数据从数据源到达catcher,而后被插入到NoSQL数据库中。以后blob maker在后台定时将数据压缩成blob格式。数据由renderer检索和格式化。
压缩旧数据依然存在一个性能瓶颈。由于数据以未压缩的格式插入进来,每一个数据点到来后都须要对行作一个更新来将数值插入到数据库中。对行的更新操做会限制数据的插入速度到每一个集群中的每一个节点上只有每秒2万个数据点。
另外一方面,图3-6中的blob直写方式的数据流容许插入速度增长了大概1千倍。为何blob直写方式会带来如此大的性能提高?基本的区别是blob maker被转移到catcher和NoSQL时间序列数据库之间了。使用这种方式,blob maker就能够从内存的数据缓存中直接读取输入的数据,而不是从存储层的宽表中提取以前已经被写入进去的数据。
基本的思想是数据到达后先被存放在内存中。这些数据同时也被写入到日志文件中。这些日志文件就是图3-6中的restart logs,它们是在Hadoop系统存放的平面文件,不是存储层的一部分。Restart logs容许内存中的数据缓存被从新导入,在数据管道必须被重建的时候。
在正常操做中,在时间窗口的末尾,新的内存中数据结构会被建立,如今旧的内存中数据结构就能够用来建立压缩的blob而后写入数据库了。一旦blob被写入了,日志文件就被删除了。这样就无需像以前的混合设计中将数据两次写入。在图3-5中的混合设计中,所有的输入数据流都会逐点写入到存储层,而后再被blob maker读取。读的状况和写大体同样。一旦数据被压缩成了blob,它又被写入到数据库中。相反地,在图3-6的blob直写设计的数据流中,完整的数据流只写入到内存中(这样速度很快),而不是写入到数据库中。数据在压缩成blob以前不会被写入到数据库,因此写入速度大幅提高。数据库操做的次数从以前数据点的数量变成了blob的数量,很容易将次数减小到以前几千分之一这样的量级。
图3-6。Blob直写方式的数据流。Catcher在内存中暂存数据,而且将其写入到restart logs中。Blob maker周期地从缓存中读取数据,而后将压缩成的blob写入到数据库中。这个设计的性能提高来自于renderer能够同时从内存和数据库中获取数据。
blob直写方式的优点是什么?一个真实世界的例子展现了它能够作什么。使用了这个架构,仅使用了一个10节点的MapR集群中的4个节点,就能够实现每秒往MapR-DB的表中插入超过一亿的数据点。这些节点都有着很高的性能,其中每一个节点有15个CPU核、大量内存和12块高配置磁盘,但你使用多数硬件均可以达到这个性能级别的1/5到1/2。
这个性能级别听起来是用来处理海量数据的,可能超出了咱们所须要的处理能力,可是在第五章咱们会展现为何这样的性能是很是有用的,即便是对那些相对温和的应用程序。
在这一点,询问为何一个关系型数据库不能处理和使用混合模式的MapR-DB或者HBase所能承受的插入和分析数据的负载是公平的。当只有blob数据被插入而不使用宽表的状况,这个问题特别有趣,由于现代关系型数据库一般支持blob或者array类型。
这个问题的答案是,关系型数据库主要解决的问题不是提升插入和检索数据的速度,它如今这样运行是有其合理性的。使用关系型数据库的主要缘由也不是由于它有更好的性能。若是使用关系系型数据库的blob格式存储数据,就意味着须要放弃大多数其余好处。此外,SQL没有提供一个好的抽象方法,来隐藏访问blob格式数据中的细节。SQL不能用任何合理的方式来访问这些数据,而且像多行事务等特性也彻底派不上用场了。事务在这里还会成为问题,由于即便不使用,它也会成为一种消耗。一个关系型数据库须要知足多行事务的需求,这使它更难被扩展到多个节点上。尽管使用如Oracle的高成本数据库能够在单个节点实现很高的性能。而使用相似Apache Hbase或者MapR-DB的NoSQL数据库,你能够简单地经过加硬件的方式实现更高的性能。
为本身用不到的特性买单的模式在一些高性能系统中是存在的。为了可扩展而牺牲传统关系型数据库的一些固有特性也是常见的,但即便你这样作了,仍是得不到本身想要的扩展性。在这种状况,使用相似HBase或者MapR-DB的替代方案是有实质上的好处的,由于你同时获得了性能和可扩展性。
这些宽表、blob混合的表设计是很是诱人的。它们所许诺的巨大性能级别使人兴奋,并且它们能运行在有容错机制、基于Hadoop的系统(好比MapR),从运维的角度看也是很吸引人的。这些新方法都不是空想,它们已经被构建出来,而且被证实有着惊人的结果。然而咱们在这里呈现的,很大程度都是概念上的东西。有真正已经实现的吗?下一章咱们会讲到如何使用OpenTSDB(一个开源时间序列数据库工具)和几个开源的MapR扩展,来实现这些新的设计。结果是利用本章所描述的概念以达到高性能的时间序列数据库是现代使用场景所须要的。
付费解决 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等领域相关问题,灵活订价,欢迎咨询,微信 ly50247。