【大数据】Flink 详解(一):基础篇

Flink 详解(一):基础篇

1、什么是 Flink ?

在这里插入图片描述

Flink 是一个以 为核心的高可用、高性能的分布式计算引擎。具备 流批一体,高吞吐、低延迟,容错能力,大规模复杂计算等特点,在数据流上提供 数据分发、通信等功能。

2、能否详细解释一下其中的 数据流、流批一体、容错能力 等概念?

数据流:所有产生的 数据 都天然带有 时间概念,把 事件 按照时间顺序排列起来,就形成了一个事件流,也被称作数据流。

流批一体

首先必须先明白什么是 有界数据无界数据

在这里插入图片描述

  • 有界数据:就是在一个确定的时间范围内的数据流,有开始,有结束,一旦确定就不会再改变,一般 批处理 用来处理有界数据,如上图的 bounded stream
  • 无界数据:就是持续产生的数据流,数据是无限的,有开始,无结束,一般 流处理 用来处理无界数据。如图 unbounded stream

Flink 的设计思想是以 为核心,批是流的特例,擅长处理 无界有界 数据, Flink 提供 精确的时间控制能力有状态 计算机制,可以轻松应对无界数据流,同时提供 窗口 处理有界数据流。所以被成为流批一体。

容错能力:在分布式系统中,硬件故障、进程异常、应用异常、网络故障等异常无处不在,Flink 引擎必须保证故障发生后 不仅可以 重启应用程序,还要 确保其内部状态保持一致,从最后一次正确的时间点重新出发。

Flink 提供 集群级容错 和 应用级容错 能力:

  • 集群级容错: Flink 与 集群管理器 紧密连接,如 YARNKubernetes,当进程挂掉后,自动重启新进程接管之前的工作。同时具备 高可用性 ,可消除所有单点故障,
  • 应用级容错:Flink 使用 轻量级分布式快照,设计检查点(checkpoint)实现可靠容错。

Flink 利用检查点特性,在框架层面提供 Exactly-once 语义,即端到端的一致性,确保数据仅处理一次,不会重复也不会丢失,即使出现故障,也能保证数据只写一次。

3、Flink 和 Spark Streaming 的区别?

Flink 和 Spark Sreaming 最大的区别在于:Flink 是标准的实时处理引擎,基于事件驱动,以流为核心;而 Spark Streaming 的 RDD 实际是一组小批次的 RDD 集合,是微批(Micro-Batch)的模型,以批为核心

下面我们介绍两个框架的主要区别:

1.架构模型

Spark Streaming 在运行时的主要角色包括:

  • 服务架构集群和资源管理 Master / Yarn Application Master;
  • 工作节点 Work / Node Manager;
  • 任务调度器 Driver;任务执行器 Executor

在这里插入图片描述

Flink 在运行时主要包含:客户端 Client、作业管理 Jobmanager、任务管理 Taskmanager

在这里插入图片描述
2. 任务调度

Spark Streaming 连续不断的生成微小的数据批次,构建有向无环图 DAG,Spark Streaming 会依次创建 DStreamGraph、JobScheduler。

在这里插入图片描述
Flink 根据用户提交的代码生成 StreamGraph,经过优化生成 JobGraph,然后提交给 JobManager进行处理,JobManager 会根据 JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 调度最核心的数据结构,JobManager 根据 ExecutionGraph 对 Job 进行调度,根据物理执行图部署到Taskmanager上形成具体的 Task 执行。

在这里插入图片描述
3. 时间机制

Spark Streaming 支持的时间机制有限,只支持 处理时间

Flink 支持了流处理程序在时间上的三个定义:事件时间 EventTime摄入时间 IngestionTime处理时间 ProcessingTime。同时也支持 watermark 机制来处理滞后数据。

在这里插入图片描述
4. 容错机制

  • 对于 Spark Streaming 任务,我们可以设置 checkpoint,然后假如发生故障并重启,我们可以从上次 checkpoint 之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义。
  • Flink 则使用 两阶段提交协议 来解决这个问题。

4、Flink 的架构包含哪些?

Flink 架构分为 技术架构运行架构 两部分。

5、简单介绍一下 Flink 的技术架构。

如下图为 Flink 技术架构:

在这里插入图片描述
Flink 作为流批一体的分布式计算引擎,必须提供面向开发人员的 API 层,同时还需要跟外部数据存储进行交互,需要 连接器,作业开发、测试完毕后,需要提交集群执行,需要 部署层,同时还需要运维人员能够管理和监控,还提供图计算、机器学习、SQL 等,需要 应用框架层

