我们使用Beam的Java SDK 2.0.0在ParDo中生成顺序索引。就像Beam introduction to stateful processing中的简单有状态索引示例一样,我们使用ValueState<Integer>
单元格,我们唯一的操作是在需要下一个索引时检索值和增量:
Integer statefulIndex = firstNonNull(index.read(), 0);
index.write(statefulIndex + 1);
当使用Google的Dataflow运行程序运行时,我们在Dataflow监控界面上注意到该ParDo的挂起时间与已用时间同步累积。我们能够确认ParDo通过ssh进入工作节点并使用top
和1
来查看每个核心的CPU使用情况来执行单线程。注释掉有状态处理单元并保持代码不变,相同的ParDo使用我们n1-standard-32
工作节点的所有内核。
即使Dataflow运行器能够根据每个键和窗口对(我们当前有一个窗口和一个键)并行化有状态索引,缺乏并行性会导致性能显着下降,我们无法使用它。这是Dataflow运行器的预期行为吗?
天真地,我预计在幕后,Beam的有状态索引将与Java的AtomicInteger
类似地运行。是否存在阻止使用ValueState<Integer>
单元格进行并行处理的约束,或者此功能尚未内置于运行程序中?
答案 0 :(得分:1)
这不仅是Dataflow运行器的预期行为,而且是任何上下文中的逻辑必需品。如果您在Beam中使用状态或在单进程Java程序中使用AtomicInteger
,则无关紧要:如果操作&#34; A&#34;写一个值和操作&#34; B&#34;读取值,然后&#34; B&#34;必须在&#34; A&#34;之后执行。对此的共同术语是关系是&#34;发生之前&#34;。
这种有状态计算形式与并行计算相反。根据定义,观察写入的读取具有因果关系。根据定义,两个并行的操作没有因果关系。
现在,您可能期望并发线程同时访问状态单元,如多线程编程的标准模式以及具有并发控制的某些共享状态。对于此示例,如果这些线程实际上是并行的,则会获得重复索引。退后一步,Beam瞄准了大规模的&#34;令人尴尬的平行&#34;计算透明地分布在大型机器集群中。细粒度的并发控制除了极难实现之外,还不能轻易转化为大规模的分布式计算。