[In A Word]In A Word章9 Flink 的WaterMark

watermark是一种衡量Event Time进展的机制,它是数据本身的一个隐藏属性。通常基于Event Time的数据,自身都包含一个timestamp.watermark是用于处理乱序事件的,而正确的处理乱序事件,通常用watermark机制结合window来实现

 

window的触发要符合以下几个条件:

  1. watermark时间 >= window_end_time
  2. 在[window_start_time,window_end_time)中有数据存在

同时满足了以上2个条件,window才会触发。


watermark是一个全局的值,不是某一个key下的值,所以即使不是同一个key的数据,其warmark也会增加.

 

 

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设置使用 EventTime 作为时间戳(默认是 ProcessingTime)
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
// 开启 Checkpoint(每 10 秒保存一次检查点,模式为 Exactly Once)
env.enableCheckpointing(10000);
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
// 设置从 Kafka 的 topic "log.orderlog" 中读取数据
MYKafkaConsumer08 consumer = new MYKafkaConsumer08(jobName);
DataStream<String> stream = env.addSource(consumer.getInstance("log.orderlog", new SimpleStringSchema()));

// 默认接上次开始消费,以下的写法(setStartFromLatest)可以从最新开始消费,相应的还有(setStartFromEarliest 从最旧开始消费)
// DataStream<String> stream = env.addSource(consumer.getInstance("log.orderlog", new SimpleStringSchema()).setStartFromLatest());

DataStream<String> orderAmount =
// 将读入的字符串转化为 OrderRecord 对象
stream.map(new ParseOrderRecord())
// 设置从 OrderRecord 对象中提取时间戳的方式,下文 BoundedOutOfOrdernessGenerator 类中具体实现该方法
.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessGenerator())
// 用 OrderRecord 对象的 action 字段进行分流(相同 action 的进入相同流,不同 action 的进入不同流)
.keyBy("action")
// 触发 10s 的滚动窗口,即每十秒的数据进入同一个窗口
.window(TumblingEventTimeWindows.of(Time.seconds(10)))
// 将同一窗口的每个 OrderRecord 对象的 count 字段加起来(其余字段只保留第一个进入该窗口的,后进去的丢弃)
.sum("count")
// 将结果从 OrderRecord 对象转换为 String,每十万条输出一条
.flatMap(new ParseResult());
// 如果想每条都输出来,那就输得慢一点,每 10 秒输出一条数据(请将上一行的 flatMap 换成下一行的 map)
// .map(new ParseResultSleep());

// 输出结果(然后就可以去 Task Manage 的 Stdout 里面看)
// 小数据量测试的时候可以这么写,正式上线的时候不要这么写!数据量大建议还是写到 Kafka Topic 或者其他的下游里面去
orderAmount.print();
env.execute(jobName);
}

public static class ParseOrderRecord implements MapFunction<String, OrderRecord>{

@Override
public OrderRecord map(String s) throws Exception {
JSONObject jsonObject = JSON.parseObject(s); long id = jsonObject.getLong("id"); int dealId = jsonObject.getInteger("dealid");
String action = jsonObject.getString("_mt_action"); double amount = jsonObject.getDouble("amount");
String timestampString = jsonObject.getString("_mt_datetime");

// 将字符串格式的时间戳解析为 long 类型,单位毫秒
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date timestampDate = simpleDateFormat.parse(timestampString);

long timestamp = timestampDate.getTime();

return new OrderRecord(id, dealId, action, amount, timestamp);
}

 public static class BoundedOutOfOrdernessGenerator implements AssignerWithPeriodicWatermarks<OrderRecord> {      
  private final long maxOutOfOrderness = 3500; // 3.5 seconds         private long currentMaxTimestamp;      
  @Override         public long extractTimestamp(OrderRecord record, long previousElementTimestamp) {      
      // 将数据中的时间戳字段(long 类型,精确到毫秒)赋给 timestamp 变量,此处是 OrderRecord 的 timestamp 字段             long timestamp = record.timestamp;             currentMaxTimestamp = Math.max(timestamp, currentMaxTimestamp);       
     return timestamp;         }      
  @Override         public Watermark getCurrentWatermark() {        
    // return the watermark as current highest timestamp minus the out-of-orderness bound             return new Watermark(currentMaxTimestamp - maxOutOfOrderness);         }



posted on 2019-09-05 11:33  深圳私塾  阅读(247)  评论(0编辑  收藏  举报

导航