Flink简介
Flink底层主要书java实现
Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行状态计算。
flink是要解决的问题就是,在高吞吐量的前提下实现实时的数据处理
flink是真的流式处理(实时处理),Spark Streaming是假的流式处理()实时处理,SpringStream是批处理,只是每批的数据比较小。
Spring Stream一般是几秒的延迟(有参数可以设置)
如今的大数据技术应用场景,对实时性的要求已经越来越高。作为新一代大数据流处理框架,由于非常好的实时性,Flink 独树一帜,在近些年引起了业内极大的兴趣和关注。Flink能够提供毫秒级别的延迟,同时保证了数据处理的低延迟、高吞吐和结果的正确性,还提供了丰富的时间类型和窗口计算、Exactly-once 语义支持,另外还可以进行状态管理,并提供了 CEP(复杂事件处理)的支持。Flink 在实时分析领域的优势,使得越来越多的公司开始将实时项目向 Flink 迁移,其社区也在快速发展壮大。
目前,Flink 已经成为各大公司实时领域的发力重点,特别是国内以阿里为代表的一众大厂,都在全力投入,不少公司为 Flink 社区贡献了大量源码。如今 Flink 已被很多人认为是大数据实时处理的方向和未来,很多公司也都在招聘和储备了解掌握 Flink 的人才。
Flink应用场景
传统数据处理架构
分析处理
用到了数据仓
流式处理
有状态的流式处理
有状态主要是指的,把流式数据存储起来(周期性的保存),方便数据处理系统异常是数据恢复。
流处理的演变
老式的lambda机构:批处理+流处理
先通过流处理保证数据的实时性,后期在通过批处理保证数据的正确性。
Flink特点
Flink和Spark Streaming的区别
Flink运行时架构
运行是时组件
作业管理器(JobManager)
任务管理器(TaskManager)
任务管理器是flink中干活的(处理业务逻辑)
资源管理器(ResourceManager)
分发器(Dispatcher)
任务提交流程
上图是从一个较为高层级的视角,来看应用中各组件的交互协作。如果部署的集群环境 不同(例如 YARN,Mesos,Kubernetes,standalone 等),其中一些步骤可以被省略,或是 有些组件会运行在同一个 JVM 进程中。
任务调度原理
第五章 Flink 流处理 API
5.1 Environment
5.2 Source(数据来源)
5.2.3 以 kafka 消息队列的数据作为来源
kafka主要是做流式数据处理,kafka是flink的最佳拍档,一般都是使用kafka做为flink的数据源。
flink kafka 的客户端可以自动根据topic的分区数启动对应的工作线程数
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-0.11_2.11</artifactId>
<version>1.7.2</version>
</dependency>
pom.xml
<?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.atguigu</groupId>
<artifactId>FlinkTutorial</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-scala_2.11</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.flink/flink-streaming-scala -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-scala_2.11</artifactId>
<version>1.7.2</version>
</dependency>
<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.bahir</groupId>
<artifactId>flink-connector-redis_2.11</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-elasticsearch6_2.11</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-statebackend-rocksdb_2.11</artifactId>
<version>1.7.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 该插件用于将Scala代码编译成class文件 -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.4.6</version>
<executions>
<execution>
<!-- 声明绑定到maven的compile阶段 -->
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
SourceTest.scala:
package com.atguigu.apitest
import java.util.Properties
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011
import scala.util.Random
/**
* Copyright (c) 2018-2028 尚硅谷 All Rights Reserved
*
* Project: FlinkTutorial
* Package: com.atguigu.apitest
* Version: 1.0
*
* Created by wushengran on 2019/9/17 10:11
*/
// 定义传感器数据样例类
case class SensorReading( id: String, timestamp: Long, temperature: Double )
object SourceTest {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 1. 从集合中读取数据
val stream1 = env.fromCollection(List(
SensorReading("sensor_1", 1547718199, 35.80018327300259),
SensorReading("sensor_6", 1547718201, 15.402984393403084),
SensorReading("sensor_7", 1547718202, 6.720945201171228),
SensorReading("sensor_10", 1547718205, 38.101067604893444)
))
// env.fromElements("flink", 1, 32, 3213, 0.324).print("test")
// 2. 从文件中读取数据
val stream2 = env.readTextFile("D:\\Projects\\BigData\\FlinkTutorial\\src\\main\\resources\\sensor.txt")
// 3. 从kafka中读取数据
// 创建kafka相关的配置
val properties = new Properties()
properties.setProperty("bootstrap.servers", "localhost:9092")
properties.setProperty("group.id", "consumer-group")
properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
properties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
properties.setProperty("auto.offset.reset", "latest")
val stream3 = env.addSource(new FlinkKafkaConsumer011[String]("topic-sensor", new SimpleStringSchema(), properties))
// sink输出
stream3.print("stream3")
// 4. 自定义数据源
// val stream4 = env.addSource(new SensorSource())
// sink输出
// stream4.print("stream4")
env.execute("source api test")
}
}
class SensorSource() extends SourceFunction[SensorReading]{
// 定义一个flag:表示数据源是否还在正常运行
var running: Boolean = true
override def cancel(): Unit = running = false
override def run(ctx: SourceFunction.SourceContext[SensorReading]): Unit = {
// 创建一个随机数发生器
val rand = new Random()
// 随机初始换生成10个传感器的温度数据,之后在它基础随机波动生成流数据
var curTemp = 1.to(10).map(
i => ( "sensor_" + i, 60 + rand.nextGaussian() * 20 )
)
// 无限循环生成流数据,除非被cancel
while(running){
// 更新温度值
curTemp = curTemp.map(
t => (t._1, t._2 + rand.nextGaussian())
)
// 获取当前的时间戳
val curTime = System.currentTimeMillis()
// 包装成SensorReading,输出
curTemp.foreach(
t => ctx.collect( SensorReading(t._1, curTime, t._2) )
)
// 间隔100ms
Thread.sleep(100)
}
}
}
5.3Transform(转换算子->数据转换)
数据转换操作代码示例
package com.atguigu.apitest
import org.apache.flink.api.common.functions.{FilterFunction, RichMapFunction}
import org.apache.flink.configuration.Configuration
import org.apache.flink.streaming.api.scala._
/**
* Copyright (c) 2018-2028 尚硅谷 All Rights Reserved
*
* Project: FlinkTutorial
* Package: com.atguigu.apitest
* Version: 1.0
*
* Created by wushengran on 2019/9/17 11:41
*/
object TransformTest {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 读入数据
val inputStream = env.readTextFile("D:\\Projects\\BigData\\FlinkTutorial\\src\\main\\resources\\sensor.txt")
// Transform操作->转换成样例类类型
val dataStream = inputStream
.map(
data => {
val dataArray = data.split(",")
SensorReading( dataArray(0).trim, dataArray(1).trim.toLong, dataArray(2).trim.toDouble )
}
)
// 1. 聚合操作
val stream1 = dataStream
//以id为key进行分组
.keyBy("id")
//分组后再处理
// .min("temperature")
//.minBy("temperature")
// .sum("temperature")
.reduce( (x, y) => SensorReading(x.id, x.timestamp + 1, y.temperature + 10) )
stream1.print();
// 2. 分流,根据温度是否大于30度划分
val splitStream = dataStream
.split( sensorData => {
if( sensorData.temperature > 30 ) Seq("high") else Seq("low")
} )
val highTempStream = splitStream.select("high")
val lowTempStream = splitStream.select("low")
val allTempStream = splitStream.select("high", "low")
highTempStream.print("高")
lowTempStream.print("低")
allTempStream.print("所有")
// 3. 合并两条流
val warningStream = highTempStream.map( sensorData => (sensorData.id, sensorData.temperature) )
val connectedStreams = warningStream.connect(lowTempStream)
val coMapStream = connectedStreams.map(
warningData => ( warningData._1, warningData._2, "high temperature warning" ),
lowData => ( lowData.id, "healthy" )
)
val unionStream = highTempStream.union(lowTempStream)
// 函数类
dataStream.filter( new MyFilter() ).print()
// 输出数据
// dataStream.print()
// highTempStream.print("high")
// lowTempStream.print("low")
// allTempStream.print("all")
// unionStream.print("union")
env.execute("transform test job")
}
}
class MyFilter() extends FilterFunction[SensorReading]{
override def filter(value: SensorReading): Boolean = {
value.id.startsWith("sensor_1")
}
}
class MyMapper() extends RichMapFunction[SensorReading, String]{
override def map(value: SensorReading): String = {
"flink"
}
override def open(parameters: Configuration): Unit = super.open(parameters)
}
简单转换算子
5.3.1 map
// Transform操作->转换成样例类类型
val dataStream = inputStream
.map(
data => {
val dataArray = data.split(",")
SensorReading( dataArray(0).trim, dataArray(1).trim.toLong, dataArray(2).trim.toDouble )
}
)
5.3.2 flatMap
Filter
分组后再处理
5.3.4 KeyBy
5.3.5 滚动聚合算子(Rolling Aggregation)
val stream1 = dataStream
//以id为key进行分组
.keyBy("id")
//分组后再处理
// .min("temperature")
//.minBy("temperature")
// .sum("temperature")
.reduce( (x, y) => SensorReading(x.id, x.timestamp + 1, y.temperature + 10) )
stream1.print();
复杂转换算子
5.3.6 Reduce
多流转换算子
5.3.7 Split 和 Select(分流)
实际使用场景:kafka流数据进来,只消费我需要的消息,不需要的再写回kafka供其他人消费。
分流:
// 2. 分流,根据温度是否大于30度划分
val splitStream = dataStream
.split( sensorData => {
if( sensorData.temperature > 30 ) Seq("high") else Seq("low")
} )
val highTempStream = splitStream.select("high")
val lowTempStream = splitStream.select("low")
val allTempStream = splitStream.select("high", "low")
highTempStream.print("高")
lowTempStream.print("低")
allTempStream.print("所有")
5.3.8 Connect 和 CoMap(合流)
5.3.9 Union
5.6 Sink (数据输出)
5.6.1 Kafka
pom.xml
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-0.11_2.12</artifactId>
<version>1.10.1</version>
</dependency>
主函数中添加 sink:
dataStream.addSink( new FlinkKafkaProducer011[String]("localhost:9092", "sinktest-topic", new SimpleStringSchema()) )
package com.atguigu.apitest.sinttest
import java.util.Properties
import com.atguigu.apitest.SensorReading
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.{FlinkKafkaConsumer011, FlinkKafkaProducer011}
/**
* Copyright (c) 2018-2028 尚硅谷 All Rights Reserved
*
* Project: FlinkTutorial
* Package: com.atguigu.apitest.sinttest
* Version: 1.0
*
* Created by wushengran on 2020/8/7 10:12
*/
object KafkaSinkTest {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 读取数据
// val inputPath = "D:\\Projects\\BigData\\FlinkTutorial\\src\\main\\resources\\sensor.txt"
// val inputStream = env.readTextFile(inputPath)
// 从kafka读取数据
val properties = new Properties()
properties.setProperty("bootstrap.servers", "localhost:9092")
properties.setProperty("group.id", "consumer-group")
val stream = env.addSource( new FlinkKafkaConsumer011[String]("sensor", new SimpleStringSchema(), properties) )
// 先转换成样例类类型(简单转换操作)
val dataStream = stream
.map( data => {
val arr = data.split(",")
SensorReading(arr(0), arr(1).toLong, arr(2).toDouble).toString
} )
dataStream.addSink( new FlinkKafkaProducer011[String]("localhost:9092", "sinktest", new SimpleStringSchema()) )
env.execute("kafka sink test")
}
}