一周一论文(翻译)——[IEEE 14] Elastic scaling for data stream processing

Abstract

本文讨论与通用分布式数据流处理应用程序的自动并行化相关的盈利问题。自动并行化涉及在应用程序的数据流图中定位区域,这些区域可以在运行时复制以应用数据分区,以实现扩展。为了使自动并行化在实践中有效,需要回答盈利问题:有多少并行通道提供最佳吞吐量?此问题的答案根据运行时的工作负载动态和资源可用性而变化。在本文中,我们提出了一种弹性自动并行化解决方案,可以动态调整用于实现高吞吐量的通道数,而不会浪费资源。最重要的是,我们的解决方案可以通过运行时状态迁移处理分区有状态运算符,这对应用程序开发人员完全透明。我们在工业级数据流处理平台上提供系统的实施和评估,以验证我们的解决方案。

1. Introduction

       随着世界变得更加互联和仪表化,来自各种软件和硬件传感器的大量数据以连续流的形式出现。可以在多个领域找到示例,例如金融市场,电信,制造业和医疗保健。在所有这些领域中,越来越需要收集,处理和分析这些数据流以提取见解以及检测新出现的模式和异常值。最重要的是,这种分析通常需要近乎实时地进行。世界变得更加互联和仪表化,来自各种软件和硬件传感器的大量数据以连续流的形式出现。可以在多个领域找到示例,例如金融市场,电信,制造业和医疗保健。在所有这些领域中,越来越需要收集,处理和分析这些数据流以提取见解以及检测新出现的模式和异常值。最重要的是,这种分析通常需要近乎实时地进行。

       流计算是一种计算范例,能够以高效且可扩展的方式执行分析任务。 通过将传入的数据流通过放置在一组分布式主机上的Operator网络,流计算提供了即时的处理模型。 由于数据不直接存储在磁盘上,因此流计算避免了更传统的数据管理存储和处理模型所面临的性能问题。 商业流处理系统的出现,如StreamBase [28]和InfoSphere Streams [16],开源系统,如S4 [34]和Storm [27],以及现有的学术系统,如STREAM [5],Borealis [1]和System S [18],是流计算范式未来增长和过去成功的证据。

       在短时间内处理大量实时数据的频繁需求是流处理应用的主要特征[26]。 因此,支持高吞吐量处理是流式系统的关键要求[14]。 它需要利用多台主机来实现可扩展性[4]。 随着可用于处理的不断增加的实时数据量,这一要求将变得更加突出。 由于云计算和多核芯片设计的进步,分布式和并行计算的可承受性得到提高,这使得这个问题变得易于处理。 这产生了对语言和系统级技术的需求,这些技术可以有效地定位和有效地利用流处理应用程序中的并行化机会。 后一方面是本文的重点。

       流应用程序被构造为有向无环图,其中顶点是Operator,边是数据流。 为了扩展此类应用程序,流处理系统可以自由决定应用程序图将如何映射到可用主机集。 自动并行化[24]是一种有效的技术,可用于以透明的方式缩放流处理应用程序。 它涉及检测应用程序图中可以在多个主机上覆制的parallel regions,这样复制区域的每个实例(我们称之为通道)处理数据流的子集以便增加吞吐量。 这种并行形式称为数据并行性。 透明数据并行化涉及在没有应用程序开发人员直接参与的情况下检测parallel regions并应用运行时机制以确保安全性:并行化应用程序产生与顺序应用程序相同的结果。

       虽然安全性确保了正确性,但并不能确保提高性能。 提高性能的透明自动并行化必须具备一定的盈利机制。 在流数据parallel regions中,盈利能力涉及确定正确的并行度,这是要使用的并行通道的数量,而无需应用程序开发人员的明确参与。 弹性自动并行化通过使盈利性决策适应运行时动态(例如工作负载的变化和资源的可用性)而更进一步。 在本文中,我们提出了为流处理应用提供有效弹性自动并行化的新技术

实现弹性自动并行化有两个重要的要求。

R1)存在有状态运算符时的弹性需要状态迁移。 这带来了两个主要挑战。 首先,为了保持自动并行化的透明性,需要在存在但不干扰应用程序逻辑的情况下执行状态迁移。 其次,我们需要尽量减少迁移状态。 通过最小化迁移状态,我们最小化可能干扰数据流的时间和空间开销。 反过来,这将使更频繁的适应。

