繁体   English   中英

Java Flink外部源

[英]Java Flink External Source

我想要一个并行的Flink源,它从内存中的阻塞队列中消耗资源。 我的想法是让应用程序将元素推入此队列,然后Flink管道使用并处理它们。

最好的模式是什么? 我看过一些Flink源实现(例如Kafka,RabbitMQ等),所有这些都正在初始化源实例中所需的连接。 我不能这样做(即,从每个源实例中初始化队列),因为

  • 每个源实例实例将创建自己的队列。
  • 需要从Flink外部引用队列以将元素推送到该队列。

目前,我提出了以下建议,但是使用静态队列对我来说并不适合。

1.每个Flink源实例从其获取元素的队列。

public class TheQueue implements Serializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(TheQueue.class);

    private transient static final BlockingQueue<Object> OBJECT_QUEUE = new LinkedBlockingQueue<>();

    public static SerializableSupplier<Object> getObjectConsumer() {
        return () -> {
            return OBJECT_QUEUE.take();
        }
    };
}

2.我的Flink管道摘录。

final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();
env.setParallelism(10);
env.addSource(TestParallelSourceFunction.getInstance(TheQueue.getObjectConsumer()))

3. Flink源功能。

public class TestParallelSourceFunction<T> extends RichParallelSourceFunction<T>{

    private static final Logger LOGGER = LoggerFactory.getLogger(TestParallelSourceFunction.class);

    private SerializableSupplier<T> supplier;

    // initialisation code

    @Override
    public void run(final SourceContext<T> ctx) throws Exception {

        LOGGER.info("Starting Flink source.");
        isRunning = true;

        while (isRunning) {
            final T t = supplier.get();
            if (t != null) {
                ctx.collect(t);
            }
        }

        LOGGER.info("Stopped Flink source.");
    }

我认为,您对诸如Kafka和RabbitMQ之类的消息队列系统及其在流应用程序中的作用的理解存在缺陷。 它们是存在于Flink之外的独立服务。 Flink不会启动或配置它们,它只是打开连接以读取它们。

因此,我们的想法是启动一个Kafka集群,并为Flink作业和任何将元素推入Kafka的应用程序提供必要的连接详细信息和主题名称。 将元素推入队列的应用程序通过tcpip与Kafka集群通信,Flink也是如此。

问题是(据我所知)是Flink接收所有运算符并对其进行序列化,然后发送给“工人”以对其进行反序列化。 这就是为什么源通常在它们内部创建连接而没有接收外部连接的原因。

如果在流程(本地执行环境)中运行Flink管道,该怎么办就是创建一个扩展RichSource函数的类,该类具有一个ID作为可序列化字段,并且在ID与阻塞队列之间有一个静态映射。 它看起来像这样(在没有IDE的情况下编写它,因此语法可能会略有不同):

public class BlockingQueueSource<T> extends RichSourceFunction<T> {
  private static final Map<String, BlockingQueue<T>> idToQueue;

  private final String id;
  private volatile boolean isRunning;

  public BlockingQueueSource(String id) {
    this.id = id;
    this.isRunning = true;
  }

  @Override
  public void open(...) {
    idToQueue.put(id, new LinkedBlockingQueue<>());
  }

  public void close() {
    isRunning = false;
    idToQueue.remove(id);
  }

  public void run(SourceContext<T> context) {
    BlockingQueue<T> queue = idToQueue.get(id);

    while(isRunning) {
      T item = queue.take();

      context.collect(item);
    }
  }

  public void addItem(T item) {
    idToQueue.get(id).put(item);
  }
}

同样,这仅在源位于创建所有Flink管道的同一进程中时才有效,这意味着您在本地执行环境中运行它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM