本文基于Flink1.9版本简述如何连接Kafka。

流式连接器

我们知道可以自己来开发Source 和 Sink ,但是一些比较基本的 Source 和 Sink 已经内置在 Flink 里。

预定义的source支持从文件、目录、socket,以及 collections 和 iterators 中读取数据。

预定义的sink支持把数据写入文件、标准输出(stdout)、标准错误输出(stderr)和 socket。

连接器可以和多种多样的第三方系统进行交互。目前支持以下系统:

  • Apache Kafka
  • Apache Cassandra(sink)
  • Amazon Kinesis Streams(source/sink)
  • Elasticsearch(sink)
  • Hadoop FileSystem (sink)
  • RabbitMQ(source/sink)
  • Apache NiFi(source/sink)
  • Twitter Streaming API(source)

请记住,在使用一种连接器时,通常需要额外的第三方组件,比如:数据存储服务器或者消息队列。

Apache Bahir 中定义了其他一些连接器

  • Apache ActiveMQ(source/sink)
  • Apache Flume(sink)
  • Redis(sink)
  • Akka (sink)
  • Netty (source)

使用connector并不是唯一可以使数据进入或者流出Flink的方式。一种常见的模式是从外部数据库或者 Web 服务查询数据得到初始数据流,然后通过 Map 或者 FlatMap 对初始数据流进行丰富和增强,这里要使用Flink的异步IO。

而向外部存储推送大量数据时会导致 I/O 瓶颈问题出现。在这种场景下,如果对数据的读操作远少于写操作,可以让外部应用从 Flink 拉取所需的数据,需要用到Flink的可查询状态接口。

本文重点介绍Apache Kafka Connector

Kafka连接器

此连接器提供对Apache Kafka提供的事件流的访问。

Flink提供特殊的Kafka连接器,用于从/向Kafka主题读取和写入数据。Flink Kafka Consumer集成了Flink的检查点机制,可提供一次性处理语义。为实现这一目标,Flink并不完全依赖Kafka 的消费者组的偏移量,而是在内部跟踪和检查这些偏移。

下表为不同版本的kafka与Flink Kafka Consumer的对应关系。

Maven Dependency Supported since Consumer and Producer Class name Kafka version
flink-connector-kafka-0.8_2.11 1.0.0 FlinkKafkaConsumer08 FlinkKafkaProducer08 0.8.x
flink-connector-kafka-0.9_2.11 1.0.0 FlinkKafkaConsumer09 FlinkKafkaProducer09 0.9.x
flink-connector-kafka-0.10_2.11 1.2.0 FlinkKafkaConsumer010 FlinkKafkaProducer010 0.10.x
flink-connector-kafka-0.11_2.11 1.4.0 FlinkKafkaConsumer011 FlinkKafkaProducer011 0.11.x
flink-connector-kafka_2.11 1.7.0 FlinkKafkaConsumer FlinkKafkaProducer >= 1.0.0

而从最新的Flink1.9.0版本开始,使用Kafka 2.2.0客户端。

下面简述使用步骤。

导入maven依赖:

<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka_2.11</artifactId>
<version>1.9.0</version>
</dependency>

安装Kafka:

可以参照 Kafka入门宝典(详细截图版)

兼容性:

从Flink 1.7开始,它不跟踪特定的Kafka主要版本。相反,它在Flink发布时跟踪最新版本的Kafka。如果您的Kafka代理版本是1.0.0或更高版本,则应使用此Kafka连接器。如果使用旧版本的Kafka(0.11,0.10,0.9或0.8),则应使用与代理版本对应的连接器。

升级Connect要注意Flink升级作业,同时

  • 在整个过程中使用Flink 1.9或更新版本。

  • 不要同时升级Flink和运营商。

  • 确保您作业中使用的Kafka Consumer和/或Kafka Producer分配了唯一标识符(uid)。

  • 使用stop with savepoint功能获取保存点(例如,使用stop --withSavepoint)。

用法:

引入依赖后,实例化新的source(FlinkKafkaConsumer)和sink(FlinkKafkaProducer)。

Kafka Consumer