(R2)存在运行时动态时的弹性需要控制算法。 这带来了两个主要挑战。 首先,通用流处理应用程序包含大量用户定义的Operator。 我们不能轻易地模拟这些Operator的反应。 应对这一挑战需要利用运行时Metrics指标来指导控制系统,而不是依赖传统的基于成本的优化。 其次,我们需要确保控制算法能够提供SASO属性[12]。 也就是说,它表现出稳定性(不会振荡使用的通道数),达到良好的精度(找到最大化吞吐量的通道数),具有较短的稳定时间(快速达到稳定的通道数),最后避免 过冲(不使用超过必要的频道)。

       我们通过开发基于Key-Value存储的状态API来解决透明迁移的挑战,该API旨在支持分区有状态Operator的实现。 分区有状态Operator为分区属性[24]标识的每个子流存储独立状态。 这些Operator在流处理应用程序中非常常见(由IP编号划分的网络跟踪,由股票行情者划分的财务流等)。 我们开发编译时重写技术,将高级用户代码转换为使用状态API的等效版本,以便保护应用程序开发人员免受状态迁移的细节。

       我们通过开发增量迁移协议和基于一致Hash散列的相关拆分策略来解决低成本迁移的挑战[19],它们共同最小化了迁移状态的数量。

       我们通过依赖于在splitter处计算的两个本地Metrics来解决运行时控制的挑战:congestion index(在Splitter处的Blocking时间的度量)和吞吐量。 splitter是一个运行时组件,与Operator共同生成要拆分的流以进行并行处理。 我们开发了一种在Splitter上工作的本地控制算法,并使用这些Metrics度量来调整用于处理流的信道数。

       我们通过在控制算法中引入几种技术来解决提供SASO属性的挑战。 这些措施包括根据观察到的Metrics指标的变化,根据使用的Channel通道数量来上下调整,以解决准确性和超调问题; 记住过去在不同操作点取得的表现以解决稳定性问题; 并快速缩放以解决建立时间问题。

本文做出以下主要贡献:

  1. 据我们所知,它提供了第一个弹性自动并行化方案,可以处理有状态运算符,适用于多个主机,并且专为通用流处理应用程序而设计。
  2. 它提出了一种状态管理API,编译时重写技术和运行时迁移协议,以最小的状态移动执行透明状态迁移。
  3. 它提出了一种控制算法,该算法使用本地信息和本地控制来实现SASO属性,以便找到最佳工作点,以便以工作负载和资源自适应方式解决盈利问题。
  4. 它提供了对工业级流处理系统的实现和评估。

       我们为实现弹性而引入的技术和算法,例如控制算法,状态管理技术和迁移协议,都具有普遍适用性,并且可以在任何流处理系统中实现。我们使用IBM InfoSphere Streams的原型版本,简称Streams及其编程语言SPL [13]来举例说明状态管理API。

       总之,本文展示了如何以透明和弹性的方式解决分布式有状态流处理的盈利问题。本文的其余部分组织如下。第2节提供了Streams和SPL [13]的背景知识,并概述了基于以前工作的自动并行化的安全性方面[24]。第3节概述了我们的弹性自动并行化解决方案。第4节描述了控制算法及其如何实现SASO属性。第5节描述了基于键值的状态API和编译时重写技术。第6节详细阐述了迁移协议。第7节报告了实验结果。第8节讨论了相关工作,第9节总结了这篇文章。

2. BACKGROUND

       本节简要讨论SPL语言和Streams中间件,然后介绍自动并行化的安全性方面

2.1 SPL AND STREAMS

       SPL [13]是一种用于开发流处理应用程序的编程语言。 SPL应用程序由通过流连接相互连接的Operator实例组成。 Operator实例是应用程序数据流图中的顶点。 Operator实例是Operator定义的实现。 例如,图1中顶部图的左侧所示的运算符实例是TCPSource Operator的实例。 通常,Operator可以具有许多不同的实例,每个实例使用不同的流类型,参数或诸如窗口的其他配置。 Operator实例可以具有零个或多个输入和输出端口。 每个输出端口生成一个唯一命名的流,它是一系列元组。 将输出端口连接到运营商的输入会建立流连接。 流连接是应用程序数据流图中的边缘。

       Operator直接在SPL(通过自定义Operator)或通用编程语言中实现。 在这两种情况下,运算符实现依赖于事件驱动的接口,它们对到达Operator输入端口的元组作出反应。 元组处理通常涉及更新某些操作符本地状态并生成在输出端口上发送的结果元组。

       Streams [16]是一个分布式流处理引擎,可以使用一组分布式主机执行SPL应用程序。 它执行各种运行时任务,例如数据传输,调度,容错和安全性。

