A Catalog of Stream Processing Optimizations

摘要

本文主要基于两个方面,一方面是流计算的各个社区都对流计算做了一些优化,本文汇总这些优化做了一个目录,另一方面这些社区给优化起的名字也不尽相同,同种优化可能有多个术语,本文统一了这些术语。

算子重排序(OPERATOR REORDERING A.K.A. HOISTING, SINKING, ROTATION, PUSH-DOWN)


2.1 例子
考虑一种持续监控患者的医疗保健应用程序,如上图,输入包括患者ID和生命体征,A算子负责用护士上一次诊断信息填充数据,B算子只转发警报生命体征的数据项,在这种排序中,A只负责填充数据,B负责过滤筛选,将B排在前面可以减少开销。

2.2 收益
如果将选择性算子放到代价高的算子之前,那么算子重排序是有收益的
比如A的选择性固定在0.5,B的选择性随x轴变化,吞吐量变化如下图:

不进行重排序的吞吐量不变是因为B只负责处理输入数据,自己的选择性并不会影响吞吐量

2.3 安全性
需要满足以下条件:

  • 确保属性可用性:第二个算子B必须只依赖于A的输入流中的属性,也就是B所需的数据属性不需要A的处理
  • 确保交换性:A与B的顺序交换所产生的效果必须相同

冗余消除(REDUNDANCY ELIMINATION A.K.A. SUBGRAPH SHARING, MULTIQUERY OPTIMIZATION)


3.1 例子
如图,这种情况很简单,考虑两个电信应用程序,其中一个不断更新账单信息,另一个监视网络问题,这两个应用程序都从算子A开始,A重复删除呼叫数据记录,并用呼叫者信息填充,A对于B、C是重复的,可以消除冗余A,节省资源

3.2 收益
如果资源有限,冗余工作的成本很大,那么消除冗余是有利可图的。
下图假设A、B、C算子总成本不变,增加A算子的成本时总吞吐量的变化:

当成本为1时消除冗余应该是不消除的两倍,因为不消除冗余计算了两次

3.3 安全性
需要满足以下条件:

  • 确保相同算法:冗余算子必须执行等价的计算,一个充分条件就是相同的代码
  • 确保可合并的状态:如果算子是无状态的则很好处理,如果有状态则需要小心处理

算子分离(OPERATOR SEPARATION A.K.A. DECOUPLED SOFTWARE PIPELINING)


4.1 例子
考虑一种零售应用层序,不断监视公共论坛,根据用户评论进行评分,算子A负责根据用户情绪与产品过滤数据项,由于算子A有两个过滤条件,所以A可以被分离成两个算子A1和A2,进而利用算子重排序(第二节)进行优化

4.2 收益
如果算子分离后能够结合其他优化,则算子分离是有利可图的

4.3 安全性
需要满足以下条件:

  • 确保分离的算子组合等价于原始算子:给定一个输入流s,只有当B2(B1(s)) = B(s)时,操作符B才能安全地分离为操作符B1和B2

融合(FUSION A.K.A. SUPERBOX SCHEDULING)


5.1 例子
考虑一个安全应用程序,它不断地检查系统日志以检测安全漏洞。应用程序包含一个算子A,用于解析日志消息,然后是一个选择算子B,它使用简单的启发式方法过滤掉与安全漏洞检测无关的日志消息。假设这两个算子运行在不同的核上,并且选择算子B与将数据项从A传输到B并触发B的成本相比是轻量级的。融合A和B可以防止不必要的数据传输和算子触发。融合消除了A和B之间的管道并行性,但由于B是轻量级的,因此节省的成本超过了管道并行性带来的损失。

5.2 收益
如果融合算子,会降低他们之间的通信成本,但融合会降低管道并行性,下图展示了两个算子在成本相同的情况下的吞吐量

5.3 安全性
需要满足以下条件:

  • 确保资源种类:融合的算子必须只依赖于资源,包括逻辑资源和物理资源,这些资源都在一台主机上可用
  • 确保资源数量:融合后的算子所需资源总量不能超过单个主机的资源
  • 避免无限递归:如果流图中有一个循环,数据可能无限的围绕这个环流动,如果算子通过函数调用实现算子融合,可能导致栈溢出

裂变(FISSION A.K.A. PARTITIONING, DATA PARALLELISM, REPLICATION)


6.1 例子
假设A是一个卷积运算算子,它对每个矩阵执行代价高昂但无状态的计算,裂变复制算子A在多个核上运行加快速度。

6.2 收益
如果复制的算子成本高到足以成为应用程序的瓶颈,并且并行化的好处超过了裂变带来的开销,那么裂变是有利可图的,裂变本身也会带来开销,下图每条曲线都由p/s/o比值指定,p/s/o代表并行/顺序/开销。换句话说,p是A本身的开销,s是图中任何不被复制的连续部分的开销,o是拆分和合并的开销。

6.3 安全性
需要满足以下条件:

  • 如果存在状态,则保持其不相交或者让他们同步:不存在状态可随意分裂,如果存在不相交的状态,按分离出分割,比如keyed状态,如果共享状态的话,则需要适当的同步条件以避免竞争
  • 如果需要排序,则按顺序合并:如果下游算子需要按上游的输入顺序输入,则需要将分裂后算子的输出排序
  • 避免死锁:前两个安全约束都涉及同步:共享状态访问同步以避免竞争条件,合并同步以等待乱序数据项。如果存在循环等待条件,同步会带来死锁风险

放置(PLACEMENT A.K.A. LAYOUT)


7.1 例子
考虑一个电信应用程序,A与C算子都很昂贵,选择算子B很廉价,将A与C放到不同的主机上很有意义,将A与B放到一起可以减小数据通信成本

