Parallel processing ApacheFlink:如何并行执行但保持消息的顺序?
关于flink的平行性,我有几个问题。这是我的设置: 我有1个主节点和2个从节点。在弗林克,我创建了3个卡夫卡消费者,每个消费者都来自不同的主题。Parallel processing ApacheFlink:如何并行执行但保持消息的顺序?,parallel-processing,apache-kafka,apache-flink,Parallel Processing,Apache Kafka,Apache Flink,关于flink的平行性,我有几个问题。这是我的设置: 我有1个主节点和2个从节点。在弗林克,我创建了3个卡夫卡消费者,每个消费者都来自不同的主题。 因为元素的顺序对我很重要,所以每个主题只有一个分区,我有flink设置来使用事件时间 然后,我在每个数据流上运行以下管道(伪代码): source .map(deserialize) .window .apply .map(serialize) .writeTo(sink) 到目前为止,我使用参数-p2启动了我的flink程序,假设这将允许我同时使
因为元素的顺序对我很重要,所以每个主题只有一个分区,我有flink设置来使用事件时间 然后,我在每个数据流上运行以下管道(伪代码):
source
.map(deserialize)
.window
.apply
.map(serialize)
.writeTo(sink)
到目前为止,我使用参数-p2
启动了我的flink程序,假设这将允许我同时使用两个节点。结果并不是我所希望的,因为我的输出顺序有时会混乱
在阅读完flink文档并试图更好地理解它之后,有人能确认我的以下“经验教训”吗
1.)传递-p2
仅配置任务并行性,即任务(如map(反序列化)
)将拆分为的最大并行实例数。如果我想在整个管道中保持顺序,我必须使用-p1
2.)在我看来,这似乎是矛盾的/令人困惑的:即使并行度设置为1,不同的任务仍然可以并行运行(同时)。因此,如果我通过-p1
,我的3条管道也将并行运行
作为后续问题:有没有办法找出哪些任务映射到哪个任务槽,以便我自己确认并行执行
如果您有任何意见,我将不胜感激
更新
这是弗林克对
-p2
的执行计划,我将试着用我所知道的回答
1) 是的,对于CLI客户端,parallelism参数可以用-p指定。您可以说这是并行实例的最大数量。但是,我看不到并行性和顺序之间的联系?据我所知,顺序由Flink使用事件中提供的时间戳或他自己的摄取时间戳进行管理。如果您希望在不同的数据源中保持秩序,这对我来说似乎很复杂,或者您可以将这些不同的数据源合并为一个
2) 如果将“并行度”设置为3,则3条管道可以并行运行。我认为这里的“并行度”指的是不同插槽上的并行
后续问题)您可以检查哪些任务映射到JobManager的web前端上的哪个任务槽。在上问完问题后,以下是答案: 1.
-p
选项定义每个作业的任务并行度。如果选择的并行度高于1,并且数据被重新分配(例如通过重新平衡()或keyBy()),则不能保证顺序
2.)当-p
设置为1时,仅使用1个任务插槽,即1个CPU内核。因此,可能有多个线程同时在一个内核上运行,但不能并行运行
至于我的要求:为了并行运行多个管道并保持顺序,我可以只运行多个Flink作业,而不是在同一Flink作业中运行所有管道。请在下面找到一个使用侧输出和插槽组进行局部缩放的示例
package org.example
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.flink.streaming.api.functions.ProcessFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.util.Collector
/**
* This example shows an implementation of WordCount with data from a text socket.
* To run the example make sure that the service providing the text data is already up and running.
*
* To start an example socket text stream on your local machine run netcat from a command line,
* where the parameter specifies the port number:
*
* {{{
* nc -lk 9999
* }}}
*
* Usage:
* {{{
* SocketTextStreamWordCount <hostname> <port> <output path>
* }}}
*
* This example shows how to:
*
* - use StreamExecutionEnvironment.socketTextStream
* - write a simple Flink Streaming program in scala.
* - write and use user-defined functions.
*/
object SocketTextStreamWordCount {
def main(args: Array[String]) {
if (args.length != 2) {
System.err.println("USAGE:\nSocketTextStreamWordCount <hostname> <port>")
return
}
val hostName = args(0)
val port = args(1).toInt
val outputTag1 = OutputTag[String]("side-1")
val outputTag2 = OutputTag[String]("side-2")
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.getConfig.enableObjectReuse()
//Create streams for names and ages by mapping the inputs to the corresponding objects
val text = env.socketTextStream(hostName, port).slotSharingGroup("processElement")
val counts = text.flatMap {
_.toLowerCase.split("\\W+") filter {
_.nonEmpty
}
}
.process(new ProcessFunction[String, String] {
override def processElement(
value: String,
ctx: ProcessFunction[String, String]#Context,
out: Collector[String]): Unit = {
if (value.head <= 'm') ctx.output(outputTag1, String.valueOf(value))
else ctx.output(outputTag2, String.valueOf(value))
}
})
val sideOutputStream1: DataStream[String] = counts.getSideOutput(outputTag1)
val sideOutputStream2: DataStream[String] = counts.getSideOutput(outputTag2)
val output1 = sideOutputStream1.map {
(_, 1)
}.slotSharingGroup("map1")
.keyBy(0)
.sum(1)
val output2 = sideOutputStream2.map {
(_, 1)
}.slotSharingGroup("map2")
.keyBy(0)
.sum(1)
output1.print()
output2.print()
env.execute("Scala SocketTextStreamWordCount Example")
}
}
package org.example
/*
*向Apache软件基金会(ASF)授权
*一个或多个参与者许可协议。请参阅通知文件
*与此工作一起分发以获取更多信息
*关于版权所有权。ASF许可此文件
*根据Apache许可证,版本2.0(
*“许可证”);除非符合规定,否则不得使用此文件
*使用许可证。您可以通过以下方式获得许可证副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*除非适用法律要求或书面同意,软件
*根据许可证进行的分发是按“原样”进行分发的,
*无任何明示或暗示的保证或条件。
*请参阅许可证以了解管理权限和权限的特定语言
*许可证下的限制。
*/
导入org.apache.flink.streaming.api.functions.ProcessFunction
导入org.apache.flink.streaming.api.scala_
导入org.apache.flink.util.Collector
/**
*此示例显示了使用文本套接字中的数据实现WordCount。
*要运行该示例,请确保提供文本数据的服务已启动并正在运行。
*
*要在本地计算机上启动示例套接字文本流,请从命令行运行netcat,
*其中,参数指定端口号:
*
* {{{
*nc-LK9999
* }}}
*
*用法:
* {{{
*SocketTextStreamWordCount
* }}}
*
*此示例显示了如何:
*
*-使用StreamExecutionEnvironment.socketTextStream
*-用scala编写一个简单的Flink流媒体程序。
*-编写和使用用户定义的函数。
*/
对象SocketTextStreamWordCount{
def main(参数:数组[字符串]){
如果(参数长度!=2){
System.err.println(“用法:\nSocketTextStreamWordCount”)
返回
}
val hostName=args(0)
val端口=args(1).toInt
val outputTag1=OutputTag[字符串](“第1面”)
val outputTag2=OutputTag[字符串](“第2面”)
val env=StreamExecutionEnvironment.getExecutionEnvironment
env.getConfig.enableObjectReuse()
//通过将输入映射到相应的对象,为名称和年龄创建流
val text=env.socketTextStream(主机名、端口).slotSharingGroup(“processElement”)
val计数=text.flatMap{
_.toLowerCase.split(\\W+)筛选器{
_.非空
}
}
.process(新的ProcessFunction[字符串,字符串]{
重写def processElement(
值:字符串,
ctx:ProcessFunction[String,String]#上下文,
输出:收集器[字符串]:单位={
如果(value.head)我上传了我的flink程序的执行计划,在那里你可以看到有一个reba