在论证了大规模运行Druid的挑战之后,我想提出我对下一代开源时间序列存储的看法,这应该不会出现Druid固有的问题。
“开源”是问题陈述的重要组成部分,因为提出的设计实质上是专有Google BigQuery的简化版本。我主要从Dremel论文和帖子“ BigQuery under the hood”中获取了有关BigQuery体系结构的信息,还从许多其他来源中获取了一些信息。
其他目标和自我约束:
非目标:
最后的介绍性说明:这篇文章基于在Metamarkets大规模运行Druid的经验和理论研究,但是所描述的设计尚未在生产中实施和测试。这篇文章中的某些陈述是错误的。如果您有任何意见或更正,请在此帖子下发表评论!
具有三个解耦子系统的时间序列存储的设计。浅蓝色线表示未压缩的面向行的数据流;深蓝线-压缩的柱状数据;红线-查询结果。
该系统由三部分组成,各部分之间有严格的职责分离:流处理系统,存储和计算树。
流处理系统摄取数据(接受“写入”),对其进行分区,将每个时间间隔内的数据转换为压缩的列格式并将其写入Storage。流处理系统的工作人员还负责计算最新数据的部分查询结果。
计算树具有多个级别的节点:最低级别的节点从Storage中下载特定分区和间隔的数据,并为其计算部分结果。如果查询间隔包括最新数据,则第二层中的节点合并特定分区的所有分区的结果,并接受最低层中的节点和Stream处理系统的工作程序的接受。第三级中的节点合并或合并第二级中节点的每个时间间隔结果,并包含每个时间间隔查询结果的缓存。这些节点还可能负责群集平衡和较低级别的计算树的自动缩放。
此设计的关键原则:
计算和存储的分离。这个想法来自BigQuery。在我有关Druid问题的文章中,我解释了Druid中缺少这种分隔如何使查询延迟不可预测,因为查询之间会相互干扰。
使计算树中的节点(几乎)是无状态的,这意味着它们是“一次性”的。它们可能是亚马逊的EC2或Google的可抢占实例,它们比普通实例便宜几倍。同样,计算树可以在数分钟之内放大和缩小,从而有可能e。G。在查询负载较低时,每晚和周末将其按比例缩小。
数据摄取(在流处理系统中)和存储分开。这个想法实际上已经在Druid中实现,它具有实时节点。这样的关注点分离可以使Storage保持非常简单,不需要分配资源来进行提取,列压缩,查询处理等。它只专注于从磁盘读取字节块并将其通过网络发送到计算中的节点和树。
流处理系统也可能比支持写操作的存储更动态。流处理系统可以根据数据摄取强度的变化而按比例放大或缩小,通常在晚上和周末较低。流处理系统可能具有在存储中难以实现的功能,例如动态重新分区。
如果查询的下载量没有使Storage的出站网络带宽饱和,则网络对总查询延迟的贡献是恒定的,并且与查询大小无关。如果将云对象存储用作存储(请参阅下面的“云对象存储”部分),或者相对于存储中的历史数据量,系统中的查询负载不成比例地较小,则可以授予此权限。
如果这两个条件都不适用,则可以使用Storage托管一些非时间序列的,下载频率较低的数据,以便人为地增加Storage群集的大小,从而增加其出站网络带宽。
否则,在存储和计算树之间的网络吞吐量可能将成为限制所提出设计中查询延迟的因素。有几种方法可以减轻这种情况:
部分分区可实现密钥分配不均。每个盒子都是一个分区。具有“其他值”的分区可能具有数千个“长尾”值。
在本文的后面,我将详细介绍系统的每个部分。
在本节中,我想讨论一些存储的可能实现。它们可以作为可互换的选项共存,就像在Druid中一样。
它是Amazon S3,Google云存储(GCS),Azure Blob存储以及其他云提供商的类似产品。
从概念上讲,这正是设计的时间序列存储中应使用的存储方式,因为GCS由名为Colossus的系统提供支持,并且它也是BigQuery的存储层。
云对象存储比我将在下面讨论的选项便宜得多,所需的管理工作少得多,并且吞吐量几乎不受限制,因此上面的整个“网络是瓶颈”一节在很大程度上是不相关的(理论上)。
云对象存储API不够完善,不足以在单个请求中支持多个字节范围的下载(用于多列的投影下推),因此每列的每次下载应是一个单独的请求。我怀疑这不是BigQuery的工作方式,它与Colossus的集成更紧密,可以实现适当的多列投影下推。
在我看来,“云对象存储”选项的主要缺点可能是其p99延迟和吞吐量。一些基准测试表明,GCS和S3在100 ms的延迟中具有p99延迟(这是可以接受的),并且吞吐量仅受下载端VM功能的限制,但是如果在并发100个负载的情况下仍然如此,我将感到非常惊讶一个节点的请求,以及整个集群中一百万个并发请求的规模。请注意,所有云提供商都没有针对对象存储延迟和吞吐量的SLA,对于GCS,公认吞吐量是“相当多的变量”。
(注意:之前,在上面的部分中,我提到了Cloud Object Storage API不支持范围请求,这是不正确的,尽管它们仍然不支持(截至2019年10月)单个请求中的多个范围下载,因此并发查询放大系数不会消失。)
此选项的主要优点是与Hadoop生态系统的其余部分很好地集成-计算树甚至可以“附加”到某些已经存在的数据仓库中。大型联接或多步查询等不适用于时间序列范式的复杂查询可以由同一HDFS群集顶部的Spark,Impala,Hive或Presto之类的系统处理。
同样重要的是,旨在部署设计的时间序列存储的组织可能已经具有非常大的HDFS集群,该集群具有较大的出站网络带宽,并且如果时间序列存储使用此HDFS集群存储其数据分区,则它可能会工作围绕网络的可扩展性问题。
但是,库存HDFS通过单个NameNode路由所有读取请求。100k并发读取请求(假设只需要一个读取请求就可以在计算树中的一个节点上下载数据分区)接近NameNode的绝对可伸缩性限制,因此,如果HDFS集群实际上忙于处理某些内容,则超出该限制与时间序列存储无关的操作。
此外,当HDFS用作“远程”分布式文件系统时,即使对于Parquet格式的文件,它也不支持投影下推,因此整个数据分区应由计算树中的节点下载。如果时间序列数据中有数百列,并且通常只使用一小部分进行查询,则效果将不佳。正如云对象存储所建议的那样,使每个数据分区的每一列都成为一个单独的文件,由于扩大了文件和读取请求的数量,因此施加了更大的可扩展性限制。NameNode将无法处理一百万个并发请求,并且HDFS并未针对小于10 MB的文件进行优化,假设最佳数据分区的大小约为一百万,则数据分区的各个列将具有的大小行。
但是,在某些情况下(例如,存在大量未充分利用的HDFS集群)并且在某些使用情况下,HDFS似乎是最经济高效的选择,并且运行良好。
Apache Kudu是一种列式数据存储,旨在在许多情况下替换HDFS + Parquet对。它结合了节省空间的列式存储以及快速进行单行读写的能力。设计的时间序列系统实际上不需要第二部分,因为写入是由Stream处理系统处理的,而我们希望使Storage更加便宜并且不浪费CPU(例如用于后台压缩任务),每个Storage节点上的内存和磁盘资源支持单行读取和写入。此外,在Kudu中对旧数据进行单行写入的方式要求在Kudu节点上进行分区解压缩,而在建议的时间序列存储设计中,只有压缩后的数据应在存储和计算树之间传输。
另一方面,Kudu具有多种功能,这些功能吸引了时间序列系统,而HDFS没有:
Kudu论文提到,从理论上讲,它可能支持可插拔的存储布局。如果实施的存储布局放弃了Kudu对提取单行写入和旧数据写入的支持,但更适合于时间序列存储设计,则Kudu可能会成为比HDFS更好的存储选项。
每个数据分区可以存储在类似Cassandra的系统中的单个条目中。从Cassandra的角度来看,列具有二进制类型,并存储数据分区的压缩列。
该选项与Kudu共享许多优点,甚至具有更好的优点:出色的读取可伸缩性,极低的延迟(尤其是如果使用ScyllaDB),表语义,仅下载所需列的能力(投影下推式)。
另一方面,类似Cassandra的系统并非设计用于多个MB的列值和大约100 MB的总行大小,并且在填充此类数据时可能开始遇到操作问题。而且,它们不支持在单行甚至单行中的单列级别上进行流读取,但可以在这些系统中相对容易地实现。
Cassandra旨在承受高写入负载,因此使用类似LSM的存储结构和大量内存,在时间序列系统中用作存储时将浪费资源。
与我上面讨论的其他选项相比,该选项最快,但成本效益最低。
请参阅此处的想法说明。https://github.com/apache/druid/issues/8575
如上所述,Druid已经将数据摄取与所谓的索引子系统或实时节点中的存储区分开了。但是,尽管该索引子系统实现了完整的分布式流处理系统的功能的子集,但它并未利用其中的任何功能,甚至也没有利用Mesos或YARN之类的资源管理器,并且一切都在Druid源代码中完成。Druid的索引子系统的效率要比现代流处理系统低得多,因为对其进行的开发工作少了数十倍。
同样,时间序列数据通常在Druid之前的其他流处理系统中进行组合或丰富。例如,沃尔玛(Walmart)通过Storm来做到这一点,而Metamarkets将Samza用于类似目的。从本质上讲,这意味着两个独立的流处理系统正在数据管道中一个接一个地运行,从而阻止了映射运算符与Druid的提取终端运算符的融合,这是流处理系统中的常见优化。
这就是为什么我认为在下一代时间序列中,数据提取应充分利用某些现有的流处理系统。
流处理系统与其余时间序列存储之间需要紧密集成,例如允许计算树中的节点查询流处理系统中的工作程序。这意味着与Storage的情况不同,它可能很难支持多个流处理系统。应该只选择一个,并将其与时间序列系统集成。
Flink,Storm和Heron都是可能的候选人。很难判断当前哪个技术更合适,或者说在哪个技术上更合适,因为这些项目可以快速相互复制要素。如果设计的时间序列系统实际上是在某个组织中创建的,则选择可能取决于该组织中已使用的流处理系统。
阅读Druid Development邮件列表中的该线程,以获取有关此主题的更多信息。
对于系统的这一部分的外观,我并不太费劲。上面的“设计概述”部分介绍了一些可能的方法。
这种方法至少存在一个问题:如果需要缓存太多查询结果,则计算树的第三(最高)级别的多个节点将无法有效地处理对特定时间序列(表)的查询。为了始终将相似的子查询(仅在总体查询间隔上不同的子查询)路由到相同的节点并捕获缓存的结果,应将具有多个子查询的一个“复合”查询分解为多个独立的查询,进而使用网络存储和计算树之间的效率较低:请参见上面的“网络是瓶颈”部分,该列表中的第一项。
但是,可以在垂直方向上扩展第三级计算树中的节点,以使其足够大,从而能够处理所有查询并容纳任何单个时间序列(甚至最繁忙的时间序列)的整个缓存。
垂直扩展意味着第三级计算树中的一个节点应处理大量并发查询。这就是为什么我认为如果从头开始构建计算树的原因之一,它应该选择异步服务器体系结构而不是阻塞(Go风格的绿色线程也可以)。其他两个原因是:
理想情况下,构建计算树的编程平台应具有以下特征:
从纯技术角度来看,C ++是赢家,它可以满足所有这些要求。选择C ++与性能无关的缺点也是众所周知的:开发速度,可调试性,使用插件体系结构扩展系统都很困难等。
JVM仍然是一个不错的选择,我相信该系统的效率可能比使用C ++内置的系统低不超过20%:
据我所知,尽管Go或Rust目前不支持运行时代码生成,尽管添加这种支持可能不需要太多的黑客操作:请参阅gojit项目以及有关Rust的StackOverflow问题。对于其他条件,Go的运行时和生成的代码可能效率较低,但是出于某些非技术性原因,它比Rust更有效。
本文由知识库于2021-09-16发表在龙哥云资源网,如有疑问,请联系我们。本文链接:https://www.longgeyun.com/knowledge/3810.html
上一篇地下城与勇士9月免费领最高43天黑钻
下一篇table表格横向的滚动条(讲解table滚动条事件)
高校最常见的食物中毒有哪些
急性肠胃炎与食物中毒怎么分辨
莫代尔面料和纯棉面料哪个好内裤 哪个儿童可以穿
为什么说开速腾的都不是一般人 速腾开出去有面子吗
活珠子和毛蛋的区别在哪里 哪个好吃
家里放石头的八大禁忌有哪些 家中石头最佳摆放位置
怎么判断自己帅还是丑男 男生怎样越长越帅
单身女生红绳戴左手还是右手 女生红绳戴哪里合适
Pr2020零基础快速入门
文字转语音App最新版3.0
APP下载页源码-带后台