一、并行度
- 一个Flink任务由多个组件组成(DataSource、Transformation、DataSink)
- 一个组件由多个并行的实例(线程)来执行,一个组件的并行实例(线程)数目就被称为该组件的并行度
1.1、并行度的设置
-
Operator Level 算子层面
setParallelism(5)
-
Execution Environment Level 执行环境层面
env.setParallelism(3)
-
Client Level 客户端层面
在客户端提交JOB时设定,通过-p参数执行并行度
-
System Level 系统层面
在系统层面可以通过设置flink-conf.yaml文件中的parallelism.default属性来指定所有执行环境的默认并行度
二、Flink之KafkaConnector
Java项目引入下面的依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka</artifactId>
<version>1.16.0</version>
</dependency>
2.1、Kafka Consumer消费策略设置
- setStartFromGroupOffsets 默认消费策略
- setStartFromEarliest 从最早的开始消费 或者setStartFromLatest 从最新的开始消费
- setStartFromTimestamp 按照时间戳往后面开始消费
public class FlinkWithKafka {
public static void main(String[] args) {
Properties properties = new Properties();
// flink 1.3版本以后,不推荐下面的写法,推荐使用KafkaSource
// FlinkKafkaConsumer<String> stringFlinkKafkaConsumer = new FlinkKafkaConsumer<>("", new SimpleStringSchema(), properties);
// 默认策略,读取group id对应保存的offset开始消费数据,读取不到根据kafka中auto.offset.reset参数的值开始消费数据
// stringFlinkKafkaConsumer.setStartFromGroupOffsets();
// 从最早的记录开始消费数据,忽略已提交的offset信息
// stringFlinkKafkaConsumer.setStartFromEarliest();
// 从最新的记录开始消费数据,忽略已提交的offset信息
// stringFlinkKafkaConsumer.setStartFromLatest();
// 从指定的时间戳开始消费数据,对于每个分区,其时间戳大于或者等于指定时间戳的记录将被作为起始位置
// stringFlinkKafkaConsumer.setStartFromTimestamp(1111L);
// 新的写法
KafkaSource.builder()
.setProperties(properties)
.setTopics("")
.setStartingOffsets(OffsetsInitializer.earliest())
.build();
}
}
2.2、Kafka Consumer的容错
Flink中也有这个checkpoint机制,checkpoint是flink实现容错的核心功能。它能够根据配置周期性的基于流中各个算子任务的State来生成快照,从而将这些State数据定期持久化存储下来。当flink程序一旦意外崩溃时,重新运行程序时可以有选择的从这些快照进行恢复。从而修正因为故障带来的程序数据异常。
- 当CheckPoint机制开启的时候,Consumer会定期把Kafka的offset信息还有其它算子任务的State信息一块保存起来
- 当Job失败重启时,Flink会从最近一次的CheckPoint中进行恢复数据,重新消费Kafka中的数据
- 为了能够使用支持容错的Consumer,需要开启CheckPoint
StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
// 每隔5000ms执行一次checkpoint
executionEnvironment.enableCheckpointing(5000);
// 设置模式为EXACTLY_ONCE(默认值)
executionEnvironment.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
// 确保两次CheckPoint之间至少有多少ms间隔
executionEnvironment.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
// checkpoint必须在一分钟内完成。完不成就进行丢弃
executionEnvironment.getCheckpointConfig().setCheckpointTimeout(60000);
// 同一时间内只允许执行一个checkpoint
executionEnvironment.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
// 一旦Flink程序被Cancel后,会保留CheckPoint数据,以便根据实际需要恢复到指定的CheckPoint
executionEnvironment.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
执行CheckPoint时,State数据保存在哪?
- MemoryStateBackend Java堆内存中
- FsStateBackend 保存在TaskManager内存中,会把State的快照数据保存到配置的文件系统中
- RocksDBStateBackend 会在本地文件系统中维护这个State,State会直接写入本地的RocksDB中,同时需要配置一个远程的文件系统
2.3、Kafka Consumer Offset自动提交
- 针对Job是否开启CheckPoint来区分
- CheckPoint关闭时,通过参数enable.auto.commit和enable.commit.interval.ms控制
- CheckPoint开启时,执行CheckPoint的时候才会提交offset
三、KafkaProducer使用
-
启动kafka
bin/kafka-server-start.sh -daemon config/server.properties
-
创建topic
bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my-topic --partitions 1
-
启动socket
-
java代码
package com.strivelearn.flink.kafka; import org.apache.flink.api.common.serialization.SimpleStringSchema; import org.apache.flink.streaming.api.datastream.DataStreamSource; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer; import org.apache.flink.streaming.connectors.kafka.KafkaSerializationSchema; import org.apache.flink.streaming.connectors.kafka.internals.KafkaSerializationSchemaWrapper; import org.apache.flink.streaming.connectors.kafka.partitioner.FlinkFixedPartitioner; import java.util.Properties; /** * Flink向kafka中生产数据 * * @author strivelearn * @version StreamKafkaSink.java, 2023年01月27日 */ public class StreamKafkaSink { public static void main(String[] args) throws Exception { StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment(); DataStreamSource<String> socketTextStream = environment.socketTextStream("192.168.234.100", 9001); // 指定需要写入的topic名称 String topic = "test"; Properties properties = new Properties(); properties.setProperty("bootstrap.servers", "192.168.234.100:9092"); // 自定义分区器实现将数据写入到指定topic具体的分区中。默认将所有的数据都写入到指定topic一个分区中 FlinkFixedPartitioner<String> objectFlinkFixedPartitioner = new FlinkFixedPartitioner<>(); KafkaSerializationSchema<String> objectKafkaSerializationSchema = new KafkaSerializationSchemaWrapper<>(topic, objectFlinkFixedPartitioner, true, new SimpleStringSchema()); FlinkKafkaProducer<String> stringFlinkKafkaProducer = new FlinkKafkaProducer<>(topic, objectKafkaSerializationSchema, properties, FlinkKafkaProducer.Semantic.EXACTLY_ONCE); socketTextStream.addSink(stringFlinkKafkaProducer); environment.execute("StreamKafkaSink"); } }
-
查看写入到kafka的消息
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
3.1、Kafka Producer的容错
- 如果Flink开启了CheckPoint。针对FlinkKafkaProducer可以提供EXACTLY_ONCE的语义保证
- 可以通过semantic参数来指定三种不同的语义:Semantic.NONE、Semantic.AT_LAST_ONCE(默认)、Semantic.EXACTLY_ONCE
FlinkKafkaProducer<String> stringFlinkKafkaProducer = new FlinkKafkaProducer<>(topic, objectKafkaSerializationSchema, properties, FlinkKafkaProducer.Semantic.EXACTLY_ONCE);