我正在使用private SemaphoreSlim semaphore = new SemaphoreSlim(1);
private (CancellationTokenSource cts, Task task)? state;
private async Task RestartAsync()
{
Task task = null;
await this.semaphore.WaitAsync();
try
{
if (this.state.HasValue)
{
this.state.Value.cts.Cancel();
this.state.Value.cts.Dispose();
try
{
await this.state.Value.task;
}
catch (OperationCanceledException)
{
}
this.state = null;
}
var cts = new CancellationTokenSource();
task = DoSomethingAsync(cts.Token);
this.state = (cts, task);
}
finally
{
this.semaphore.Release();
}
try
{
await task;
}
catch (OperationCanceledException)
{
}
}
在Flink中执行流计算。我为我的工作定义了一个扩展BroadcastState
的类。假设我有一个以KeyedBroadcastProcessFunction
为键的流A,和一个流B,该流广播给所有执行者,以使用我定义的类处理A中的元素。我知道我可以在此类中的(user_id, location)
或processBroadcastElement
中注册一个计时器,以便在超时时可以通过调用processElement
来删除特定键组的关联状态。我不知道在那之后,这个关键小组还存在吗?
例如,在流A中,state.clear()
附带了一条新消息,并且我们生成了这样的密钥组及其关联状态。之后,如果出现另一条带有(user_id=1, location='usa')
的消息,它将触发(user_id=1, location='usa')
并发出结果。
说24小时后,我不再对这个密钥组processElement()
感兴趣,我可以注册一个计时器来清除关联的状态,但是我无法控制这个密钥组。结果,在24小时之后,当另一个带有(user_id=1, location='usa')
的消息出现时,由于此密钥组仍然存在,因此(user_id=1, location='usa')
仍将被调用。在作业运行时,尽管它们的关联状态将在24小时后清除,但是密钥组会累积还是不应该与内存使用有关?
相关博客:https://www.da-platform.com/blog/a-practical-guide-to-broadcast-state-in-apache-flink
答案 0 :(得分:0)
Flink的键控状态组织为分布式(或分片)键值存储,其中键可以是简单的东西,例如整数和字符串,也可以是复合词,例如(user_id = 1,location ='usa')。 密钥组与复合密钥不同。密钥组是Flink 1.2中引入的运行时构造(请参见FLINK-3755),以允许有效地重新缩放键值状态。密钥组是密钥空间的子集,并被检查点作为一个独立的单元。在运行时,同一密钥组中的所有密钥在作业图中被分区在一起-每个子任务具有一个或多个完整密钥组的密钥值状态。该design doc提供了更多详细信息。作为使用DataStream API的用户,键组是实现细节,而不是您直接使用的东西。
对于KeyedBroadcastProcessFunction
中的计时器,可以在processElement
或onTimer
方法中注册,但不能在processBroadcastElement
方法中注册。这是因为计时器始终与某个键相关联,并且没有与广播元素相关联的键。但是,可以通过使用processBroadcastElement
对象上的applyToKeyedState
方法在KeyedBroadcastProcessFunction.Context
方法期间操纵任何或所有键控状态。有关更多详细信息,请参见docs。
一旦调用state.clear(),该键的状态条目将被删除。当然,该键的新流事件可能会在状态清除后到达,并且您可以根据需要再次存储该键的值状态。为了避免由于不再使用不再相关的键而保留状态,从而避免了无限制的内存使用,您需要特别小心。您可能希望这样的逻辑在每次创建状态后24小时使状态失效:
processElement:
if state.value() is null, register timer
state.update(...)
onTimer:
state.clear()
或者您可能需要更复杂的逻辑来延长状态的寿命,无论何时更新或访问状态。
另一种选择是使用state time-to-live功能。
更新:
无论何时使用任何ProcessFunction类型的processElement
或onTimer
方法,上下文中都会隐式存在一个特定键,并且对键状态所做的所有操作(例如.update()
或.clear()
)将仅影响该键的状态。
广播状态的工作方式有所不同。广播状态始终为MapState,并被复制到所有并行子任务中。广播状态是无密钥的-如果您在processElement
方法期间读取广播状态,则无论该调用期间上下文中有什么密钥,您都将看到相同的广播状态值。
只有在processBroadcastElement
的{{1}}方法中,您才能修改(或清除)广播状态,并且重要的是,所有修改(或删除)都必须以相同的方式进行。并行实例。这样设计是为了确保每个并行实例在广播状态下都具有相同的内容。忽略此规则将导致状态不一致,这可能很难调试。有关更多信息,请参见the docs。
所以是的,如果您在广播状态下调用.clear(),那么所有键的所有广播状态都将被删除。或者,您可以从广播状态中删除特定项目(请记住,广播状态为MapState),在这种情况下,将针对所有键删除该特定项目。
在Flink培训站点中有几个使用广播状态的示例。见