1 回答
即使有状态函数,底层 Flink 作业的拓扑结构在作业启动时也是固定的。每个有状态的函数作业都使用或多或少像这样的作业图(入口各不相同,但其余的总是这样):
在这里,您可以看到所有加载的入口都成为 Flink 源操作符发出输入消息,路由器成为链接到这些源的平面图操作符。
充当路由器的平面图将输入消息转换为内部事件信封,它本质上只是将消息有效负载与其目标逻辑地址包装在一起。信封是流经流图的所有消息的在线数据类型。Stateful Functions 运行时以函数调度器运算符为中心,该运算符跨所有模块运行所有已加载函数的实例。
在路由器平面图操作符和函数调度器操作符之间是一个 keyBy 操作,它使用目标目的地id
作为键对输入流进行重新分区。这种网络洗牌保证所有用于给定的消息id
都发送到函数调度操作符的同一个实例。
收到后,函数调度程序从信封中提取目标函数地址,加载该函数实例,然后使用包装的输入(也在信封中)调用该函数。
函数调度器的不同实例如何相互发送消息?
这是通过将每个函数调度器与反馈运算符放在一起来完成的。所有传出消息都使用目标函数id
作为键通过另一个网络洗牌。
此反馈运算符在作业图中创建一个循环或迭代。有状态函数在其消息传递模式中可以有循环或循环,并且不限于使用 DAG 处理数据。
反馈通道有检查点;在失败的情况下消息永远不会丢失。
有关这方面的更多信息,我推荐 Tzu-Li (Gordon) Tai 的 Flink Forward 演讲:Stateful Functions: Polyglot Event-Driven Functions for Stateful Distributed Applications。上图来自他的演讲。