先分步骤介绍构建过程,文末附Flink1.9连接Kafka完整代码。

Kafka consumer 根据版本分别叫做FlinkKafkaConsumer08 FlinkKafkaConsumer09等等

Kafka >= 1.0.0 的版本就叫FlinkKafkaConsumer。

构建FlinkKafkaConsumer

java示例代码如下:

Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "test");
DataStream<String> stream = env
.addSource(new FlinkKafkaConsumer<>("topic", new SimpleStringSchema(), properties));

scala:

val properties = new Properties()
properties.setProperty("bootstrap.servers", "localhost:9092")
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181")
properties.setProperty("group.id", "test")
stream = env
.addSource(new FlinkKafkaConsumer[String]("topic", new SimpleStringSchema(), properties))
.print()

必须有的:

1.topic名称

2.用于反序列化Kafka数据的DeserializationSchema / KafkaDeserializationSchema

3.配置参数:“bootstrap.servers” “group.id” (kafka0.8还需要 “zookeeper.connect”)

配置消费起始位置

java:

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

FlinkKafkaConsumer<String> myConsumer = new FlinkKafkaConsumer<>(...);
myConsumer.setStartFromEarliest(); // start from the earliest record possible
myConsumer.setStartFromLatest(); // start from the latest record
myConsumer.setStartFromTimestamp(...); // start from specified epoch timestamp (milliseconds)
myConsumer.setStartFromGroupOffsets(); // the default behaviour //指定位置
//Map<KafkaTopicPartition, Long> specificStartOffsets = new HashMap<>();
//specificStartOffsets.put(new KafkaTopicPartition("myTopic", 0), 23L);
//myConsumer.setStartFromSpecificOffsets(specificStartOffsets); DataStream<String> stream = env.addSource(myConsumer);

scala:

val env = StreamExecutionEnvironment.getExecutionEnvironment()

val myConsumer = new FlinkKafkaConsumer[String](...)
myConsumer.setStartFromEarliest() // start from the earliest record possible
myConsumer.setStartFromLatest() // start from the latest record
myConsumer.setStartFromTimestamp(...) // start from specified epoch timestamp (milliseconds)
myConsumer.setStartFromGroupOffsets() // the default behaviour //指定位置
//val specificStartOffsets = new java.util.HashMap[KafkaTopicPartition, java.lang.Long]()
//specificStartOffsets.put(new KafkaTopicPartition("myTopic", 0), 23L)
//myConsumer.setStartFromSpecificOffsets(specificStartOffsets) val stream = env.addSource(myConsumer)
检查点

启用Flink的检查点后,Flink Kafka Consumer将使用主题中的记录,并以一致的方式定期检查其所有Kafka偏移以及其他操作的状态。如果作业失败,Flink会将流式程序恢复到最新检查点的状态,并从存储在检查点中的偏移量开始重新使用Kafka的记录。

如果禁用了检查点,则Flink Kafka Consumer依赖于内部使用的Kafka客户端的自动定期偏移提交功能。

如果启用了检查点,则Flink Kafka Consumer将在检查点完成时提交存储在检查点状态中的偏移量。

java

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(5000); // checkpoint every 5000 msecs

scala

val env = StreamExecutionEnvironment.getExecutionEnvironment()
env.enableCheckpointing(5000) // checkpoint every 5000 msecs
分区发现

Flink Kafka Consumer支持发现动态创建的Kafka分区,并使用一次性保证消费它们。

还可以使用正则:

java

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
properties.setProperty("group.id", "test"); FlinkKafkaConsumer011<String> myConsumer = new FlinkKafkaConsumer011<>(
java.util.regex.Pattern.compile("test-topic-[0-9]"),
new SimpleStringSchema(),
properties); DataStream<String> stream = env.addSource(myConsumer);
...

scala

val env = StreamExecutionEnvironment.getExecutionEnvironment()

val properties = new Properties()
properties.setProperty("bootstrap.servers", "localhost:9092")
properties.setProperty("group.id", "test") val myConsumer = new FlinkKafkaConsumer08[String](
java.util.regex.Pattern.compile("test-topic-[0-9]"),
new SimpleStringSchema,
properties) val stream = env.addSource(myConsumer)
...
时间戳和水印