2.2 Auto-Parallelization

       自动并行化是在应用程序的流程图中自动发现数据parallel regions的过程,可以在运行时利用它。 除了发现这些parallel regions之外,编译器还必须建立激活适当的运行时机制所需的某些属性,以确保自动并行化的安全性。 例如,如果parallel regions是无状态的,则要应用的运行时数据分割机制可以是循环的,而如果该区域是分区有状态的,则必须使用基于Hash的方案来执行数据分割。

       我们使用清单1中给出的SPL代码示例说明了一个示例自动并行化过程。这里,我们看到一个名为OpMon的示例操作监视应用程序。 TCP Source运算符的实例用于接收包含有关不同应用程序的网络使用情况的信息的流。 接下来是一个Aggregate运算符实例,它使用appId作为分区键计算每个应用程序的每分钟数据使用信息。 聚合结果通过Filter运算符获取,以保留网络使用率高于阈值的应用程序。 最后,将结果结果发送到TCP Sink运算符实例。

       图1显示了OpMon应用程序(顶部)的数据流图的可视化,以及它的自动并行化版本(在底部)。 在此示例中,并行区域由Aggregate和Filter运算符组成。 它是一个分区的有状态parallel regions,因为Aggregate运算符基于每个分区维护状态。 Splitter驻留在parallel regions之前的Operator的输出端口上,并负责将元组路由到并行通道。 一旦元组被路由到特定通道,那么与它共享appId属性值的所有未来元组必须被路由到同一个通道。 这是通过在appId属性上应用hash函数在Splitter上实现的。

       在此示例中,在parallel regions(TCP Sink)之后还有一个附加Operator。 此外,没有迹象表明该Operator可以容忍乱序结果。 因此,这个特定的parallel regions(需要在其输出处维持元组的顺序。 这是在合并时实现的,合并位于并行区域之后的运算符的输入端口上。 合并使用在Splitter处分配并通过并行区域传送的序列号执行重新排序操作。

       最后,这个并行区域包含一个Filter运算符,可以删除一些元组。 这导致选择性值最多为1.因此,如果给定信道的元组碰巧以比其他信道更高的频率丢弃,则合并可能长时间阻塞。 这是因为在没有元组到达的时候,合并无法区分需要很长时间才能到达的元组和永远不会到达(丢弃)的元组。 为了解决这个问题,这个特定的并行区域使用pulespules是由Splitter周期性地发送并由合并器使用的特殊标记,以避免冗长的停顿。

       有关自动并行化安全方面的完整详细信息,请参见[24]。 总之,并行区域的以下属性[33]在用于确保安全性的运行时机制中起着核心作用:

  1. Statefulness : 确定区域是否可以并行化,因为只有无状态和分区有状态运算符适合数据并行。 它还确定了分离器使用的数据分区方案。
  2. Ordering: 下游运营商的要求确定并行区域是否需要在合并期间进行排序步骤。
  3. Selectivity: 并行区域的确定是否需要pulse以避免冗长的停顿。

在本文的其余部分,我们将了解如何通过运行时自适应来解决自动并行化的盈利方面问题。

3. SOLUTION OVERVIEW

       在本节中,我们将概述我们的解决方案,该解决方案基于运行时弹性。

       我们的方法的关键思想是将盈利能力决策留给运行时,我们可以在其中推断工作负载和资源可用性。 当应用程序开始执行时,并行通道的数量将设置为1. 放置在Splitter上的控制算法会根据其维护的本地运行时指标Metrics,定期重新评估要使用的通道数。 控制算法可以决定增加或减少使用的信道数量,或者在任何决策点不采取任何行动。 当要使用的通道数改变时,如果并行区域是有状态的,则可能需要执行状态迁移协议。

       重要的是要注意,我们没有解决这项工作中的放置问题。 特别是,当我们的算法请求新的并行通道时,我们假设它将被放置在系统中的可用主机/核心上。

       对于分区有状态的并行区域,改变并行通道的数量需要部分重新定位状态。 例如,如果并行通道的数量增加,则一些分区的分配需要从现有的并行通道移动到新的并行通道。 每当在Splitter处发生这种分配的改变时,与移动的分区相关联的状态也必须被重新定位。 特别地,新添加的并行信道需要从现有并行信道收集分配给它们的分区的状态。 类似地,当移除现有通道时,与其处理的分区相关联的状态必须重新分配到现有并行通道。

       作为系统不变量,每个分区在任何给定时间点仅由单个并行通道拥有。 我们使用一致性hash执行分区到并行通道的分配,以最小化迁移期间移动的状态量。

       为了透明地执行运行时迁移,流处理中间件必须推断Operator维护的状态。 在通常使用用户定义的Operator的通用流式传输系统中,这需要特殊的机器。 为了解决这个问题,我们的解决方案包括一个本地Key-Vaule存储形式的状态管理API。 SPL编译器重写Custom Operator中存在的代码,以便将状态转换为使用此API,从而使运行时能够推断此状态并执行透明迁移。

4. CONTROL ALGORITHM

定期运行控制算法以更新并行信道的数量。 它依赖于以下两个本地计算的指标:

Congestion:表示Splitter在连接上发送元组时是否观察到不适当的延迟。 它在两个方面是一个有用的指标:1)阻塞的存在表明我们需要更多的信道来处理当前的负载,同样缺乏阻塞表明我们可能使用的信道多于必要的信道。 2)阻塞值的时间变化可以指示工作负载可用性的变化。 我们通过对阻塞指数应用阈值来计算阻塞作为布尔值,阻塞指数是由于背压而阻塞Splitter处的元组传输的时间分量的Metcis。

       为了计算阻塞指数,我们使用非阻塞I / O来传输元组。 如果发送呼叫通知我们会发生阻塞,则我们阻塞直到可用空间并测量所涉及的阻塞量。 总的来说,阻塞指数衡量阻塞所花费的时间。 我们在所有Channel上平均这个值。 拥塞指数是范围[0,1]中的值。 我们将在4.3节中进一步讨论阻塞指数阈值。

