OrderedStreamElementQueue - 潜在的死锁

时间:2017-05-04 14:18:55

标签: java asynchronous apache-flink

在订购模式下使用AsyncFunc时,我似乎遇到了死锁。

我已经能够将此错误转载如下:

import org.apache.flink.streaming.api.datastream.AsyncDataStream;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.async.AsyncFunction;
import org.apache.flink.streaming.api.functions.async.collector.AsyncCollector;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AsyncTest {

    @Test
    public void test() throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        DataStream<Integer> source = env.fromCollection(Arrays.asList(1,2,3,4,5,6,7));

        AsyncDataStream.orderedWait(source,
                new AsyncFunction<Integer, String>(){
                    @Override
                    public void asyncInvoke(Integer integer, AsyncCollector<String> asyncCollector) throws Exception {
                           AsyncTest.getFuture(integer).whenComplete((t,m) -> {
                               if (m==null){
                                   asyncCollector.collect(Collections.singleton(t));
                                   return;
                               }
                               asyncCollector.collect(m);
                           });
                    }
                }, 20000, TimeUnit.MILLISECONDS,5)
                .returns(String.class)
                .print();
        env.execute("unit-test");
    }

    static CompletableFuture<String> getFuture(Integer input) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {

            }
            if (input == 7){
                System.out.println("Returning");
                return "ok";
            }
            System.out.println("Waking up");
            throw new RuntimeException("test");
        },new ScheduledThreadPoolExecutor(10));
    }
}

我认为这种僵局可能来自于 OrderedStreamElementQueue 的基础 ArrayQueue 首先被不完整的未来填满。

发射器试图从此队列中查看时,由于没有完成任何未来,发射器会暂停其执行。

当期货完成时,它们会异常完成,因此不会触发应该在 headIsCompleted 上调用signalAll的 onCompleteHandler 方法(并因此唤醒发射器线程)

同时,当队列已满时,对 orderedStreamElement tryPut 的任何调用都会返回false,因此没有 StreamElementQueueEntry 可以通过调用 onCompleteHandler 进行链接。

所以,似乎Emitter线程无法被唤醒。

这只是我的猜测。也许我弄错了。但是当我在本地运行上面的代码时,执行永远不会结束。

除了增加队列的容量和/或作业的并行性之外,有没有办法克服这个问题?

1 个答案:

答案 0 :(得分:1)

您的分析是正确的。问题是StreamElementQueueEntry没有对其未来的特殊完成做出反应。因此,每当发生超时或其他异常时,StreamElementQueueEntry未正确设置为已完成,并且Emitter未收到有关新完成条目的通知。

FLINK-6435修复了问题,该问题已合并到Flink主页。