7.2 收益
安置交易沟通成本与资源利用。当多个算子被放置在同一台主机上时,它们会竞争公共资源,如磁盘、内存或CPU

7.3 安全性

  • 确保资源种类:如果每个主机上的所有算子都有正确的资源,那么放置是安全的
  • 确保资源数量:融合运算子所需的资源总量(如FPGA容量)不得超过单个主机的资源
  • 遵守安全和许可限制:除了资源限制外,放置也可能受到安全性的限制,某些算子只能在受信任的主机上运行。除了这些技术限制之外,法律问题也可能适用
  • 如果放置是动态的,只移动可重定位的操作符:动态放置需要算子迁移(即,将算子从一个主机移动到另一个主机)。要安全地做到这一点,需要移动算子的状态,并确保在切换过程中没有飞行中的数据项丢失。根据系统的不同,这可能只适用于某些算子

负载均衡(LOAD BALANCING)


8.1 例子
考虑一个安全应用程序,它不断检查从医院传出的消息是否泄露机密的患者信息,算子A是昂贵的,应用裂变创建并行副本A1、A2、A3,当其中一个副本忙于处理一条需要很长时间处理的消息,而另一个副本处于空闲状态时,这种优化将下一条消息发送给空闲副本

8.2 收益
如果负载平衡能够补偿倾斜,那么它是有利可图的。

8.3 安全性

  • 避免饥饿:工作分配必须确保每个数据项最终都得到处理
  • 确保每个worker都是合格的:如果在裂变之后完成负载平衡,每个副本必须能够处理每个数据项。这意味着副本必须是无状态的,或者可以访问公共共享状态。
  • 建立放置安全:如果在放置算子时进行负载平衡,则必须满足第7.3节中的放置安全条件

状态共享(STATE SHARING A.K.A. SYNOPSIS SHARING, DOUBLE-BUFFERING)


9.1 例子
考虑一个财务应用程序,该应用程序连续计算1小时和1天的股票数量加权平均价格和其他统计数据。假设应用程序为每个聚合维护很大的窗口,以至于它们的内存需求可能是单个主机的很大一部分。但是,如果聚合之间的唯一区别是它们的时间粒度,那么它们可以共享相同的聚合窗口,从而减少两个算子所需的内存总量。

9.2 收益
如果通过减少内存占用来减少由于缓存丢失或磁盘I/O而导致的暂停,那么状态共享对于吞吐量来说是有利可图的

9.3 安全性

  • 确保状态对两个算子都可见:共享状态的操作符必须具有对状态的共同访问权。通常,这是通过融合来完成的,将它们放在相同的操作系统进程中
  • 避免竞争条件:状态共享必须通过确保数据不可变或适当地同步访问来防止竞争条件
  • 安全管理内存:共享状态的内存管理正确。既不能过早回收,也不允许无限制地增长(即泄漏)。

批处理(BATCHING A.K.A. TRAIN SCHEDULING, EXECUTION SCALING)


10.1 例子
考虑一个医疗保健应用程序,该应用程序反复触发用于医学成像的FFT(快速傅里叶变换)算子,批处理可以在多个数据项上分摊将FFT代码放入缓存的成本

10.2 收益
批处理以吞吐量换取延迟。批处理可以通过在更多数据项上摊销操作触发和通信成本来提高吞吐量。这种可摊销成本包括可能嵌套很深的调用;预热成本,特别是指令缓存;还有调度成本,可能涉及到上下文转换。另一方面,批处理会导致更糟糕的延迟,因为数据项不会在可用时立即进行处理,而是在整个批处理可用时才进行处理。该图显示了从1到10个数据项的批处理大小的权衡。对于吞吐量,越高越好;最初,吞吐量有很大的提高,但是当每批成本摊销后,吞吐量曲线趋于平稳。对于延迟,越低越好;延迟随批处理大小线性增加,批处理越大,延迟越严重。

10.3 安全性

  • 避免死锁:批处理只有在不导致死锁的情况下才是安全的。如果算子图是循环的,批处理可能导致死锁
  • 满足deadline:某些应用程序具有严格的实时约束;其他的则有涉及延迟的服务质量(QoS)约束

算法的选择(ALGORITHM SELECTION A.K.A. TRANSLATION TO PHYSICAL QUERY PLAN)


11.1 例子
算法越好肯定越快

11.2 收益

11.3 安全性

  • 确保相同的行为:两个算法行为必须相同

负载脱落(LOAD SHEDDING A.K.A. ADMISSION CONTROL, GRACEFUL DEGRADATION)


12.1 例子
考虑一个应急管理应用程序,它向警察和消防公司以及普通公众提供后勤信息。在正常情况下,系统可以很容易地跟上负载并向每个请求的人显示信息。然而,当灾难发生时,负载可能会增加几个数量级,并超过系统的容量。如果不减少负载,请求就会堆积起来,没有人会得到及时的响应。相反,更好的做法是,只对警察或消防公司的请求提供完整而准确的回复,降低其他人的准确性,从而减轻部分负担

12.2 收益
负载减少以降低精度为代价提高了吞吐量

12.3 安全性
与本文中的其他优化不同,从定义上讲,负载脱落是不安全的。当其他优化尝试计算与未优化情况相同的结果时,负载脱落计算不同的近似结果;应用程序的服务质量将降低。然而,根据特定的应用,这种质量下降可能是可以接受的。

优化方法关系图

posted @ 2023-03-05 16:05  红橙黄绿蓝鳍金枪鱼  阅读(55)  评论(0)    收藏  举报