在许多情况下,记录的时间戳(显式或隐式)嵌入记录本身。另外,用户可能想要周期性地或以不规则的方式发出水印。

我们可以定义好Timestamp Extractors / Watermark Emitters,通过以下方式将其传递给您的消费者:

java

Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "test"); FlinkKafkaConsumer08<String> myConsumer =
new FlinkKafkaConsumer08<>("topic", new SimpleStringSchema(), properties);
myConsumer.assignTimestampsAndWatermarks(new CustomWatermarkEmitter()); DataStream<String> stream = env
.addSource(myConsumer)
.print();

scala

val properties = new Properties()
properties.setProperty("bootstrap.servers", "localhost:9092")
// only required for Kafka 0.8
properties.setProperty("zookeeper.connect", "localhost:2181")
properties.setProperty("group.id", "test") val myConsumer = new FlinkKafkaConsumer08[String]("topic", new SimpleStringSchema(), properties)
myConsumer.assignTimestampsAndWatermarks(new CustomWatermarkEmitter())
stream = env
.addSource(myConsumer)
.print()

Kafka Producer

Kafka Producer 根据版本分别叫做FlinkProducer011 FlinkKafkaProducer010等等

Kafka >= 1.0.0 的版本就叫FlinkKafkaProducer 。

构建FlinkKafkaConsumer

java

DataStream<String> stream = ...;

FlinkKafkaProducer011<String> myProducer = new FlinkKafkaProducer011<String>(
"localhost:9092", // broker list
"my-topic", // target topic
new SimpleStringSchema()); // serialization schema // versions 0.10+ allow attaching the records' event timestamp when writing them to Kafka;
// this method is not available for earlier Kafka versions
myProducer.setWriteTimestampToKafka(true); stream.addSink(myProducer);

scala

val stream: DataStream[String] = ...

val myProducer = new FlinkKafkaProducer011[String](
"localhost:9092", // broker list
"my-topic", // target topic
new SimpleStringSchema) // serialization schema // versions 0.10+ allow attaching the records' event timestamp when writing them to Kafka;
// this method is not available for earlier Kafka versions
myProducer.setWriteTimestampToKafka(true) stream.addSink(myProducer)

需要指定broker list , topic,序列化类。

自定义分区:默认情况下,将使用FlinkFixedPartitioner将每个Flink Kafka Producer并行子任务映射到单个Kafka分区。

可以实现FlinkKafkaPartitioner类自定义分区。

Flink1.9消费Kafka完整代码:

import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import java.util.Properties; public class KafkaConsumer { public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
properties.setProperty("group.id", "test");
//构建FlinkKafkaConsumer
FlinkKafkaConsumer<String> myConsumer = new FlinkKafkaConsumer<>("topic", new SimpleStringSchema(), properties);
//指定偏移量
myConsumer.setStartFromEarliest(); DataStream<String> stream = env
.addSource(myConsumer); env.enableCheckpointing(5000);
stream.print(); env.execute("Flink Streaming Java API Skeleton");
}

项目地址:https://github.com/tree1123/flink_demo_1.9

更多Flink知识,欢迎关注实时流式计算

