在 05 课时已经讲过,描述一个流计算过程使用的是 DAG,也就是“有向无环图”。对于“有向”,我们知道这是代表着流数据的流向。而“无环”又是指什么呢?为什么一定要是“无环”?

其实之所以要强调“无环”,是因为在流计算系统中,当“有环”和“反向压力”一起出现时,流计算系统将会出现“死锁”问题。

为什么流计算过程不能有环?

简单案例

简单的流计算过程
image.png
让 B 在处理完后,将其结果重新输入给自己再处理一次。
image.png
实际运行上面这段代码就会发现,只需要运行不到 1 秒钟,上面这段程序就会“卡”住
这是怎么回事呢?事实上这就是因为程序已经“死锁”了!

流计算过程死锁分析

下图描绘了流计算过程之所以会发生死锁的原因:
image.png
如此一来,整个流计算过程就形成了一个死锁,A 和 B 两个步骤都会永远等待下去,这样就出现了我们前边看到的程序“卡”住现象。

另一个案例

image.png
业务逻辑本来是 A 到 B 到 C 这样的“无环”图,结果由于我们给这三个不同的步骤,分配了同一个执行器 executor,实际实现的流计算过程就成了一个“有环”的过程。

如何避免死锁

一是不使用反向压力功能。只需要我们不使用反向压力功能,即使业务形成“环”了,也不会死锁,因为每个步骤只需要将其输出放到输入队列中,不会发生阻塞等待,所以就不会死锁了。但很显然,这种方法禁止使用。毕竟,没有反向压力功能,就又回到 OOM 问题了,这是万万不可的!

二是避免业务流程形成“环”。这个方法最主要的作用,是指导我们在设计业务流程时,不要将业务流程设计成“有环”的了。否则如果系统有反向压力功能的话,容易出现类似于图 3 的死锁问题。

三是千万不要让多个步骤使用相同的队列或执行器。这个是最容易忽略的问题,特别是一些对异步编程和流计算理解不深的开发人员,最容易给不同的业务步骤分配相同的队列或执行器,在不知不觉中就埋下了死锁的隐患。

总的来说,在流计算过程中,反向压力功能是必不可少的,为了避免“死锁”的问题,流计算过程中的任何一个步骤,它的输出绝不能再重新流回作为它的输入。

使用异步编程框架注意问题

  • 这个异步框架支持反向压力?没有不支持的话,是如何处理 OOM 问题的?
  • 这个异步框架会发生死锁吗?如果会死锁的话,是如何处理死锁问题的?