Apache Flink:在MapReduce()中正确地进行异步Web服务调用

时间:2017-10-10 05:15:48

标签: java apache-flink

我的程序具有以下mapPartition功能:

public void mapPartition(Iterable<Tuple> values, Collector<Tuple2<Integer, String>> out)

我从输入的values&amp;将它们发送到Web服务进行转换。我将结果添加回out集合。

为了加快这一过程,我通过使用async进行了网络服务调用Executors。这会产生问题,要么是taskManager released exception,要么AskTimeoutException。我增加了记忆力超时,但它没有帮助。有很多输入数据。我相信这导致很多工作排在ExecutorService&amp;因此占用了大量的内存。

最好的方法是什么?

我也在查看taskManager vs taskSlot配置,但对两者之间的差异感到有些困惑(我猜它们与进程vs线程相似?)。我不确定在什么时候增加taskManagers vs taskSlots?例如如果我有三台机器,每台机器4cpus,那么我的taskManager=3应该taskSlot=4吗?

我还在考虑单独增加mapPartition的并行性来说10以获得更多线程来访问网络服务。评论或建议?

1 个答案:

答案 0 :(得分:2)

您应该查看Flink Asyncio,这样您就可以在流应用程序中以异步方式查询您的Web服务。

有一点需要注意的是,Asyncio函数不是多线程的,并且每个分区的每个记录按顺序调用一次,因此您的Web应用程序需要确定性地返回并且可能快速返回,以使作业不被阻止。

此外,可能更多的分区可以帮助您的情况,但您的网络服务需要再次足够快地满足这些请求

Flinks网站的示例代码块:

// This example implements the asynchronous request and callback with Futures that have the
// interface of Java 8's futures (which is the same one followed by Flink's Future)

/**
 * An implementation of the 'AsyncFunction' that sends requests and sets the callback.
 */
class AsyncDatabaseRequest extends RichAsyncFunction<String, Tuple2<String, String>> {

/** The database specific client that can issue concurrent requests with callbacks */
private transient DatabaseClient client;

@Override
public void open(Configuration parameters) throws Exception {
    client = new DatabaseClient(host, post, credentials);
}

@Override
public void close() throws Exception {
    client.close();
}

@Override
public void asyncInvoke(final String str, final AsyncCollector<Tuple2<String, String>> asyncCollector) throws Exception {

    // issue the asynchronous request, receive a future for result
    Future<String> resultFuture = client.query(str);

    // set the callback to be executed once the request by the client is complete
    // the callback simply forwards the result to the collector
    resultFuture.thenAccept( (String result) -> {

        asyncCollector.collect(Collections.singleton(new Tuple2<>(str, result)));

    });
  }
}

// create the original stream (In your case the stream you are mappartitioning)
DataStream<String> stream = ...;

// apply the async I/O transformation
DataStream<Tuple2<String, String>> resultStream =
AsyncDataStream.unorderedWait(stream, new AsyncDatabaseRequest(), 1000, TimeUnit.MILLISECONDS, 100);

编辑:

由于用户想要创建大小为100的批次,asyncio目前特定于Streaming API,因此最好的方法是创建大小为100的countwindows。

此外,要清除可能没有100个事件的最后一个窗口,自定义Triggers可以与计数触发器和基于时间的触发器结合使用,以便触发器在元素计数之后或每几个触发后触发分钟。

此处Flink Mailing List提供了一个很好的跟进,用户“Kostya”创建了一个可用的自定义触发器here