Flink1.9整合Kafka的更多相关文章

  1. SpringBoot整合Kafka和Storm

    前言 本篇文章主要介绍的是SpringBoot整合kafka和storm以及在这过程遇到的一些问题和解决方案. kafka和storm的相关知识 如果你对kafka和storm熟悉的话,这一段可以直接 ...

  2. SpringBoot实战(十四)之整合KafKa

    本人今天上午参考了不少博文,发现不少博文不是特别好,不是因为依赖冲突问题就是因为版本问题. 于是我结合相关的博文和案例,自己改写了下并参考了下,于是就有了这篇文章.希望能够给大家帮助,少走一些弯路. ...

  3. 基于Java+SparkStreaming整合kafka编程

    一.下载依赖jar包 具体可以参考:SparkStreaming整合kafka编程 二.创建Java工程 太简单,略. 三.实际例子 spark的安装包里面有好多例子,具体路径:spark-2.1.1 ...

  4. SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合消息服务 2.具体内容 对于异步消息组件在实际的应用之中会有两类: · JMS:代表作就是 ...

  5. Spark之 Spark Streaming整合kafka(并演示reduceByKeyAndWindow、updateStateByKey算子使用)

    Kafka0.8版本基于receiver接受器去接受kafka topic中的数据(并演示reduceByKeyAndWindow的使用) 依赖 <dependency> <grou ...

  6. flume 整合 kafka

    flume 整合 kafka:   flume:高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统. kafka:分布式的流数据平台.   flume 采集业务日志,发送到kafka   一. ...

  7. Trident整合Kafka

    首先编写一个打印函数KafkaPrintFunction import org.apache.storm.trident.operation.BaseFunction; import org.apac ...

  8. 整合Kafka到Spark Streaming——代码示例和挑战

    作者Michael G. Noll是瑞士的一位工程师和研究员,效力于Verisign,是Verisign实验室的大规模数据分析基础设施(基础Hadoop)的技术主管.本文,Michael详细的演示了如 ...

  9. Spark学习之路(十六)—— Spark Streaming 整合 Kafka

    一.版本说明 Spark针对Kafka的不同版本,提供了两套整合方案:spark-streaming-kafka-0-8和spark-streaming-kafka-0-10,其主要区别如下:   s ...

随机推荐

  1. 003——Netty之Buffer、Channel以及多路复用器Selector

    Buffer 1.缓冲区类型 2.缓冲区定义 (1)Buffer是一个对象,其中包含写入与读出的数据.是新IO与原IO的重要区别.任何情况下访问NIO中的数据都需要通过缓存区进行操作. (2)Buff ...

  2. java之异常详解

    一.什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错.在java中,阻止当前方法或作用域正常运行的情况,称之为异常. 二.异常体系 Java把异常当作对象来处理,并定义一个基类java. ...

  3. Javascript中,实现十大排序方法之一(冒泡排序及其优化设想)

    冒泡排序的Javascript实现 首先定义一个取值范围在(0~100000)之间的随机值的长度为10万的数组, function bubbleSort(arr) { console.time('冒泡 ...

  4. net core Webapi基础工程搭建(五)——缓存机制

    目录 前言 Cache Session Cookie 小结 补充 前言 作为WebApi接口工程,性能效率是必不可少的,每次的访问请求,数据库读取,业务逻辑处理都或多或少耗费时间,偶尔再来个各种花式f ...

  5. 番茄日志发布1.0.3版本-增加Kafka支持

    番茄日志(TomatoLog)能做什么 可能你是第一次听说TomatoLog,没关系,我可以从头告诉你,通过了解番茄日志,希望能帮助有需要的朋友,番茄日志处理将大大降低你采集.分析.处理日志的过程. ...

  6. **p,*p和&p使用有感

    *p两种使用情况: 1.定义指针变量,如char *p:这里p是一个变量,单单在这一点上与int a 无差别:但p这个变量特殊在其中只能存地址. 引申:对于char **p,p中存一个地址add1,a ...

  7. @RequestBody 注意的问题

    contentType : "application/json", //只能是这个 RequestBody 不能和form/data共存: @RequestMapping(valu ...

  8. 良许Linux | Linux学习方法及学习资料汇总

    很多人想学习Linux,却不知道怎么着手,甚至不知道Linux有哪些方向,非常迷茫.基于此,我特地写了篇文章介绍Linux方向性问题,没想到一不小心成了爆款: 到什么程度才叫精通 Linux?​ 看完 ...

  9. python学习——文件操作

    打开文件 f = open(文件名, 文件打开模式,文件编码) ‘w’:只写模式,它是只能写,而不能读的.如果用’w’模式打开一个不存在的文件,则会创建新的文件开始写入:如果用’w’模式打开一个已存在 ...

  10. MSIL实用指南-加载int值

    这一篇讲的是怎样加载整数值到运算栈上.这一类的指令都是以Ldc_I4开头. Ldc_I4类OpCodes的Ldc_I4字段的功能是把一个int值压入运算栈上.它的使用方法是ilGenerator.Em ...