6、详细介绍一下 Flink 的运行架构。

如下图为 Flink 运行架构:

在这里插入图片描述
Flink 集群采取 Master - Slave 架构,Master 的角色为 JobManager,负责集群和作业管理,Slave 的角色是 TaskManager,负责执行计算任务,同时,Flink 提供客户端 Client 来管理集群和提交任务,JobManagerTaskManager 是集群的进程。

  • Client:Flink 客户端是 Flink 提供的 CLI 命令行工具,用来提交 Flink 作业到 Flink 集群,在客户端中负责 StreamGraph(流图)和 JobGraph(作业图)的构建。
  • JobManager:JobManager 根据并行度将 Flink 客户端提交的 Flink 应用分解为子任务,从资源管理器 ResourceManager 申请所需的计算资源,资源具备之后,开始分发任务到 TaskManager 执行 Task,并负责应用容错,跟踪作业的执行状态,发现异常则恢复作业等。
  • TaskManager:TaskManager 接收 JobManage 分发的子任务,根据自身的资源情况 管理子任务的启动、 停止、销毁、异常恢复等生命周期阶段。Flink 程序中必须有一个 TaskManager。

7、介绍一下 Flink 的并行度。

Flink 程序在执行的时候,会被映射成一个 Streaming Dataflow。一个 Streaming Dataflow 是由一组 Stream 和 Transformation Operator 组成的。在启动时从一个或多个 Source Operator 开始,结束于一个或多个 Sink Operator。

Flink 程序本质上是并行的和分布式的,在执行过程中,一个流(stream)包含一个或多个流分区,而每一个 operator 包含一个或多个 operator 子任务。操作子任务间彼此独立,在不同的线程中执行,甚至是在不同的机器或不同的容器上。

operator 子任务的数量是这一特定 operator 的并行度。相同程序中的不同 operator 有不同级别的并行度。

在这里插入图片描述
一个 Stream 可以被分成多个 Stream 的分区,也就是 Stream Partition。一个 Operator 也可以被分为多个 Operator Subtask。如上图中,Source 被分成 Source1 和 Source2,它们分别为 Source 的 Operator Subtask。每一个 Operator Subtask 都是在不同的线程当中独立执行的。一个 Operator 的并行度,就等于 Operator Subtask 的个数

上图 Source 的并行度为 2 2 2。而一个 Stream 的并行度就等于它生成的 Operator 的并行度。数据在两个 operator 之间传递的时候有两种模式:

  • One to One 模式:两个 operator 用此模式传递的时候,会保持数据的分区数和数据的排序;如上图中的 Source1 到 Map1,它就保留的 Source 的分区特性,以及分区元素处理的有序性。
  • Redistributing (重新分配)模式:这种模式会改变数据的分区数;每个 operator subtask 会根据选择 transformation 把数据发送到不同的目标 subtasks,比如 keyBy() 会通过 hashcode 重新分区,broadcast()rebalance() 方法会随机重新分区。

8、Flink 的并行度的怎么设置的?

