Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记

要想Flink实现ExactlyOnce需要Source能够记录偏移量,Sink支持开启事务

一、Source

1、使用KafkaSource需要调用addSource方法,传入一个FlinkKafkaConsumer的实例

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第1张图片

2、FlinkKafkaConsumer类实现了FlinkKafkaConsumerBase,点到FlinkKafkaConsumerBase里面我们看到他有一个成员变量,这个成员变量就是用来记录Kafka的某个topic的某个分区的偏移量,因为可能会有一个台机器读多个kafka分区的情况,所以用的ListState

二、Sink

1、调用addSink方法,传入一个FlinkKafkaProducer的一个实例,点入到FlinkKafkaProducer里面,看到这个类继承了TwoPhaseCommitSinkFunction,这个类叫做两阶段提交接收函数后面我们能看到什么是两阶段提交

 
  

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第2张图片

 2、可以看到TwoPhaseCommitSinkFunction这个方法继承了RichSinkFunction,并实现了CheckpointedFunction, CheckpointListener这两个接口

 3、RichSinkFunction是自定义Sink基本都要实现;CheckpointedFunction提供了initializeState和snapshotState这两个方法,initializeState方法是subTask的生命周期方法,snapshotState方法是在每次Checkpoint的时候,调用一次这个方法;继承CheckpointListener需要实现notifyCheckpointComplete方法和notifyCheckpointAborted方法

这里我们需要看一下Flink的Checkpoint的步骤,下图(这是实现两阶段提交的关键!!)

从下图,我们可以看到(④)当JobManager集齐了这次Checkpoint所有subtask的应答后,会想实现了CheckpointListener接口的subtask发送这次Checkpoint成功的消息;(⑤)所有实现了CheckpointListener方法的Task的subtask会调用notifyCheckpointComplete方法

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第3张图片

 4、(①)我们看FlinkKafkaProducer的initializeState方法调用了父TwoPhaseCommitSinkFunction的initializeState方法

(②)TwoPhaseCommitSinkFunction的initializeState方法首先恢复了用来保存数据的状态

 (③)TwoPhaseCommitSinkFunction的initializeState方法开启了一个事务

 5、FlinkKafkaProducer的invoke方法,每有一个条数据进入到Sink就调用一次这个方法

它将topic、分区号、时间戳、序列化的key和value封装到ProducerRecord的实例中

再使用KafkaProducer的连接将变量recordsend(数据没有立即写入到Kafka的Broker中,而是缓存到支持事务的客户端),再有数据进入到Sink中,再调用invoke方法,再将数据使用Kafka的Producer发送(和上面一个意思),只要没有flush或数据达到一定的大小,数据就会缓存在客户端

 

6、(①)随着时间的推移,在Checkpoint时,会调用FlinkKafkaProducer的snapshotState方法,这个方法首先调用了父类的snapshotState方法,我们看父类的snapshotState

 (②) 在该方法中调用了preCommit方法,preCommit方法大概就干了一件事,将客户端的数据flush到Kafka的Broker中,但是!!注意,这时候并没有提交事务(写入到Kafka Broker中的数据是uncommited状态),然后将缓存在客户端的数据持久化到statebacked中。

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第4张图片

 Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第5张图片

 7、当所有的subtask都完成checkpoint之后,也就是JobManager集齐了所有subtask的Ack应答之后,就会向所有实现了CheckpointListener接口的Task的subtask发送Chenkpoint成功的消息,之后在subtask中调用重写的notifyCheckpointComplete方法

8、TwoPhaseCommitSinkFunction重写的notifyCheckpointComplete方法中调用了commit方法

,这个方法会提交事务,并将客户端的数据flush到Kafka的Broker----这样写入到Kafka中的数据才算真正写入成功!

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第6张图片

 Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第7张图片

 


在写入的时候,可能会出现错误

(一) 如果Checkpoint失败,所有subtask重启,然后从上一次的状态恢复数据,会接着之前的偏移量继续读,继续处理

(二) 如果Checkpoint成功了,提交事务失败了,所有的subtask重启,然后在initializeState方法中恢复状态装的数据,再将数据写入到Kafka的Broker中,并提交事务

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第8张图片

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第9张图片

Flink的从Kafka中读取再写入Kafka如何实现的ExactlyOnce--笔记_第10张图片


现在看一下这个两阶段提交接是哪两个阶段

preCommit,即在Checkpoint时,将客户端缓存的数据flush到Broker中(但没有提交事务)

commit在整个这次Checkpoint成功后,JobManager通知实现了CheckpointListener接口的subtask(Sink),提交事务

你可能感兴趣的:(学生笔记,flink)