这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
Flink 1.10 在 SQL DDL 中增加了针对流处理定义时间属性及产生 watermark 的语法扩展(FLIP-66 [22])。这使得用户可以在用 DDL 语句创建的表上进行基于时间的操作(例如窗口)以及定义 watermark 策略,该篇内容记录了流计算程序在创建kafak连接过程中使用watermark定义水印的实例以及解读。
watermark 概念
在Flink中,水位线是一种衡量Event Time进展的机制,用来处理实时数据中的乱序问题的,通常是水位线和窗口结合使用来实现。
从设备生成实时流事件,到Flink的source,再到多个oparator处理数据,过程中会受到网络延迟、背压等多种因素影响造成数据乱序。在进行窗口处理时,不可能无限期的等待延迟数据到达,当到达特定watermark时,认为在watermark之前的数据已经全部达到(即使后面还有延迟的数据), 可以触发窗口计算,这个机制就是 Watermark(水位线)
注:图源flink官方网站,侵删。
水位线的计算
watermark本质上是一个时间戳,且是动态变化的,会根据当前最大事件时间产生。watermarks具体计算为
watermark = 进入 Flink 窗口的最大的事件时间(maxEventTime)— 指定的延迟时间(t)
当watermark时间戳大于等于窗口结束时间时,意味着窗口结束,需要触发窗口计算。
DDL中的使用
CREATE TABLE Orders (
`user` BIGINT,
product STRING,
order_time TIMESTAMP(3),
# 定义水印
WATERMARK FOR order_time AS order_time - INTERVAL '5' SECOND
) WITH (...);
WATERMARK
子句定义表的事件时间属性并采用WATERMARK FOR rowtime_column_name AS watermark_strategy_expression
这种格式。其中定义使用的字段是原表中中存在的并可以作为具有事件时间
属性的字段(可以来源meta)。字段必须是表中的一级字段,是可以被计算的字段,并且该字段的类型必须是TIMESTAMP(3),水印计算表达的返回值类型也必须是TIMESTAMP(3)。
样例
create table table (
`data` ARRAY<STRING>,
`es` BIGINT,
`old` ARRAY<MAP<STRING, STRING>>,
`table` STRING,
`type` STRING,
proctime AS PROCTIME(),
ts as TO_TIMESTAMP(FROM_UNIXTIME(`es`/1000,'yyyy-MM-dd HH:mm:ss')),
WATERMARK FOR ts AS ts - INTERVAL '6' HOUR
) with (
...
);
watermark 策略
-
严格意义上递增的时间戳,发出到目前为止已观察到的最大时间戳的水印。时间戳大于最大时间戳的行记录不会延迟计算。
WATERMARK FOR rowtime_column AS rowtime_column
-
递增的时间戳,发出到目前为止已观察到的最大时间戳-1毫秒的水印。时间戳等于或大于最大时间戳的行记录不会延迟计算。
WATERMARK FOR rowtime_column AS rowtime_column - INTERVAL '0.001' SECOND.
-
有界时间戳(乱序) 发出水印,它是观察到的最大时间戳减去指定的延迟,例如,WATERMARK FOR rowtime_column AS rowtime_column-INTERVAL'5' SECOND是5秒的延迟水印策略。
WATERMARK FOR rowtime_column AS rowtime_column - INTERVAL 'string' timeUnit.
所以案例中的是6小时延迟策略。
需要注意:
Flink目前不支持直接把Long类型的转成Timestamp类型的,如果你的数据源中ts是Long类型的时间戳,建表语句不能直接写成ts TIMESTAMP(3),如果想用timestamp类型的,数据源中的时间需要时UTC格式的.或者可以用案例上面那种写法,利用Flink的日期函数TO_TIMESTAMP把bigint类型的转成timestamp类型的.