我们在实际生产环境中可以从四个不同层面设置并行度:

  • 操作算子层面(Operator Level
  • 执行环境层面(Execution Environment Level
  • 客户端层面(Client Level
  • 系统层面(System Level

需要注意的优先级:算子层面 > 环境层面 > 客户端层面 > 系统层面。

9、Flink 编程模型了解不?

Flink 应用程序主要由三部分组成, source、转换 transformation、目的地 sink。这些流式 dataflows 形成了有向图,以一个或多个源(source)开始,并以一个或多个目的地(sink)结束。

在这里插入图片描述
在这里插入图片描述

10、Flink 作业中的 DataStream,Transformation 介绍一下?

Flink 作业中,包含两个基本的块:数据流DataStream)和 转换Transformation)。

DataStream 是逻辑概念,为开发者提供 API 接口,Transformation 是处理行为的抽象,包含了数据的读取、计算、写出。所以 Flink 作业中的 DataStream API 调用,实际上构建了多个由 Transformation 组成的数据处理流水线(Pipeline)。

DataStream API 和 Transformation 的转换如下图:

在这里插入图片描述

11、Flink 的分区策略了解吗?

数据分区 在 Flink 中叫作 Partition。本质上来说,分布式计算就是把 一个作业 切分成子任务 Task, 将不同的数据交给不同的 Task 计算。

在分布式存储中, Partition 分区的概念就是把数据集切分成块,每一块数据存储在不同的机器上。同样 ,对于分布式计算引擎,也需要将数据切分,交给位于不同物理节点上的 Task 计算。

StreamPartitioner 是 Flink 中的数据流分区抽象接口,决定了在实际运行中的数据流分发模式, 将数据切分交给 Task 计算,每个 Task 负责计算一部分数据流。所有的数据分区器都实现了ChannelSelector 接口,该接口中定义了负载均衡选择行为。

// ChannelSelector 接口定义
public interfaceChannelSelector<T extends IOReadablewritable> { 
    //下游可选 Channel 的数量
    void setup (intnumberOfChannels); 
    //选路方法
    int selectChannel (T record); 
    //是否向下游广播
    boolean isBroadcast();
 }

在该接口中可以看到,每一个分区器都知道下游通道数量,该通道在一次作业运行中是固定的,除非修改作业的并行度,否则该值不会改变。

目前 Flink 支持 8 8 8 种分区策略的实现,数据分区体系如下图:
在这里插入图片描述
(1)GlobalPartitioner

数据会被分发到下游算子的第一个实例中进行处理。

(2)ForwardPartitioner

在 API 层面上 ForwardPartitioner 应用在 DataStream 上,生成一个新的 DataStream。

该 Partitioner 比较特殊,用于在同一个 OperatorChain 中上下游算子之间的数据转发,实际上数据是直接传递给下游的,要求上下游并行度一样。

(3)ShufflePartitioner

随机的将元素进行分区,可以确保下游的 Task 能够均匀地获得数据,使用代码如下:

dataStream.shuffle();

(4)RebalancePartitioner

Round-robin 的方式为每个元素分配分区,确保下游的 Task 可以均匀地获得数据,避免数据倾斜。使用代码如下:

dataStream.rebalance();

(5)RescalePartitioner

根据上下游 Task 的数量进行分区, 使用 Round-robin 选择下游的一个Task 进行数据分区,如上游有 2 2 2 个 Source.,下游有 6 6 6 个 Map,那么每个 Source 会分配 3 3 3 个固定的下游 Map,不会向未分配给自己的分区写入数据。这一点与 ShufflePartitioner 和 RebalancePartitioner 不同, 后两者会写入下游所有的分区。
在这里插入图片描述

运行代码如下:

dataStream.rescale();

(6)BroadcastPartitioner

将该记录广播给所有分区,即有 N N N 个分区,就把数据复制 N N N 份,每个分区 1 1 1 份,其使用代码如下:

dataStream.broadcast();

(7)KeyGroupStreamPartitioner

在 API 层面上,KeyGroupStreamPartitioner 应用在 KeyedStream上,生成一个新的 KeyedStream。

KeyedStream 根据 keyGroup 索引编号进行分区,会将数据按 Key 的 Hash 值输出到下游算子实例中。该分区器不是提供给用户来用的。

KeyedStream 在构造 Transformation 的时候默认使用 KeyedGroup 分区形式,从而在底层上支持作业 Rescale 功能。

(8)CustomPartitionerWrapper

用户自定义分区器。需要用户自己实现 Partitioner 接口,来定义自己的分区逻辑。

static class CustomPartitioner implements Partitioner<String> {
      @Override
      public int partition(String key, int numPartitions) {
          switch (key){
              case "1":
                  return 1;
              case "2":
                  return 2;
              case "3":
                  return 3;
              default:
                  return 4;
          }
      }
  }

12、描述一下 Flink Wordcount 执行包含的步骤有哪些?

主要包含以下几步:

  • 获取运行环境 StreamExecutionEnvironment;
  • 接入 source 源 ;
  • 执行转换操作,如 map()flatmap()keyby()sum()
  • 输出 sink 源,如 print();
  • 执行 execute。

提供一个示例:

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;


public class WordCount {

    public static void main(String[] args) throws Exception {
        //定义socket的端口号
        int port;
        try{
            ParameterTool parameterTool = ParameterTool.fromArgs(args);
            port = parameterTool.getInt("port");
        }catch (Exception e){
            System.err.println("没有指定port参数,使用默认值9000");
            port = 9000;
        }
        //获取运行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        //连接socket获取输入的数据
        DataStreamSource<String> text = env.socketTextStream("10.192.12.106", port, "\n");
        //计算数据
        DataStream<WordWithCount> windowCount = text.flatMap(new FlatMapFunction<String, WordWithCount>() {
            public void flatMap(String value, Collector<WordWithCount> out) throws Exception {
                String[] splits = value.split("\\s");
                for (String word:splits) {
                    out.collect(new WordWithCount(word,1L));
                }
            }
        })//打平操作,把每行的单词转为<word,count>类型的数据
                .keyBy("word")//针对相同的word数据进行分组
                .timeWindow(Time.seconds(2),Time.seconds(1))//指定计算数据的窗口大小和滑动窗口大小
                .sum("count");
        //把数据打印到控制台
        windowCount.print()
                .setParallelism(1);//使用一个并行度
        // 注意:因为flink是懒加载的,所以必须调用execute方法,上面的代码才会执行
        env.execute("streaming word count");
    }
    /**
     * 主要为了存储单词以及单词出现的次数
     */
    public static class WordWithCount{
        public String word;
        public long count;
        public WordWithCount(){}
        public WordWithCount(String word, long count) {
            this.word = word;
            this.count = count;
        }
        @Override
        public String toString() {
            return "WordWithCount{" + 
                    "word='" + word + '\'' +
                    ", count=" + count +
                    '}';
        }
    }
}

13、Flink 常用的算子有哪些?

分两部分:

(1)数据读取,这是 Flink 流计算应用的起点,常用算子有:

  • 从内存读:fromElements
  • 从文件读:readTextFile
  • Socket 接入 :socketTextStream
  • 自定义读取:createInput

(2)处理数据的算子,主要用于 转换 过程,常用的算子包括:

  • 单输入单输出:Map
  • 单输入、多输出:FlatMap
  • 过滤:Filter
  • 分组:KeyBy
  • 聚合:Reduce
  • 窗口:Window
  • 连接:Connect
  • 分割:Split

【1】Apache Flink - 数据流上的有状态计算:https://flink.apache.org/zh/

【2】Apache Flink 文档:https://nightlies.apache.org/flink/flink-docs-release-1.17/zh/

【3】Flink大全 - 洋群满满のBlog

【4】史上最全干货!Flink面试大全总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/68147.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

模板的进阶

目录 1.非类型模板参数 2.模板特化 2.1概念 2.2函数模板特化 2.3类模板特化 2.3.1全特化 2.3.2偏特化 3.模板分离编译 3.1什么是分离编译 3.2 模板的分离编译 3.3解决方法 4. 模板总结 1.非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a…

Python(七十五--总结)列表、字典、元组、集合总结

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

关于Object 0 = new Object() 的追魂九连问

文章目录 对象的创建过程对象的组成解析普通对象**结果分析&#xff1a;**给对象添加属性注意事项 补充jvm压缩指针栗子&#xff1a; 对象头包含什么对象怎么定位&#xff1f;**句柄方式和直接引用的优缺点&#xff1a;** 对象怎么分配&#xff1f;为什么hotspot不使用c对象来代…

QT的信号槽的四种写法和五种链接方式

目录 四种信号槽写法&#xff1a; 五种连接方式&#xff1a; 实例&#xff1a; 常见错误及改正&#xff1a; 错误1: 未连接信号与槽 错误2: 信号和槽参数不匹配 错误3: 未使用Q_OBJECT宏 错误4: 跨线程连接未处理 在Qt中&#xff0c;信号&#xff08;Signal&#xff09…

Stephen Wolfram:让 ChatGPT 真正起作用的是什么?

What Really Lets ChatGPT Work? 让 ChatGPT 真正起作用的是什么&#xff1f; Human language—and the processes of thinking involved in generating it—have always seemed to represent a kind of pinnacle of complexity. And indeed it’s seemed somewhat remarkabl…

go-admin 使用开发

在项目中使用redis 作为数据缓存&#xff1a;首先引入该包 “github.com/go-redis/redis/v8” client : redis.NewClient(&redis.Options{Addr: config.QueueConfig.Redis.Addr, // Redis 服务器地址Password: config.QueueConfig.Redis.Password, // Redis 密码&…

Vue自定义指令使用

本篇文章讲述使用Vue自定义指令&#xff0c;并在项目中完成相应功能。 在平常Vue脚手架项目中&#xff0c;使用到 自定义指令较少&#xff0c;一般都是使用的自带指令&#xff0c;比如 v-show 、v-if 、 v-for 、 v-bind 之类的。这些已经能够满足大多数项目使用。更多的可能也…

springboot+mybatis实现简单的增、删、查、改

这篇文章主要针对java初学者&#xff0c;详细介绍怎么创建一个基本的springboot项目来对数据库进行crud操作。 目录 第一步&#xff1a;准备数据库 第二步&#xff1a;创建springboot项目 方法1&#xff1a;通过spring官网的spring initilizer创建springboot项目 方法2&am…

UG NX二次开发(C#)-CAM自定义铣加工的出口环境

文章目录 1、前言2、自定义铣削加工操作3、出错原因4、解决方案4.1 MILL_USER的用户参数4.2 采用自定义铣削的方式生成自定义的dll4.2 配置加工的出口环境4.3 调用dll5、结论1、前言 作为一款大型的CAD/CAM软件, UG NX为我们提供了丰富的加工模板,通过加工模板能直接用于生成…

day7 8-牛客67道剑指offer-JZ74、57、58、73、61、62、64、65、把字符串转换成整数、数组中重复的数字

文章目录 1. JZ74 和为S的连续正数序列暴力解法滑动窗口&#xff08;双指针&#xff09; 2. JZ57 和为S的两个数字3. JZ58 左旋转字符串4. JZ73 翻转单词序列5. JZ61 扑克牌顺子6. JZ62 孩子们的游戏(圆圈中最后剩下的数)迭代 模拟递归 约瑟夫环问题 找规律 7. JZ64 求123...n8…

0基础学C#笔记08:插入排序法

文章目录 前言一、过程简单描述&#xff1a;二、代码总结 前言 我们在玩打牌的时候&#xff0c;你是怎么整理那些牌的呢&#xff1f;一种简单的方法就是一张一张的来&#xff0c;将每一张牌插入到其他已经有序的牌中的适当位置。当我们给无序数组做排序的时候&#xff0c;为了…

SpringBoot 该如何预防 XSS 攻击

XSS 漏洞到底是什么&#xff0c;说实话我讲不太清楚。但是可以通过遇到的现象了解一下。在前端Form表单的输入框中&#xff0c;用户没有正常输入&#xff0c;而是输入了一段代码&#xff1a;</input><img src1 onerroralert1> 这个正常保存没有问题。问题出在了列表…

竞赛项目 深度学习疲劳驾驶检测 opencv python

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

HCIP-linux和kvm(ks配置文件自动化安装及console连虚拟机有问题)

1、linux linux安装教程参考&#xff0c;https://blog.51cto.com/cloudcs/5245337 yum源配置 本地yum源配置&#xff1a; 8版本配置&#xff1a;将光盘iso挂载到某个目录&#xff0c;/dev/cdrom是/dev/sr0软链接&#xff0c;# mount /dev/cdrom /mnt&#xff0c;# ls /mnt Ap…

.NET6使用SqlSugar操作数据库

1.//首先引入SqlSugarCore包 2.//新建SqlsugarSetup类 public static class SqlsugarSetup{public static void AddSqlsugarSetup(this IServiceCollection services, IConfiguration configuration,string dbName "ConnectString"){SqlSugarScope sqlSugar new Sq…

手动创建一个DOCKER镜像

1. 我们先使用C语言写一个hello-world程序 vim hello.c # include <stdio.h>int main() {print("hello docker\n"); } 2. 将hello.c文件编译成二进制文件, 需要安装工具 yum install gcc yum install glibc-static 开始编译 gcc -static hello.c -o hello 编译…

Mybatis Plus条件构造器LambdaQueryWrapper

官网地址 Mybatis Plus条件构造器LambdaQueryWrapper 目前数据库数据情况&#xff0c;User表 iduser_namebirthdaysexaddress1张12023-08-10男123163.com2李12023-08-10女222163.com3张22023-08-10女999163.com4张32023-08-10男9994qq.com ## 简单介绍 如何使用各种场景 方法…

基于Promise.resolve实现Koa请求队列中间件

本文作者为360奇舞团前端工程师 前言 最近在做一个 AIGC 项目&#xff0c;后端基于 Koa2 实现。其中有一个需求就是调用兄弟业务线服务端 AIGC 能力生成图片。但由于目前兄弟业务线的 AIGC 项目也是处于测试阶段&#xff0c;能够提供的服务器资源有限&#xff0c;当并发请求资源…

Java算法_ LRU 缓存(LeetCode_Hot100)

题目描述&#xff1a;请你设计并实现一个满足 LRU &#xff08;最近最少使用&#xff09; 缓存 约束的数据结构。 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 import java.util.HashMap; import java.util.Map;/*** 2 * Author: L…

微信小程序备案流程

微信小程序备案流程 &#x1f4d4; 千寻简笔记介绍 千寻简笔记已开源&#xff0c;Gitee与GitHub搜索chihiro-notes&#xff0c;包含笔记源文件.md&#xff0c;以及PDF版本方便阅读&#xff0c;且是用了精美主题&#xff0c;阅读体验更佳&#xff0c;如果文章对你有帮助请帮我…