Throughput: 是在上一个适应期间每秒处理的元组数。 吞吐量在两个方面是有用的:1)当我们根据通道数量移动到新的操作点时,它告诉我们情况是否有所改善。毕竟,目标是优化吞吐量。 2)吞吐量的时间变化可以指示工作量的变化。 控制算法基于以下两个基本原则运行:

(P1)Expand:如果出现拥堵,则上升(增加通道数),除非您以前曾在那里并且没有观察到提高的吞吐量。

(P2)Contract:如果没有拥堵,则下降(减少通道数量),除非您曾经去过那里并观察到拥堵。

       这里,(P1)提供了SASO的准确性:我们获得了良好的准确性,因为通道数量增加直到拥塞被消除。 (P2)提供SASO中的过度配置属性:我们避免使用超过必要的更多信道,因为除非下面出现拥塞,否则信道数量会减少。 (P1)和(P2)中的“除非”条款在SASO中提供稳定性属性:我们不会在操作点之间振荡,因为过去发生的事情会被记住而不会重复。 但是,当工作量波动时,这两个原则是不够的。 当工作负载可用性发生变化时,我们需要忘记过去发生的部分事情。 因此,我们引入了以下调整以适应工作负载变化

(P3)拥塞适应:如果在拥塞中观察到工作量增加(减少)的变化,则忘记过去关于上升(下降)通道的观察。

