Parallel processing 具有自定义源的Flink工作流并行性

Parallel processing 具有自定义源的Flink工作流并行性,parallel-processing,apache-flink,Parallel Processing,Apache Flink,我有一个用Flink构建的工作流,它由一个自定义源、一系列地图/平面地图和一个接收器组成 我的自定义源的run()方法遍历存储在文件夹中的文件,并通过上下文的collect()方法收集每个文件的名称和内容(我有一个自定义对象,它将此信息存储在两个字段中) 然后,我有一系列地图/平面地图转换这些对象,然后使用自定义接收器将其打印成文件。在Flink的Web UI中生成的执行图如下所示: 我有一个集群或两个worker,每个都有6个插槽(它们都有6个内核)。我将平行度设置为12。从执行图中,我看到

我有一个用Flink构建的工作流,它由一个自定义源、一系列地图/平面地图和一个接收器组成

我的自定义源的run()方法遍历存储在文件夹中的文件,并通过上下文的collect()方法收集每个文件的名称和内容(我有一个自定义对象,它将此信息存储在两个字段中)

然后,我有一系列地图/平面地图转换这些对象,然后使用自定义接收器将其打印成文件。在Flink的Web UI中生成的执行图如下所示:

我有一个集群或两个worker,每个都有6个插槽(它们都有6个内核)。我将平行度设置为12。从执行图中,我看到源代码的并行度为1,而工作流的其余部分的并行度为12

当我运行工作流时(我在专用文件夹中有大约15K个文件),我会使用htop监控我员工的资源。大多数情况下,所有磁芯的利用率都高达100%,但大约每30分钟左右,8-10个磁芯就会闲置约2-3分钟

我的问题如下:

  • 我知道源代码运行时具有并行性1,我认为从本地存储读取时这是正常的(我的文件位于每个工作进程中的同一目录中,因为我不知道将选择哪个工作进程来执行源代码)。这真的正常吗?你能解释一下为什么会这样吗

  • 我的工作流程的其余部分是使用parallelism 12执行的,这看起来是正确的,因为通过检查任务管理器的日志,我从所有插槽中得到了打印结果(例如,
    …[平面图->地图->地图->接收器:未命名(**3/12**)]信息……
    …[平面图->地图->地图->接收器:未命名(**5/12**)]信息……
    ,等等)。但我不明白的是,如果一个插槽正在执行源角色,而我的集群中有12个插槽,那么工作流的其余部分是如何由12个插槽执行的?一个插槽是否同时作用于工作流其余部分的源和一个实例?如果是,如何分配此特定插槽的资源?是否有人可以解释此工作流中正在进行的步骤?例如(这可能是错误的):

    • 插槽1读取文件并将其转发到可用插槽(2到12)
    • 插槽1将一个文件转发给它自己并停止读取,直到它完成其工作
    • 完成后,插槽1读取更多文件并将其转发到可用的插槽
    我相信我上面描述的是错误的,但我举个例子来更好地解释我的问题

  • 为什么大多数内核每30分钟(或多或少)就会有这种空闲状态,持续大约3分钟
  • 单一使用者设置将管道的总吞吐量限制为仅一个使用者的性能。此外,它还向所有插槽引入了重洗牌-在本例中,消费者读取的所有数据也在这个消费者插槽上序列化,这是一个额外的CPU负载。相反,让使用者并行性等于map/flat-map parallelsm将允许链接source->map操作并避免混乱
  • 默认情况下,Flink允许子任务共享插槽,即使它们是不同任务的子任务,只要它们来自同一个作业。结果是一个插槽可能容纳作业的整个管道。因此,在您的示例中,插槽1既有使用者任务,也有地图/平面地图任务,而其他插槽只有地图/平面地图任务。有关更多详细信息,请参见此处:。此外,您还可以在Web UI上查看每个子任务的实例
  • 是否启用了检查点?如果是,如果是30分钟,那么这可能就是状态快照的时间间隔

  • 为了回答关于并行化阅读的具体问题,我将执行以下操作

  • 通过扩展
    RichSourceFunction
    实现自定义源代码
  • open()
    方法中,调用
    getRuntimeContext().getNumberOfParallelSubtask()
    获取总并行度,并调用
    getRuntimeContext().getIndexOfThissSubtask()
    获取正在初始化的子任务的索引
  • run()
    方法中,当您迭代文件时,获取每个文件名的
    hashCode()
    ,对总并行度进行模化。如果这等于子任务的索引,则处理它

  • 通过这种方式,您可以将工作分散到12个子任务上,而无需子任务尝试处理同一个文件。

    谢谢您的回复。关于1)我想这是受访问本地存储的soource的使用限制的,对吗?不是我可以通过设置一个参数来增加它的并行性吗?如果我理解正确的话,如果我使用Kafka来存储对象(每个插槽订阅一个分区),我可以改进。但是对于本地存储,这是不可能的,对吗?关于2)这些子任务是否并行执行?如果我的消费者在某一特定点上处理map/flatmap子任务之一,它会并行地作为源服务于其余的任务,还是会被阻止直到完成?1)老实说,我没有处理过本地存储,但假设每个工作进程上都有类似的文件,如果可能的话,您可以通过将数据划分到不同的子文件夹来并行化源。或者,例如,根据子任务索引为每个子任务分配自己的工作状态。2) 是的,这些子任务是并行执行的,每个子任务都在自己的线程中执行。这些线程没有相互阻塞,除了内存缓冲区。@Mikalailushcytski很好地回答了所有问题。我只是补充一点,你应该在12的并行度下运行它。根据使用的
    InputFormat
    和文件,Flink能够将一个大文件分割成更小的块(约32 MB),甚至能够并行处理一个巨大的文件。