Apache Filnk----入门

文章目录

有界流和无界流

  • 无界数据流:
    • 有定义流的开始,但没有定义流的结束;
    • 它们会无休止的产生数据:
    • 无界流的数据必须持续处理,即数据被摄取后需要立刻处理我们不能等到所有数据都到达再处理,因为输入是无限的。
  • 有界数据流:
    • 有定义流的开始,也有定义流的结束:
    • 有界流可以在摄取所有数据后再进行计算:
    • 有界流所有数据可以被排序,所以并不需要有序摄取:
    • 有界流处理通常被称为批处理

有状态流处理

把流处理需要的额外数据保存成一个状态 ,然后针对这条数据进行处理,并且更新状态 。这就是所谓的"有状态的流处理"

  • 状态在内存中:优点:速度快 ;缺点:可靠性差
  • 状态在分布式系统中:优点:可靠性高;缺点:速度慢
  • 高吞吐和低延迟。每秒处理数百万个事件,毫秒级延迟。
  • 结果的准确性。Flink提供了事件时间(event-time)和处理时间(processing-time)语义对于乱序事件流,事件时间语义仍然能提供一致且准确的结果。
  • 精确一次(exactly-once)的状态一致性保证。
  • 可以连接到最常用的外部系统,如Kata、Hive、JDBC、HDFS、Redis等
  • 高可用。本身高可用的设置,加上与K8S,YARN和Mesos的紧密集成,再加上从故障中快速恢复和动态扩展任务的能力,Fhnk能做到以极少的停机时间7x24全天候运行。
  • 有状态流处理:通过底层API(处理函数),对最原始数据加工处理。底层API与DataSstrea API相集成,可以处理复杂的计算。
  • DataStream API(流处理)和DataSet API(批处理)封装了底层处理函数,提供了通用的模块,比如转换(transormations,包括map、flatmap等),连接(joms),聚合(aggregations),窗口(windows)操作等。注意:Flimk1.12以后,DataStream API已经实现真正的流批一体,所以DataSet API已经过时
  • Table API 是以表为中心的声明式编程,其中表可能会动态变化。Ible API遵循关系模型:表有二维数据结构,类似于关系数据库中的表;同时API提供可比较的操作,例如select、project、jomn、group-by、aggregate等。我们可以在表与 DataStream/Dataset 之间无缝切换,以允许程序将 Table AP与DataStream 以及 DataSet 混合使用。
  • SOL这一层在语法与表达能力上与 Table API类似,但是是以SOL查询表达式的形式表现程序。SOL抽象与Table API交互密切,同上心能有难区的时SOL查询可以直接在Table API定义的表上执行。
  • 在IDEA中创建Maven项目

  • 添加项目依赖

    java 复制代码
    <properties>
            <flink.version>1.17.0</flink.version>
    </properties>
    
    
        <dependencies>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-streaming-java</artifactId>
                <version>${flink.version}</version>
            </dependency>
    
         <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-clients</artifactId>
                <version>${flink.version}</version>
         </dependency>
    </dependencies>

WordCount 代码编写

批处理

批处理基本思路:先逐行读入文件数据,然后将每一行文字拆分成单词;接着按照单词分组,统计每组数据的个数,就是对应单词的频次。

1)数据准备

(1)在工程根目录下新建一个input文件夹,并在下面创建文本文件words.txt

(2)在words.txt中输入一些文字,例如:

复制代码
hello flink
hello world
hello java

2)代码编写

(1)在com.yudan.wc包下新建Java类BatchWordCount,在静态main方法中编写代码。具体代码实现如下:

java 复制代码
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.AggregateOperator;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.operators.FlatMapOperator;
import org.apache.flink.api.java.operators.UnsortedGrouping;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.util.Collector;

public class BatchWordCount {

    public static void main(String[] args) throws Exception {

        // 1. 创建执行环境
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
        
        // 2. 从文件读取数据  按行读取(存储的元素就是每行的文本)
        DataSource<String> lineDS = env.readTextFile("input/words.txt");
        
        // 3. 转换数据格式
        FlatMapOperator<String, Tuple2<String, Long>> wordAndOne = lineDS.flatMap(new FlatMapFunction<String, Tuple2<String, Long>>() {

            @Override
            public void flatMap(String line, Collector<Tuple2<String, Long>> out) throws Exception {

                String[] words = line.split(" ");

                for (String word : words) {
                    out.collect(Tuple2.of(word,1L));
                }
            }
        });

        // 4. 按照 word 进行分组
        UnsortedGrouping<Tuple2<String, Long>> wordAndOneUG = wordAndOne.groupBy(0);
        
        // 5. 分组内聚合统计
        AggregateOperator<Tuple2<String, Long>> sum = wordAndOneUG.sum(1);

        // 6. 打印结果
        sum.print();
    }
}

(2)输出

