案例1.从kafka读取数据再写入kafka
环境:
- flink版本:1.7.2
- kafka版本:2.1.1
flink与kafka交互有多种方式,本案例通过dataStream的addSource和addSink的方式与kafka交互。flink默认支持kafka作为source和sink,引入flink自带的连接器和kafka依赖:
<!-- 注意版本,其中0.11是kafka client版本,2.11是scala版本,1.7.2是flink版本。 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-0.11_2.11</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.12</artifactId>
<version>1.0.0</version>
</dependency>
如果不是maven项目,可自行下载以下的jar包,加入到外部lib中:
代码如下:
import java.util.Properties
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.streaming.api.CheckpointingMode
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.connectors.kafka.{
FlinkKafkaConsumer011, FlinkKafkaProducer011}
import scala.util.Random
/**
* flink以kafka为source和sink
*/
object FlinkFromKafka {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
/**
* 如果启用了Flink的Checkpint机制,
* 那么Flink Kafka Consumer将会从指定的Topic中消费消息,
* 然后定期地将Kafka offsets信息、状态信息以及其他的操作信息进行Checkpint。
* 所以,如果Flink作业出故障了,Flink将会从最新的Checkpint中恢复,
* 并且从上一次偏移量开始读取Kafka中消费消息。
*/
env.enableCheckpointing(2000,CheckpointingMode.EXACTLY_ONCE)
//消费者配置
val properties = new Properties
properties.put("bootstrap.servers", "hadoop02:9092,hadoop03:9092,hadoop04:9092")
properties.put("group.id", "g3")
// properties.put("auto.offset.reset", "earliest")
// properties.put("auto.offset.reset","latest");
properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
//创建消费者 入参(topic,序列化schema,消费者配置)
val consumer = new FlinkKafkaConsumer011[String]("topic1", new SimpleStringSchema(), properties)
consumer.setStartFromEarliest() //设置从最开始消费
/**
* 这里有个问题:为什么设置为从最开始消费,每次重启项目都会消费所有旧消息呢?
* 在实际开发中,如果重启就会消费所有旧消息,肯定是有问题的。
*/
//以kafkaConsumer作为source创建流
val stream: DataStream[String] = env.addSource(consumer).setParallelism(1)//设置并行度为1
// val kStream: KeyedStream[(String, Int), Tuple] = stream.map((_, 1)).keyBy(0)
// val data = kStream.timeWindow(Time.seconds(5)).reduce((x, y) => (x._1, x._2 + y._2))
// data.print()
//处理逻辑:过滤出“a”,拼接一个随机数,然后写出到kafka
val filterStream = stream.filter("a".equals(_