一、什么是Flink
Flink是一个开源的分布式
,高性能
,高可用
,准确的
流处理框架。支持流(Stream)处理
(实时计算)和批(Batch)处理
(离线计算)
- 分布式:可以运行在很多台机器上
- 高性能:处理性能很高
- 高可用:支持程序的自动重启等机制
- 准确的:可以保证处理数据的准确性
1.1、Flink三大核心组件
- Data Source
- Transformations
- Data Sink
1.2、Fink的流处理和批处理
- 在大数据处理领域,批处理和流处理一般被认为是两种不同的任务,一个大数据框架一般会被设计为只能处理其中一个任务
- Flink通过灵活的执行引擎,能够同时支持批处理和流处理
流处理系统和批处理系统最大的不同在于节点之间的数据传输方式:
- 流处理系统:当一条数据被处理完成后,序列化到缓存中,然后立刻通过网络传输到下一个节点,由下一个节点继续处理。这个是典型的一条一条处理(
低延迟要求
) - 批处理系统:当一条数据被处理完成后,序列化到缓存中,此时并不会立刻通过网络传输到下一个节点,当缓存写满的时候,它会持久化到本地磁盘上面,当所有数都被处理完成之后,才开始将处理后的数据通过网络传输到下一个节点(
高吞吐量要求
)
Flink同时支持这两种模式,Flink以固定的缓存块为单位进行网络数据传输,用户可以通过缓存块超时值指定缓存块的传输时机,如果缓存块的超时值为0,则Flink的数据传输方式类似于前面所说的流处理系统的标准模型
,此时系统可以获得最低的处理延迟。如果缓存块的超时值为无限大,则Flink的数据传输方式,类似于前面所说的批处理系统的标准模型
,此时系统可以获取最高的吞吐量。其实底层还是流式计算模型,批处理只是一个极限的特例而已
1.3、Flink的三种数据传输模型
- Record-by-record:make buffer as full 一条一条执行
- Batch:Retaion all buffers 批处理执行
- Pipelined:ship buffer when actually full 缓存块执行
1.4、实时计算框架对比
产品 | Storm | SparkStreaming | Flink |
---|---|---|---|
模型 | Native(来一条一条处理) | Mirco-Batch(一小批一小批处理) | Native |
API | 组合式(只有基础api) | 声明式(封装好的高级函数) | 声明式 |
语义 | At-least-once(最少一次,消息不会丢失,但是可能会重复) | Exectly-once(恰好一次。消息有且仅会被传输一次) | Exectly-once |
容错机制 | Ack(每发出一条数据,需要收到回复) | Checkpoint(JobManager定时触发) | Checkpoint |
状态管理 | 无 | 基于DStream | 基于操作 |
延时 | Low | Medium | Low |
吞吐量 | Low | High | High |
二、Flink代码入门
idea引入scala
-
pom依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.strivelearn</groupId> <artifactId>flink-study</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!--开发离线代码依赖--> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-java</artifactId> <version>1.16.0</version> </dependency> <!--开发实时代码依赖--> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-streaming-java</artifactId> <version>1.16.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-scala_2.12</artifactId> <version>1.16.0</version> </dependency> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-streaming-scala_2.12</artifactId> <version>1.16.0</version> </dependency> <!--flink客户端依赖--> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-clients</artifactId> <version>1.16.0</version> </dependency> </dependencies> </project>
-
Flink Job开发步骤
- 获取一个执行环境
- 加载/创建 初始化数据
- 指定操作数据的transcation算子
- 指定数据目的地
- 调用execute触发执行程序
注意:Flink程序是延迟计算的,只有最后调用execute方法的时候才会真正触发执行程序
-
代码案例场景:
通过socket实时产生一些单词,使用Flink实时接收数据,对指定时间内(比如:2秒)的数据进行聚合统计并且把时间窗口内计算的结果打印出来
-
先要安装linux nc -l 命令,端口测试,TCP服务
yum install nc
安装完成后,在服务器端执行以下命令,实现TCP方式监听5000端口,且显示输出命令:
nc -l [port number] -v
eg:
nc -l 5000 -v
package com.strivelearn.flink;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;
/**
* @author strivelearn
* @version SocketWindowWordCountJava.java, 2023年01月08日
*/
public class SocketWindowWordCountJava {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> text = environment.socketTextStream("bigdata01", 9001);
environment.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
SingleOutputStreamOperator<Tuple2<String, Integer>> wordCount = text.flatMap(new FlatMapFunction<String, String>() {
@Override
public void flatMap(String line, Collector<String> collector) throws Exception {
String[] words = line.split(" ");
for (String word : words) {
collector.collect(word);
}
}
}).map(new MapFunction<String, Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> map(String s) throws Exception {
return new Tuple2<>(s, 1);
}
}).keyBy(tup -> tup.f0).timeWindow(Time.seconds(2)).sum(1);
// 使用一个线程执行打印操作
wordCount.print().setParallelism(1);
// 执行程序
environment.execute("SocketWindowWordCountJava");
}
}