复制代码
(flink,1)
(world,1)
(hello,3)
(java,1)

从Flink 1.12开始,官方推荐的做法是直接使用DataStream API,在提交任务时通过将执行模式设为BATCH来进行批处理:

复制代码
$ bin/flink run -Dexecution.runtime-mode=BATCH BatchWordCount.jar

流处理

java 复制代码
import org.apache.flink.api.common.typeinfo.Types;
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;
import org.apache.flink.util.Collector;

import java.util.Arrays;

public class StreamWordCount {

    public static void main(String[] args) throws Exception {
    
        // 1. 创建流式执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        
        // 2. 读取文件
        DataStreamSource<String> lineStream = env.readTextFile("input/words.txt");
        
        // 3. 转换、分组、求和,得到统计结果
        SingleOutputStreamOperator<Tuple2<String, Long>> sum = lineStream.flatMap(new FlatMapFunction<String, Tuple2<String, Long>>() {
            @Override
            public void flatMap(String line, Collector<Tuple2<String, Long>> out) throws Exception {

                String[] words = line.split(" ");

                for (String word : words) {
                    out.collect(Tuple2.of(word, 1L));
                }
            }
        }).keyBy(data -> data.f0)
           .sum(1);

        // 4. 打印
        sum.print();
        
        // 5. 执行
        env.execute();
    }
}

输出:

复制代码
3> (java,1)
5> (hello,1)
5> (hello,2)
5> (hello,3)
13> (flink,1)
9> (world,1)
  • 主要观察与批处理程序BatchWordCount的不同:
    • 创建执行环境的不同,流处理程序使用的是StreamExecutionEnvironment。
    • 转换处理之后,得到的数据对象类型不同。
    • 分组操作调用的是keyBy方法,可以传入一个匿名函数作为键选择器(KeySelector),指定当前分组的key是什么。
    • 代码末尾需要调用env的execute方法,开始执行任务。

读取socket文本流

在实际的生产环境中,真正的数据流其实是无界的,有开始却没有结束,这就要求我们需要持续地处理捕获的数据。为了模拟这种场景,可以监听socket端口,然后向该端口不断的发送数据。

java 复制代码
import org.apache.flink.api.common.typeinfo.Types;
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;
import org.apache.flink.util.Collector;

import java.util.Arrays;

public class SocketStreamWordCount {

    public static void main(String[] args) throws Exception {

        // 1. 创建流式执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        
        // 2. 读取文本流:hadoop102表示发送端主机名、7777表示端口号
        DataStreamSource<String> lineStream = env.socketTextStream("hadoop102", 7777);
        
        // 3. 转换、分组、求和,得到统计结果
        SingleOutputStreamOperator<Tuple2<String, Long>> sum = lineStream.flatMap((String line, Collector<Tuple2<String, Long>> out) -> {
            String[] words = line.split(" ");

            for (String word : words) {
                out.collect(Tuple2.of(word, 1L));
            }
        }).returns(Types.TUPLE(Types.STRING, Types.LONG))
                .keyBy(data -> data.f0)
                .sum(1);

        // 4. 打印
        sum.print();
        
        // 5. 执行
        env.execute();
    }
}

Flink还具有一个类型提取系统,可以分析函数的输入和返回类型,自动获取类型信息,从而获得对应的序列化器和反序列化器。但是,由于Java中泛型擦除的存在,在某些特殊情况下(比如Lambda表达式中),自动提取的信息是不够精细的------只告诉Flink当前的元素由"船头、船身、船尾"构成,根本无法重建出"大船"的模样;这时就需要显式地提供类型信息,才能使应用程序正常工作或提高其性能。

因为对于flatMap里传入的Lambda表达式,系统只能推断出返回的是Tuple2类型,而无法得到Tuple2<String, Long>。只有显式地告诉系统当前的返回类型,才能正确地解析出完整数据。

相关推荐
欧先生^_^10 小时前
学习 Apache Kafka
学习·kafka·apache
别这么骄傲10 小时前
Flink概念-状态一致性的三种级别
大数据·flink
欧先生^_^13 小时前
Apache Spark 源码解析
大数据·spark·apache
w236173460114 小时前
Apache中间件解析漏洞与安全加固
安全·中间件·apache
24k小善15 小时前
FlinkSql入门与实践
java·大数据·flink·云计算
gegeyanxin20 小时前
Flink checkpoint问题排查指南
flink·数据倾斜·checkpoint失败
中科三方1 天前
APP和小程序需要注册域名吗?(国科云)
小程序·apache
晴天彩虹雨2 天前
Flink 数据清洗与字段标准化最佳实践
大数据·数据仓库·flink
24k小善2 天前
Flink TaskManager详解
java·大数据·flink·云计算
Flink_China2 天前
抖音集团电商流量实时数仓建设实践
大数据·flink