• Flink (一)概述


    第一章 Flink 简介

    1.1 初识 Flink

    Flink 起源于 Stratosphere 项目,Stratosphere 是在 2010~2014 年由 3 所地处柏林的大学和欧洲的一些其他的大学共同进行的研究项目, 2014 年 4 月 Stratosphere 的代码被复制并捐赠给了 Apache 软件基金会, 参加这个孵化项目的初始成员是Stratosphere 系统的核心开发人员, 2014 年 12 月, Flink 一跃成为 Apache 软件基金会的顶级项目。

    在德语中,Flink 一词表示快速和灵巧,项目采用一只松鼠的彩色图案作为 logo,这不仅是因为松鼠具有快速和灵巧的特点,还因为柏林的松鼠有一种迷人的红棕色, 而 Flink 的松鼠 logo 拥有可爱的尾巴, 尾巴的颜色与 Apache 软件基金会的 logo 颜色相呼应,也就是说,这是一只 Apache 风格的松鼠。


    Flink 项目的理念是:“Apache Flink 是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源流处理框架”。

    Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。

    Flink 被设计在所有常见的集群环境中运行,以内存执行速度和任意规模来执行计算。

    为什么选择 Flink?

    流数据更真实地反映了我们的生活方式
    • 传统的数据架构是基于有限数据集的
    • 我们的目标
        ➢ 低延迟
        ➢ 高吞吐
        ➢ 结果的准确性和良好的容错性

    哪些行业需要处理流数据?

    • 电商和市场营销➢ 数据报表、广告投放、业务流程需要

    • 物联网(IOT)➢ 传感器实时数据采集和显示、实时报警,交通运输业

    • 电信业➢ 基站流量调配

    • 银行和金融业➢ 实时结算和通知推送,实时检测异常行为

    1.2 Flink 的重要特点

    事件驱动型(Event-driven)

    事件驱动型应用是一类具有状态的应用, 它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。比较典型的就是以 kafka 为代表的消息队列几乎都是事件驱动型应用。
    与之不同的就是 SparkStreaming 微批次,如图:

    事件驱动型:

    流与批的世界观

    批处理的特点是 有界、持久、大量,非常适合需要访问全套记录才能完成的计算工作, 一般用于离线统计。

    流处理的特点是 无界、实时, 无需针对整个数据集执行操作,而是对通过系统传输的每个数据项执行操作,一般用于实时统计。

    在 spark 的世界观中,一切都是由批次组成的, 离线数据是一个大批次, 而实时数据是由一个一个无限的小批次组成的。

    而在 flink 的世界观中,一切都是由流组成的,离线数据是有界限的流,实时数据是一个没有界限的流,这就是所谓的有界流和无界流。

    无界数据流: 无界数据流有一个开始但是没有结束,它们不会在生成时终止并提供数据,必须连续处理无界流,也就是说必须在获取后立即处理 event。对于无界数据流我们无法等待所有数据都到达,因为输入是无界的,并且在任何时间点都不会完成。处理无界数据通常要求以特定顺序(例如事件发生的顺序)获取 event,以便能够推断结果完整性。

    有界数据流: 有界数据流有明确定义的开始和结束,可以在执行任何计算之前通过获取所有数据来处理有界流,处理有界流不需要有序获取,因为可以始终对有界数据集进行排序,有界流的处理也称为批处理。

    这种以流为世界观的架构,获得的最大好处就是具有极低的延迟

    最大区别

    • Flink是基于事件的真正的实时流式处理,Spark是批量或者微批处理
    • Flink 用流处理去模拟批处理的思想,比Spark 用批处理去模拟流处理的思想扩展性更好。

    Flink最核心的数据结构是Stream,它代表一个运行在多分区上的并行流。在 Stream 上同样可以进行各种转换操作(Transformation)。与 Spark 的 RDD 不同的是,Stream 代表一个数据流而不是静态数据的集合。所以,它包含的数据是随着时间增长而变化的。而且 Stream 上的转换操作都是逐条进行的,即每当有新的数据进来,整个流程都会被执行并更新结果。这样的基本处理模式决定了 Flink 会比 Spark Streaming 有更低的流处理延迟性。

    状态

    • Flink比Spark支撑更多的状态操作。

    Spark比flink有的优势

    • 从SQL 功能的角度来讲,Spark和Flink分别提供SparkSQL和Table APl提供SQL
    • Spark对SQL支持更好,相应的优化、扩展和性能更好,而Flink在SQL支持方面还有很大提升空间。

    分层 api

    • 越顶层越抽象,表达含义越简明,使用越方便
    • 越底层越具体,表达能力越丰富,使用越灵活

    最底层级的抽象仅仅提供了有状态流,它将通过过程函数( Process Function) 被嵌入到 DataStream API 中。底层过程函数( Process Function) 与 DataStream API 相集成,使其可以对某些特定的操作进行底层的抽象,它允许用户可以自由地处理来自一个或多个数据流的事件,并使用一致的容错的状态。除此之外,用户可以注册事件时间并处理时间回调,从而使程序可以处理复杂的计算。

    实际上,大多数应用并不需要上述的底层抽象,而是针对核心 API( Core APIs) 进行编程,比如 DataStream API( 有界或无界流数据) 以及 DataSet API(有界数据集)。这些 API 为数据处理提供了通用的构建模块, 比如由用户定义的多种形式的转换( transformations),连接( joins),聚合( aggregations),窗口操作( windows) 等等。DataSet API 为有界数据集提供了额外的支持, 例如循环与迭代。这些 API 处理的数据类型以类( classes)的形式由各自的编程语言所表示。

    Table API 是以表为中心的声明式编程,其中表可能会动态变化( 在表达流数据时)。Table API 遵循(扩展的)关系模型:表有二维数据结构( schema)( 类似于关系数据库中的表),同时 API 提供可比较的操作,例如 select、project、join、group-by、aggregate 等。Table API 程序声明式地定义了什么逻辑操作应该执行,而不是准确地确定这些操作代码的看上去如何。

    尽管 Table API 可以通过多种类型的用户自定义函数( UDF)进行扩展,其仍不如核心 API 更具表达能力, 但是使用起来却更加简洁( 代码量更少)。除此之外, Table API 程序在执行之前会经过内置优化器进行优化。

    你可以在表与 DataStream/DataSet   之间无缝切换,以允许程序将 Table API   与DataStream   以及 DataSet   混合使用。

    Flink 提供的最高层级的抽象是 SQL 。这一层抽象在语法与表达能力上与Table API 类似,但是是以 SQL 查询表达式的形式表现程序。SQL 抽象与 Table API 交互密切,同时 SQL 查询可以直接在 Table API 定义的表上执行。

    目前 Flink 作为批处理还不是主流,不如 Spark 成熟,所以 DataSet 使用的并不是很多。Flink Table API 和 Flink SQL 也并不完善,大多都由各大厂商自己定制。所以我们主要学习 DataStream API 的使用。实际上 Flink 作为最接近 Google DataFlow 模型的实现,是流批统一的观点,所以基本上使用 DataStream 就可以了。

    Flink 几大模块

    • Flink Table & SQL(还没开发完)
    • Flink Gelly(图计算)
    • Flink CEP(复杂事件处理)
    • 支持事件时间(event-time)和处理时间(processing-time)语义
    • 精确一次(exactly-once)的状态一致性保证
    • 低延迟,每秒处理数百万个事件,毫秒级延迟
    • 与众多常用存储系统的连接高可用,动态扩展,实现7*24小时全天候运行

    1.3 Flink四大基石

    • checkpoint:基于chandy-lamport算法实现分布式计算任务的一致性语义;
    • state:flink中的状态机制,flink天生支持state,state可以认为程序的中间计算结果或者是历史计算结果;
    • time:flink中支持基于事件时间和处理时间进行计算,spark streaming只能按照process time进行处理;基于事件时间的计算我们可以解决数据迟到和乱序等问题。
    • window:flink提供了更多丰富的window,基于时间,基于数量,session window,同样支持滚动和滑动窗口的计算。

    第二章 快速上手

    2.1 搭建 maven工程 FlinkTutorial

    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.atguigu</groupId>
        <artifactId>FlinkTutorial</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-java</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-streaming-java_2.12</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-connector-kafka-0.11_2.12</artifactId>
                <version>1.10.1</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.12</artifactId>
                <version>1.10.1</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.12</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-table-planner_2.12</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-table-planner-blink_2.12</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-csv</artifactId>
                <version>1.10.1</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>
    </project>

    2.2 批处理wordcount

    import org.apache.flink.api.common.functions.FlatMapFunction;
    import org.apache.flink.api.java.DataSet;
    import org.apache.flink.api.java.ExecutionEnvironment;
    import org.apache.flink.api.java.tuple.Tuple2;
    import org.apache.flink.util.Collector;
    
    // 批处理word count
    public class WordCount {
        public static void main(String[] args) throws Exception{
            // 创建执行环境
            ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
    
            // 从文件中读取数据
            String inputPath = "D:\\bigdata\\Flink\\FlinkTutorial\\src\\main\\resources\\hello.txt";
            DataSet<String> inputDataSet = env.readTextFile(inputPath);
    
            // 对数据集进行处理,按空格分词展开,转换成(word, 1)二元组进行统计
            DataSet<Tuple2<String, Integer>> resultSet = inputDataSet.flatMap(new MyFlatMapper())
                    .groupBy(0)    // 按照第一个位置的word分组
                    .sum(1);    // 将第二个位置上的数据求和
    
            resultSet.print();
        }
    
        // 自定义类,实现FlatMapFunction接口]
        // Flink Tuple2
        public static class MyFlatMapper implements FlatMapFunction<String, Tuple2<String, Integer>> {
            @Override
            public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
                // 按空格分词
                String[] words = value.split(" ");
                // 遍历所有word,包成二元组输出
                for (String word : words) {
                    out.collect(new Tuple2<>(word, 1));
                }
            }
        }
    }

    2.3 流处理wordcount

    import org.apache.flink.api.java.tuple.Tuple2;
    import org.apache.flink.streaming.api.datastream.DataStreamSource;
    import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    
    public class StreamWordCount {
        public static void main(String[] args) throws Exception{
    //        1、创建流处理执行环境
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    //        **设置并行度(线程)**
            env.setParallelism(8);//最大线程分区为8,控制台输出最大值为“8>”
    //    2、从文件读取数据
            String inputPuth = "D:\\bigdata\\Flink\\FlinkTutorial\\src\\main\\resources\\hello.txt";
            DataStreamSource<String> inputDataStream = env.readTextFile(inputPuth);
    //       3、基于数据流进行转换计算,调用笔记(一)中的MyFlatMapper();
            SingleOutputStreamOperator<Tuple2<String, Integer>> resultStream = inputDataStream.flatMap(new WordCount.MyFlatMapper())
                    .keyBy(0)
                    .sum(1);
    //      4、输出
            resultStream.print();
    //       5、执行任务
            env.execute();
        }
    }

    网络流传输

    import org.apache.flink.api.java.tuple.Tuple2;
    import org.apache.flink.streaming.api.datastream.DataStream;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    
    public class StreamWordCount2 {
        public static void main(String[] args) throws Exception{
    
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
            DataStream<String> inputDataStream = env.socketTextStream("linux101", 7777);
    
            DataStream<Tuple2<String, Integer>> wordCountDataStream = inputDataStream
                    .flatMap( new WordCount.MyFlatMapper())
                    .keyBy(0)
                    .sum(1); wordCountDataStream.print().setParallelism(1);
    
            env.execute();
        }
    }

    测试—— 在 linux101机器中中用 netcat 命令进行发送测试。

    nc -lk 7777

    第三章 集群搭建

    3.1 flink的安装模式

    三种:

    local:单机模式,尽量不使用

    standalone:flink自带集群,资源管理由flink集群管理

    flink on yarn: 把资源管理交给yarn实现。

    image-20200415124521431

    安装环境准备:

    jdk1.8及以上版本,免密登录;

    flink的安装包,下载地址:https://flink.apache.org/zh/downloads.html

    同时下载额外组件,放到 lib 目录下https://repo.maven.apache.org/maven2/org/apache/flink/flink-shaded-hadoop-2-uber/2.8.3-10.0/flink-shaded-hadoop-2-uber-2.8.3-10.0.jar

    3.2 standalone模式

    原理

    解压flink安装包

    [wkf@hadoop102 software]$ tar -xf flink-1.10.1-bin-scala_2.12.tgz -C /opt/module

    上传hadoop组件到flink的lib目录

    修改配置文件 conf/flink-conf.yaml

    jobmanager.rpc.address: hadoop102
    jobmanager.rpc.port: 6123
    jobmanager.heap.size: 1024
    taskmanager.heap.size: 1024
    taskmanager.numberOfTaskSlots: 4 #设置slots数为CPU核心数
    taskmanager.memory.preallocate: false
    parallelism.default: 1
    jobmanager.web.port: 8081
    taskmanager.tmp.dirs: /export/servers/flink/tmp
    web.submit.enable: true

    修改master文件 conf/master

    hadoop102:8081

    修改conf目录下slave文件

    hadoop103
    hadoop104

    配置hadoop_conf_dir到/etc/profile中,是flink on yarn的时候使用

    分发flink目录到其它节点

    [wkf@hadoop102 module]$ xsync flink-1.10.1/

    启动集群

    bin/start-cluster.sh 

    停止集群

     bin/stop-cluster.sh

    单独启动jobmanager或者taskmanager

    bin/jobmanager.sh start/stop
    bin/taskmanager.sh start/stop

    h提交任务到standalone集群

    /export/servers/flink/bin/flink run  /export/servers/flink/examples/batch/WordCount.jar 
    --input hdfs://node1:8020/wordcount/input/words.txt --output hdfs://node1:8020/wordcount/output/result.txt  --parallelism 2

    注意:使用的数据文件是hdfs上,不能是本地文件路径,因为会找不到文件。


    访问 http://hadoop102:8081 可以对 flink 集群和任务进行监控管理。

     

    Web UI提交job

    启动Flink后,可以在Web UI的Submit New Job提交jar包,然后指定Job参数。

    • Entry Class

      程序的入口,指定入口类(类的全限制名)

    • Program Arguments

      程序启动参数,例如--host localhost --port 7777

    • Parallelism

      设置Job并行度。

      Ps:并行度优先级(从上到下优先级递减)

      • 代码中算子setParallelism()
      • ExecutionEnvironment env.setMaxParallelism()
      • 设置的Job并行度
      • 集群conf配置文件中的parallelism.default

      ps:socket等特殊的IO操作,本身不能并行处理,并行度只能是1

    • Savepoint Path

      savepoint是通过checkpoint机制为streaming job创建的一致性快照,比如数据源offset,状态等。

      (savepoint可以理解为手动备份,而checkpoint为自动备份)

    ps:提交job要注意分配的slot总数是否足够使用,如果slot总数不够,那么job执行失败。(资源不够调度)

    这里提交前面demo项目的StreamWordCount,在本地socket即nc -lk 7777中输入字符串,查看结果

    输入:

    hello world
    ni hao

    点击Submit提交

     到Task Managers查看输出

    命令行提交job

    查看已提交的所有job

     $ bin/flink list      
        Waiting for response...
        ------------------ Running/Restarting Jobs -------------------
        30.01.2021 17:09:45 : 30d9dda946a170484d55e41358973942 : Flink Streaming Job (RUNNING)
        --------------------------------------------------------------
        No scheduled jobs.

    提交job
         -c指定入口类
          -p指定job的并行度
    bin/flink run -c <入口类> -p <并行度> <jar包路径> <启动参数>

    $ bin/flink run -c com.atguigu.wc.StreamWordCount -p 3 /tmp/Flink_Tutorial-1.0-SNAPSHOT.jar --host hadoop02 --port 7777
    Job has been submitted with JobID 33a5d1f00688a362837830f0b85fd75e

    取消job

    bin/flink cancel <Job的ID>

    $ bin/flink cancel 30d9dda946a170484d55e41358973942
    Cancelling job 30d9dda946a170484d55e41358973942.
    Cancelled job 30d9dda946a170484d55e41358973942.

    注:Total Task Slots只要不小于Job中Parallelism最大值即可。

    eg:这里我配置文件设置taskmanager.numberOfTaskSlots: 3,实际Job运行时总Tasks显示7,具体4个任务步骤分别需求(1,3,2,1)数量的Tasks。

    3.3 yarn模式

    ​ Flink提供了两种在yarn上运行的模式,分别为Session-Cluster和Per-Job-Cluster模式。

    Sesstion Cluster模式

    ​ Session-Cluster 模式需要先启动集群,然后再提交作业,接着会向 yarn 申请一块空间后,资源永远保持不变。如果资源满了,下一个作业就无法提交,只能等到 yarn 中的其中一个作业执行完成后,释放了资源,下个作业才会正常提交。所有作业共享 Dispatcher 和 ResourceManager共享资源;适合规模小执行时间短的作业。

    在 yarn 中初始化一个 flink 集群,开辟指定的资源,以后提交任务都向这里提交。这个 flink 集群会常驻在 yarn 集群中,除非手工停止。

    启动hadoop集群(略)

    启动yarn-session

    yarn-sisson.sh是flink/bin/的命令,并不是hadoop的yarn的命令。

    bin/yarn-session.sh -n 2 -s 2 -jm 1024 -tm 1024 -nm test -d

    其中:

    •  -n(--container):TaskManager的数量。现在版本里- n已经没有了,不指定TaskManager个数,动态分配TaskManager
    •  -s(--slots):每个TaskManager的slot数量,默认一个slot一个core,默认每个taskmanager的slot的个数为1,有时可以多一些taskmanager,做冗余。
    •  -jm:JobManager的内存(单位MB)。
    •  -tm:每个taskmanager的内存(单位MB)。
    •  -nm:yarn 的appName(现在yarn的ui上的名字)。
    •  -d:后台执行。

    执行任务

    bin/flink run -c com.atguigu.wc.StreamWordCount /tmp/FlinkTutorial-1.0-SNAPSHOT.jar --host hadoop102 –-port 7777

    去 yarn 控制台查看任务状态

    取消 yarn-session

    yarn application --kill application_1645258252906_0001

    Per Job Cluster 模式

    ​ 一个 Job 会对应一个集群,每提交一个作业会根据自身的情况,都会单独向 yarn 申请资源,直到作业执行完成,一个作业的失败与否并不会影响下一个作业的正常提交和运行。独享 Dispatcher 和 ResourceManager,按需接受资源申请;适合规模大长时间运行的作业。

    每次提交都会创建一个新的 flink 集群,任务之间互相独立,互不影响,方便管理。任务执行完成之后创建的集群也会消失。

    启动hadoop集群(略)
    不启动yarn-session,直接执行job

    bin/flink run -m yarn-cluster -c com.atguigu.wc.StreamWordCount /tmp/FlinkTutorial-1.0-SNAPSHOT.jar --host hadoop102 –-port 7777

    3.4 Kubernetes部署

    ​ 容器化部署时目前业界很流行的一项技术,基于Docker镜像运行能够让用户更加方便地对应用进行管理和运维。容器管理工具中最为流行的就是Kubernetes(k8s),而Flink也在最近的版本中支持了k8s部署模式。

    搭建Kubernetes集群(略)

    配置各组件的yaml文件

    在k8s上构建Flink Session Cluster,需要将Flink集群的组件对应的docker镜像分别在k8s上启动,包括JobManager、TaskManager、JobManagerService三个镜像服务。每个镜像服务都可以从中央镜像仓库中获取。

    启动Flink Session Cluster

    // 启动jobmanager-service 服务
    kubectl create -f jobmanager-service.yaml
    // 启动jobmanager-deployment服务
    kubectl create -f jobmanager-deployment.yaml
    // 启动taskmanager-deployment服务
    kubectl create -f taskmanager-deployment.yaml

    访问Flink UI页面

    集群启动后,就可以通过JobManagerServicers中配置的WebUI端口,用浏览器输入以下url来访问Flink UI页面了:

    http://{JobManagerHost:Port}/api/v1/namespaces/default/services/flink-jobmanager:ui/proxy

  • 相关阅读:
    paramiko模块
    linux 文件权限管理
    itext 生成pdf文件添加页眉页脚
    Python3 断言
    net core WebApi——文件分片上传与跨域请求处理
    Linux配置部署_新手向(二)——Nginx安装与配置
    Linux配置部署_新手向(一)——CentOS系统安装
    net core Webapi基础工程搭建(七)——小试AOP及常规测试_Part 2
    net core Webapi基础工程搭建(六)——数据库操作_Part 2
    net core Webapi基础工程搭建(七)——小试AOP及常规测试_Part 1
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/15889369.html
Copyright © 2020-2023  润新知