首页 笔记 图片 查字 
所属分类:Flink
浏览:37
内容:


参考:
https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/dev/table/concepts/determinism/

要点:
1. 什么是确定性?
引用 SQL 标准中对确定性的描述:“如果一个操作在重复相同的输入值时能保证计算出相同的结果,那么该操作就是确定性的”。
2. 批处理都是确定性的吗?
  - 两个非确定性结果的批查询示例
但实际上,同一个查询在批处理上也并不总是能得到一致的结果。
  - 批处理中的不确定性因素
批处理中的不确定性因素, 主要是由不确定函数造成的,上述两个查询示例中,内置函数 CURRENT_TIMESTAMP 和 UUID() 在批处理中的行为是有差异的。
这个差异是因为 Flink 继承了 Apache Calcite  对函数的定义,在确定性函数之外存在不确定函数(non-deterministic function)和动态函数(dynamic  function,  内置的动态函数以时间函数为主)两类,不确定函数会在运行时(即在集群执行,每条记录单独计算)确定对应的值,而动态函数仅在生成查询计划时确定对应的值, 运行时不再执行(不同时间执行得到不同的值,但同一次执行得到的值一致)。
3. 流上的确定性
流和批处理的一个核心区别是数据的无界性,Flink SQL 对流计算抽象为动态表上的连续查询(continuous query)。 因此批查询示例中的动态函数在流场景中(逻辑上每条基表记录的变更都会触发查询被执行)也就等效于不确定性函数。
  - 流上的不确定性
  除了不确定函数,流上其他可能产生不确定性的因素主要有:
  Source 连接器回溯读取的不确定性
  基于处理时间计算的不确定性
  基于 TTL 淘汰内部状态数据的不确定性
    - 流上的不确定更新
    什么是不确定更新(Non-deterministic Update, 简称 NDU)? 增量消息包含插入(Insert,简称 I)、删除(Delete,简称 D)、更新前(Update_Before,简称 UB),更新后(Update_After,简称 UA),在仅有插入类型增量消息的查询管道中不存在 NDU 问题。 在有更新消息(除 I 外还包含 D、UB、UA 至少一种消息)时,会根据查询推导消息的更新键(可视为变更日志的主键)。
    1、能推导出更新键时,管道中的算子通过更新键来维护内部状态。
    2、不能推导出更新键时(有可能 CDC 源表或 Sink 表就没定义主键,也可能从查询的语义上某些操作就推导不出来),所有的算子维护内部状态时只能通过比较完整的行来处理更新(D/UB/UA)消息, Sink 节点在没有定义主键时以 Retract 模式工作,按整行进行删除操作。 因此,在按行删除时,所有需要维护状态的算子收到的更新消息不能被不确定的列值干扰, 否则就会导致 NDU 问题造成计算错误。
    
    在有更新消息传递并且无法推导出更新键的链路上,以下三点是最主要的 NDU 问题来源:
    1、不确定函数(包括标量、表值、聚合类型的内置或自定义函数)
    2、在一个变化的源表上 Lookup Join
    3、CDC 源表携带了元数据字段(系统列,不属于实体行本身)
    - 如何消除流查询的不确定性影响
    流查询中的不确定更新(NDU)问题通常不是直观的,可能较复杂的查询中一个微小条件的改动就可能产生 NDU 问题风险,从 1.16 版本开始,Flink SQL (FLINK-27849)引入了实验性的 NDU 问题处理机制 ’table.optimizer.non-deterministic-update.strategy’, 当开启 TRY_RESOLVE 模式时,会检查流查询中是否存在 NDU 问题,并尝试消除由 Lookup Join  产生的不确定更新问题(内部会增加物化处理),如果还存在上述第 1 或 第 3 点因素无法自动消除,Flink SQL  会给出尽量详细的错误信息提示用户调整 SQL 来避免引入不确定性(考虑到物化带来的高成本和算子复杂性,目前还没有支持对应的自动解决机制)。