我有一个Flink流应用程序,该应用程序需要能够在特定键控流上“暂停”和“取消暂停”处理。 “处理”意味着仅对流执行一些简单的异常检测。
我们正在考虑的流程如下:
ProcessCommand
,PauseCommand
或ResumeCommand
的命令流,每个命令流都带有一个id
,用于KeyBy
。
ProcessCommands
将在处理密钥之前检查密钥是否已暂停,如果没有,则进行缓冲。
PauseCommands
将暂停密钥的处理。
ResumeCommands
将取消暂停键的处理并刷新缓冲区。
这种流程看起来合理吗?如果可以,我是否可以使用类似split
的运算符来实现?
示例流,省略了单个记录时间戳:
[{command: process, id: 1}, {command: pause, id: 1}, {command: process, id: 1}, {command: resume, id: 1}, {command: process, id: 1}]
Flow:
=>
{command: process, id: 1} # Sent downstream for analysis
=>
{command: pause, id: 1} # Starts the buffer for id 1
=>
{command: process, id: 1} # Buffered into another output stream
=>
{command: resume, id: 1} # Turns off buffering, flushes [{command: process, id: 1}] downstream
=>
{command: process, id: 1} # Sent downstream for processing as the buffering has been toggled off
答案 0 :(得分:1)
可以使用Flink's Window operator来实现。首先,通过应用POJO
操作来创建基于tuple
或map
的流。
然后,根据您的需要,您可以在该流上使用keyBy
来获得keyedStream
。
现在,通过结合使用基于时间的无限window
,trigger
和window function
,您可以实现命令流的切换行为。
基本上,您可以将windows
用作缓冲区,该缓冲区在接收到暂停记录后将保留过程记录,直到接收到恢复记录为止。您将要编写一个自定义触发器,该触发器将根据您的情况逐出窗口(缓冲区)。
以下是Trigger
具有onElement()
被覆盖方法的自定义实现。
/**
* We trigger the window processing as per command inside the record. The
* process records are buffered when a pause record is received and the
* buffer is evicted once resume record is received. If no pause record is
* received earlier, then for each process record the buffer is evicted.
*/
@Override
public TriggerResult onElement(Tuple2<Integer, String> element, long timestamp, Window window,
TriggerContext context) throws Exception {
if (element.f1.equals("pause")) {
paused = true;
return TriggerResult.CONTINUE;
} else if (element.f1.equals("resume")) {
paused = false;
return TriggerResult.FIRE_AND_PURGE;
} else if (paused) // paused is a ValueState per keyed stream.
return TriggerResult.CONTINUE;
return TriggerResult.FIRE_AND_PURGE;
}
中查看完整的工作示例