flink实时流遇到的问题排查
- 1、技术和环境
- 2、问题表述
- 3、简化的代码
- 4、问题排查思路
- 5、结论
- 6、后续补充
1、技术和环境
技术:kafka、zookeeper、DataStream、redis
环境表述:kafka生产者KafkaProducerTest类mock 3条日志后,FlinkDataRealTimeFlowDeal类有建消费者,消费日志数据进行实时流DataStream处理,进行日志清洗、数据落库redis。
2、问题表述
理论上:
KafkaProducerTest生产者每次执行x条日志,消费者实际读取x条日志,实际落库x条处理结果。
实际:
(有问题)KafkaProducerTest生产者第1次执行3条日志,消费者实际读取3条日志,实际落库2条处理结果。
(正常)KafkaProducerTest生产者第2次执行之前的3条日志,消费者实际读取3条日志,实际落库3条处理结果。
(有问题)KafkaProducerTest生产者第3次执行之前的3条日志,消费者实际读取3条日志,实际落库2条处理结果。
(正常)KafkaProducerTest生产者第4次执行之前的3条日志,消费者实际读取3条日志,实际落库3条处理结果。
…
问题总结:奇数次执行时数据漏掉了1条没有落库,偶数次全部落库成功。
注意:每次执行的是相同的日志数据(测试用)。
3、简化的代码
DataStream.flatMap(进行日志清洗-Collector收集).keyBy(0).countWindow(2).reduce(进行聚合).process(进行redis落库)
4、问题排查思路
首先查看日志,发现:
进行【日志清洗-Collector收集】的方法:内部的错误日志信息打印处理了3次,符合要求,说明3条日志均进行了日志清洗。
然后,结合看方法:flatMap(String value, Collector<Tuple2<String, List>> out),flatMap扁平化得到的Collector是一个Tuple2<String, List类型的收集。
接着,keyby(0)后(以Tuple2的第一个参数对数据进行平铺)得到:
String key1,List< UserEventAction>111
String key2,List< UserEventAction>11
String key2,List< UserEventAction>22
String key3,List< UserEventAction>1
String key3,List< UserEventAction>2
String key3,List< UserEventAction>3
第一条日志(未处理):(key1平铺结果:处理0条,未处理1条)
第二条日志(处理):(key2平铺结果:处理2条,未处理0条)
第三条日志(部分处理):(key3平铺结果:处理2条,未处理1条)
备注:本业务场景,一条日志对应一个key。
进行【聚合】的方法reduce:内部共处理了4条Tuple2<String, List< UserEventAction>里的平铺元素(日志清洗的对象结果)。缺少了2条未处理。
观察到:对应日志条数:未处理1条。处理了2条日志(1条处理,1条部分处理)。
聚合前一步是countWindow。
推断是countWindow(2)出现问题。
上述结果推测:
key1暂不处理:具备1条数据,在countWindow(2)时数据每满2个触发一次,会处理。暂时不处理List< UserEventAction>111。等下一次key1有新数据时候,满2处理。
key2处理:具备2条数据,在countWindow(2)时数据每满2个触发一次,会处理2条:List< UserEventAction>11,List< UserEventAction>22。
key3部分处理:具备3条数据,在countWindow(2)时数据每满2个触发一次,会处理2条:List< UserEventAction>1,List< UserEventAction>2。暂时不处理List< UserEventAction>3。等下一次key3有新数据时候,满2条处理。
备注:也可以从落库redis的数据反序列化后得到印证。
5、结论
把countWindow改成1就可以都落库了。
DataStream.flatMap(进行日志清洗-Collector收集).keyBy(0).countWindow(1).reduce(进行聚合).process(进行redis落库)
问题解决了,问题在countWindow(2),也就是当根据keyBy(0)分组之后,数据的数量每次达到2时进行输出。
日志清洗后的结果是一条日志对应一个key,一个key对应多个List< UserEventAction>或者单个List< UserEventAction>。
设置2的时候,对应的key的List< UserEventAction>如果只有一条就不会落库,kafka生产者执行两次时候就会累积到两条相同的key的数据,每满2条处理后续操作,所以之前有奇数次执行和偶数次执行区别。
6、后续补充
主要是和flatMap平铺后收集到的key的种类数量有关系。