这是我参与「第四届青训营 」笔记创作活动的的第7天
今天,我们来讨论流计算系统中的死锁问题。
流计算过程死锁分析
一般情况下之所以会出现“死锁”,主要是因为我们使用锁的方式不对,比如使用了不可重入锁,或者使用多个锁时出现了交叉申请锁的情况。这种情况下出现的“死锁”问题,我们确确实实看到了“锁”的存在。
但当我们在使用流计算编程时,会发现“流”的编程方式已经非常自然地避免了“锁”的使用,也就是说我们并不会在“流”处理的过程中用到“锁”。这是因为,当使用“流”时,被处理的对象依次从上游流到下游。当对象在流到某个步骤时,它是被这个步骤的线程唯一持有,因此不存在对象竞争的问题。
但这是不是就说流计算过程中不会出现“死锁”问题呢?也不是。
所以,为什么会出现“死锁”呢?这里就需要我们仔细分析下了。下面的图 3 描绘了图 2 中的流计算过程之所以会发生死锁的原因。
假设整个流计算过程有 A 和 B 这两个步骤,并且具备“反向压力”能力。这时候,如果 A 的输出已经将 B 的输入队列占满,而 B 的输出又需要重新流向 B 的输入队列,那么由于“反向压力”的存在,B 会一直等到其输入队列有空间可用。而 B 的输入队列又因为 B 在等待,永远也不会有空间被释放,所以 B 会一直等待下去。同时,A 也会因为 B 的输入队列已满,由于反向压力的存在,它也只能不停地等待下去。
如此一来,整个流计算过程就形成了一个死锁,A 和 B 两个步骤都会永远等待下去,这样就出现死锁。
如何避免死锁
所以,我们在流计算过程中,应该怎样避免死锁呢?其实很简单,有三种方法。
一是不使用反向压力功能。只需要我们不使用反向压力功能,即使业务形成“环”了,也不会死锁,因为每个步骤只需要将其输出放到输入队列中,不会发生阻塞等待,所以就不会死锁了。
二是我们在设计业务流程时,不要将业务流程设计成“有环”的了。
三是不要让多个步骤使用相同的队列或执行器。
总的来说,在流计算过程中,反向压力功能是必不可少的,为了避免“死锁”的问题,流计算过程中的任何一个步骤,它的输出绝不能再重新流回作为它的输入。
只需要注意以上几点就可以不用考虑“锁”的问题。也可以给程序带来显著的性能提升。