(P4)吞吐量适应:如果观察到指示工作量增加(减少)的吞吐量的变化,则忘记过去关于上升(下降)信道的观察。

       这里,(P3)和(P4)使控制算法能够适应工作负载变化。 注意,控制算法具有以下关键特征:它将在多个信道上建立,使得没有拥塞,但是任何较少数量的信道将导致拥塞。 当处于这种稳定状态时,如果工作量增加,它将开始观察拥塞并上升(由于(P1))。 当工作量减少时,它将观察到吞吐量减少并且忘记下面的一个信道导致拥塞(由于(P4))并且下降(由于(P2))的事实。

       此版本的控制算法还有两个小问题。 第一个是关于拥堵的性质。 该算法被设计为解释拥塞的存在,作为需要更多信道来处理负载的指示。 在拥塞不是由于并行区域的成本而是由于并行区域下游的流量成本的情况下,增加通道数量不会导致任何改进,而是会导致过冲。 我们称这种拥塞远程拥塞,并使用以下附加原则避免潜在的陷阱:

(P5)远程拥塞:如果在增加信道数量后拥塞继续,但吞吐量没有显着增加,则下降。

       这里,(P5)避免了由于持续存在拥塞而导致信道数量连续增加的情况,但吞吐量没有提高。 没有(P5),这可能发生在远程拥塞的情况下。 值得注意的是,大多数流应用程序在通过并行化删除其原始瓶颈时最终会达到可伸缩性限制。 这是因为瓶颈移动到应用程序的不可并行化部分,在大多数情况下,该部分是Source,Sink或某些有状态操作符。 在并行区域下游的Operator成为瓶颈的所有情况下,将发生远程拥塞。

       第二个问题是,在可用资源(诸如主机和核心的执行上下文)和并行区域的成本都很高的情况下,最佳信道数也可以是高的。 因此,控制算法可能需要很长时间才能达到该数量。 这是由于算法的一次一个通道性质,并可能对SASO中的稳定时间属性产生负面影响。 我们通过引入一个称为快速缩放的算法选项来解决这个问题。 总结如下:

(P6)快速扩展:不是一次操作一个通道,而是一次操作一个级别,并在级别和通道数之间定义超线性映射。这里,(P6)通过仍然一步一步地改变操作点来保持算法的主要操作模式。 但是它不是直接使用通道数,而是使用一个级别,通过一个函数将其映射到通道数。 特别是,我们使用以下函数:

       为了从0开始增加级别值,这导致以下一系列通道数:{1,2,3,4,6,8,11,16,23,32,...}。 根据最大通道数和建立时间要求,可以使用遵循更陡峭或更陡峭曲线的其他功能。

图2给出了控制算法的高级描述,说明了原理P1到P6。

4.1 Algorithm Implementation

       控制算法保留三个状态变量。 第一个是当前的适应期,用P表示。第二个表示当前级别,用L表示。第三个是保存每个级别的以下信息的数组:算法所处的最后一个适应期 这个级别,用P i表示; 是否在最后一次算法处于此水平时观察到拥塞,用C i表示; 上次算法处于此级别时观察到的吞吐量,用T ai表示; 以及在最后一次算法在该水平上保持连续周期的第一个周期期间观察到的吞吐量,由T i表示。 我们使用L *来表示最大级别数。

       控制算法具有称为变化灵敏度的全局参数,表示为 α,其确定重要变化意味着什么。 它取一个[0,1]范围内的值。 值为1表示算法对吞吐量的微小变化非常敏感。 例如,如果灵敏度很高,则吞吐量的微小改善就足够了。 吞吐量的所有变化都针对线性缩放系统中单个通道的理想吞吐量进行标准化。

       算法1中的init()程序提供状态变量的初始化逻辑。该算法的核心在算法2提供的getNumberOfChannels()例程中给出,该例程将当前吞吐量(由T表示)和当前拥塞状态(由C表示)作为参数。作为第一步,应用原理(P3)和(P4)以查看负载是否有变化。如果负载增加(减少),则重置保持有关上述(下面)级别的信息。第二步更新保留的有关当前级别,上次吞吐量,上次拥塞状态和第一次吞吐量的信息(除非算法最后一次处于此级别)。第三步调整当前级别。首先,应用原则(P5)来查看是否存在远程拥塞。如果是这样,我们会回到上一个级别。否则,应用原则(P1):我们检查是否存在拥塞,如果是,则上升一级除非算法之前存在但吞吐量更差。最后,应用原则(P2),即如果没有拥塞,我们向下一级,除非算法之前已经存在并观察到拥塞。一旦调整了当前电平,则应用原理(P6)以返回对应于当前电平的通道计数。

