流式计算中的背压/反压

130 阅读2分钟

一. 背景

1.1 排队论

通过队列来有效提升系统的负载能力

1.2 ReactiveStream设计模式

生产者-消费者+迭代器

  1. 消费者Subsriber订阅生产者Publisher

  2. Publisher有内容了会调用Sub.onSubsribe()

  3. Subsriber请求Pub.request(n)

  4. Publisher请求Sub.onNext(data)

1.3 流式系统的挑战

  1. 分布式环境更加复杂

  2. 系统中每一层子系统都需要具备背压处理能力

二. Storm反压

  1. 每个Bolt都有一个Backpressure线程检测是否有recv queue是否有阻塞

  2. 如果有阻塞就会把情况写入zk

  3. 其他Spout会监听zk,收到反压情况就会停止发送

三. SparkStreaming反压

  1. 有Fetcher模块实时从Buffer、Processing等节点中收集指标,然后给PID Controller来计算速率,告知Receiver来调整速度

  2. Receiver -> Buffer -> Processing -> PID Controller

  3. PID (Proportional Integral Derivative,比例积分差分控制算法)

四. Flink反压

4.1 基础知识

  1. 发送端ResultPartition

  2. 接收端InputGate

  3. 都从LocalBufferPool申请空间,task级别

  4. LocalBufferPool从NetworkBufferPool申请空间,TaskManager级别

4.2 基础流程

写(Producer)

  1. Task.RecordWriter -> ResultPartition

  2. ResultPartition -> Netty

  3. Netty -> Socket

读(Consumer)

  1. Task.RecordReader <- InputGate

  2. InputGate <- Netty

  3. Netty <- Socket

4.3 1.5之前基于TCP滑动窗口feedback反压(自然背压)

生产者速度大于消费者

1.Consumer处理不过来,InputGate满了

2.InputGate从LBP获取buffer

3.LBP从NBP获取buffer

4.过了段时间IC满->LBP满->NBP满,IC关掉Netty读取,Netty关掉Socket读取

5.过滤段时间Socket的buffer没有消费也满了,通过tcp feedback(window=0)ack给Sender

6.过了一会Sender的buffer也满了

7.Netty写不进去,当Netty的水位到了上界就不可写

8.RS就无法写入数据到Netty,然后不断从LBP、NBP申请buffer直至申请满了

缺点

  1. 任何一个下游任务背压的时候,整个TM的链路都会受影响

  2. 流控链路太长,反压生效延迟大

  3. tcp做流控会阻塞tcp通信,导致比如checkpoint barrier无法发出

4.4 1.5+ Credit Based反压

1. Producer的RP向Consumer的IG发送消息的时候会带上backlog size告诉下游准备发送多少消息

2. 下游Consumer会返回相应的credit告诉Producer可以发送多少

3. 当消费端有Buffer可用的时候会有探测机制告知Sender恢复发送数据

优点

  1. 实现任务级背压,只会影响这个任务,不会影响TM的其他任务

  2. 链路减短,延时降低

  3. 不会阻塞Socket

参考

blog.csdn.net/baichoufei9…