4.2 Detecting Workload Changes

       算法3中给出了用于检测工作负载变化的逻辑.checkLoadChangeViaCongestion()例程使用拥塞状态来检测负载变化。如果当前级别和最后级别相同,但拥塞状态已经改变,则将其视为负载变化的指示(如果当前存在拥塞则负载增加,否则负载减少)。如果当前级别低于最后一级,但拥塞已消失,则将其视为负载减少。最后,如果当前级别高于​​最后一级,但是已经出现拥塞,则将其视为负载增加。 checkLoadChangeViaThroughput()例程使用吞吐量来检测负载变化。如果当前级别和最后级别相同,但吞吐量存在显着变化,则将其视为负载变化的指示(如果当前吞吐量值较高则负载增加,否则负载减少)。变化灵敏度用于检测相对于线性缩放系统中的理想变化的显着变化。如果当前级别低于最后一级,但吞吐量增加,则将其视为负载增加。最后,如果当前级别高于​​最后一级,但吞吐量已降低,则将其视为负载减少。

4.3 Discussion of Parameters

       控制算法具有三个可配置参数。其中,拥塞指数阈值是唯一需要仔细调整的阈值。我们在实验评估部分中根据经验研究其设置,并显示在[0.01,0.3]范围内的任何阈值提供了稳健的设置。

       快速缩放是一项可以打开以减少建立时间的功能。它调整了快速适应和微调并行通道数量的能力之间的权衡。

       更改灵敏度可调整系统对工作负载变化的敏感度。在迁移成本较低的系统中,变化灵敏度参数的较小值(较高的灵敏度)是合适的。对于迁移成本高昂的系统,最好在采取适应步骤之前等待观察到的吞吐量发生重大变化。例如,如果通道处理的吞吐量下降了10%,那么通过降低一级来对此做出反应对于具有高开销迁移的系统来说可能过于激进。

       即使用户没有调整快速缩放或改变选择性,我们的算法也能满足所有SASO属性。但是,通过提供这些参数,我们使高级用户可以根据需要调整SASO属性之间的相对权衡。

5. STATE MANAGEMENT

       参与并行区域的运营商要么是无状态的,要么是分区有状态的,如第2.2节所述。 分区有状态运算符基于分区属性在每个分区的基础上维护独立状态。 这些操作员需要特殊的机器来支持透明的弹性平行化。 特别是,运行时系统需要迁移(跨主机)与分区子集关联的状态。 这要求运行时了解由分区有状态运算符管理的状态。

       为了解决这个问题,我们开发了一个状态管理API和一个相关的状态管理服务。 此外,我们提供语言级机制,使新开发的运营商能够利用托管状态。 有关托管状态API的详细信息及其在SPL应用程序中的透明使用,请参阅附录A.

6. STATE MIRGRATION

       响应于控制算法在Splitter处做出的决定,对并行区域执行迁移协议。当控制算法更新通道数时,它还更新它用于在并行通道之间分配分区的数据分区功能并启动迁移协议。仅在分区有状态并行区域的情况下才需要迁移。

       通过从Splitter向所有并行通道发送迁移脉冲来启动迁移协议。当并行通道中的操作员接收到迁移脉冲时,它首先将脉冲向下游转发,然后开始执行每个操作员的迁移协议。这使得在并行区域包含多于一个分区有状态运算符的情况下,可以并行地在多个运算符的副本之间执行状态迁移。

       我们首先描述运算符的迁移协议,然后讨论使用不同数据分区函数对系统性能的影响。

7. CONCLUSIONS

       我们提出了一种自动并行化方案,可以为流处理应用程序提供弹性。它可以根据工作负载的可用性调整在运行时使用的并行通道数。最重要的是,通过依赖分区状态的迁移,它能够处理流处理应用程序中常见的分区有状态运算符。我们提出了一种控制算法,该算法能够实现良好的吞吐量,具有较短的建立时间,并避免振荡和过冲。我们描述了状态管理API和迁移协议,它们共同实现了对应用程序开发人员透明的弹性并行化。此外,弹性不会干扰安全性,并且在相同的输入下,相同的输出以相同的顺序产生,而不管是否存在迁移。实验结果说明了我们的解决方案在寻找平行区域的理想工作点并在工作负载动态存在的情况下调整这一点的有效性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章