Flink 初体验:从 Hello World 到实时数据流处理

在大数据处理领域,Apache Flink 以其卓越的流批一体化处理能力脱颖而出,成为众多企业构建实时数据应用的首选框架。本文将带领你迈出 Flink 学习的第一步,从基础概念入手,逐步引导你编写并运行第一个 Flink 程序 ------ 经典的 WordCount,让你亲身感受 Flink 在实时数据流处理方面的强大魅力。

1.1 什么是 Flink​

Flink 是一个分布式流批一体化开源平台,旨在对无界和有界数据流进行有状态计算。无界数据流是一种持续不断产生的数据,例如网站的实时访问日志、传感器的实时监测数据等;有界数据流则是在有限时间内产生的数据,像一份固定的历史订单数据集。Flink 通过统一的编程模型和运行时引擎,无缝处理这两种类型的数据,这是它区别于其他大数据框架的显著特性。​

  • 流批一体:Flink 的 DataStream API 用于处理无界数据流,DataSet API 用于处理有界数据流,但底层运行时引擎高度统一。这意味着开发者可以使用相似的编程范式处理不同性质的数据,大大降低了开发和维护成本。例如,在一个电商系统中,既可以使用 Flink 实时分析用户的实时购买行为(流处理),也可以定期分析历史订单数据(批处理),且代码逻辑有很高的复用性。
  • 低延迟、高吞吐:Flink 通过高效的内存管理、流水线执行模型以及对分布式计算的优化,能够在保证低延迟的同时实现高吞吐量。在实时推荐系统中,需要快速响应用户的操作,根据用户实时行为推荐相关商品,Flink 能够满足这种对延迟敏感的场景需求,同时处理大规模的用户行为数据。
  • 精确一次语义:在复杂的分布式数据处理场景中,数据可能会因为网络故障、节点故障等原因出现重复处理的情况。Flink 的精确一次(Exactly - Once)语义保证了无论发生什么故障,每个输入事件都只会被处理一次,确保了数据处理结果的准确性。例如在金融交易系统中,每一笔交易的处理结果必须准确无误,Flink 的精确一次语义就能提供坚实的保障。
  • 实时数据分析:企业需要实时了解业务运营状况,通过对实时产生的业务数据进行分析,及时做出决策。如电商平台实时分析商品的销售趋势、用户的购买偏好,以便及时调整营销策略。
  • 实时数据集成:从多个数据源实时采集数据,并将其整合到数据仓库或其他存储系统中。例如将来自 MySQL、Kafka 等不同数据源的数据实时同步到 Hive 数据仓库,为后续的数据分析提供基础。
  • 流上机器学习:利用实时数据流训练和更新机器学习模型,实现模型的在线学习和实时预测。在智能客服系统中,根据用户实时输入的问题,利用在线更新的机器学习模型快速给出准确回答。

在编写 Flink 程序之前,需要搭建好开发环境。这里以 Maven 项目为例,在 Java 环境下进行开发。​

2.1 安装 Java​

确保本地安装了 Java 环境,并且配置了JAVA_HOME环境变量。可以通过在命令行中输入java -version来检查 Java 是否安装成功。​

2.2 安装 Maven​

Maven 是一个项目管理工具,用于构建和管理 Java 项目。从 Maven 官网下载并解压安装包,然后配置MAVEN_HOME环境变量,将%MAVEN_HOME%\bin添加到系统的PATH变量中。在命令行中输入mvn -version验证 Maven 安装是否成功。​

2.3 创建 Maven 项目​

打开命令行,进入到合适的目录下,执行以下命令创建一个 Maven 项目:

复制代码
mvn archetype:generate -DgroupId=com.example -DartifactId=flink -example -DarchetypeArtifactId=maven -archetype -quickstart -DinteractiveMode=false

这将创建一个名为flink - example的 Maven 项目,项目结构如下:

复制代码
flink - example
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── App.java
    │   └── resources
    └── test
        ├── java
        │   └── com
        │       └── example
        │           └── AppTest.java
        └── resources

在项目的pom.xml文件中添加 Flink 相关依赖。这里以 Flink 1.14.2 版本为例,添加如下依赖:

XML 复制代码
<dependencies>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink - java</artifactId>
        <version>1.14.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink - streaming - java_2.12</artifactId>
        <version>1.14.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink - runtime_2.12</artifactId>
        <version>1.14.2</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j - api</artifactId>
        <version>1.7.32</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j - simple</artifactId>
        <version>1.7.32</version>
    </dependency>
</dependencies>

这些依赖分别包含了 Flink 的核心 Java 库、流处理库、运行时库以及日志相关库。其中flink - streaming - java_2.12中的2.12表示 Scala 的版本,因为 Flink 是基于 Scala 开发的,这里使用的是与 Scala 2.12 兼容的版本。

3.1 理解 WordCount​

WordCount 是大数据领域的经典入门程序,其功能是统计一段文本中每个单词出现的次数。在 Flink 中,我们可以使用流处理的方式来实现 WordCount,实时统计源源不断输入的文本流中的单词计数。​

3.2 代码实现​

在src/main/java/com/example目录下创建一个新的 Java 类,命名为WordCount.java,编写如下代码:

java 复制代码
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 WordCount {
    public static void main(String[] args) throws Exception {
        // 创建流执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // 从文件中读取数据作为数据源,这里假设文件名为input.txt,位于项目根目录下
        DataStreamSource<String> text = env.readTextFile("input.txt");

        // 对读取到的文本进行处理
        SingleOutputStreamOperator<WordWithCount> result = text
               .flatMap((String line, Collector<String> out) -> {
                    Arrays.stream(line.split(" ")).forEach(out::collect);
                })
               .map(word -> new WordWithCount(word, 1))
               .keyBy(WordWithCount::getWord)
               .sum("count");

        // 打印结果
        result.print();

        // 执行任务
        env.execute("WordCount Example");
    }

    // 定义一个POJO类用于存储单词及其计数
    public static class WordWithCount {
        private String word;
        private int count;

        public WordWithCount() {
        }

        public WordWithCount(String word, int count) {
            this.word = word;
            this.count = count;
        }

        public String getWord() {
            return word;
        }

        public void setWord(String word) {
            this.word = word;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }

        @Override
        public String toString() {
            return "WordWithCount{" +
                    "word='" + word + '\'' +
                    ", count=" + count +
                    '}';
        }
    }
}
3.3 代码解析​
  1. 创建流执行环境:

    java 复制代码
    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    StreamExecutionEnvironment是 Flink 流处理的入口点,通过getExecutionEnvironment方法获取一个运行时环境实例,它负责管理任务的执行和资源分配。

  2. 读取数据源:

    java 复制代码
    DataStreamSource<String> text = env.readTextFile("input.txt");

    这里使用readTextFile方法从本地文件input.txt中读取数据,将文件中的每一行作为一个元素,创建一个DataStreamSource对象,它表示一个数据流的源头。

  3. 数据处理:

    java 复制代码
    .flatMap((String line, Collector<String> out) -> {
        Arrays.stream(line.split(" ")).forEach(out::collect);
    })

    flatMap操作将输入的每一行文本按空格分割成多个单词,并将这些单词输出到下游。这里使用 Java 8 的Arrays.stream和forEach方法实现单词分割和输出。

    java 复制代码
    .map(word -> new WordWithCount(word, 1))

    map操作将每个单词映射为一个WordWithCount对象,其中单词作为word字段,初始计数为 1。

    java 复制代码
    .keyBy(WordWithCount::getWord)

    keyBy操作根据WordWithCount对象的word字段对数据流进行分组,相同单词的数据会被分到同一个组中,以便后续进行聚合操作。

    java 复制代码
    .sum("count");

    sum操作对每个组内的count字段进行求和,统计每个单词出现的总次数。

  4. 打印结果:

    java 复制代码
    result.print();

    print操作将处理后的结果打印到控制台,方便查看。在实际生产环境中,可能会将结果输出到其他存储系统,如 Kafka、HBase 等。

  5. 执行任务:

    java 复制代码
    env.execute("WordCount Example");

    execute方法触发任务的执行,参数"WordCount Example"是任务的名称,用于在 Flink 的 Web UI 中标识该任务。

四、运行 WordCount 程序​
4.1 准备测试数据​

在项目根目录下创建一个input.txt文件,输入一些文本内容,例如:

java 复制代码
hello world
hello flink
flink is great
4.2 运行程序​

在命令行中进入项目目录,执行以下命令运行程序:

java 复制代码
mvn clean package
java -cp target/flink - example - 1.0 - SNAPSHOT.jar com.example.WordCount

mvn clean package命令用于清理项目并打包成一个可执行的 JAR 文件,java -cp命令用于运行打包后的 JAR 文件,指定主类为com.example.WordCount。​

运行成功后,控制台会输出每个单词及其出现的次数,类似如下结果:

java 复制代码
WordWithCount{word='hello', count=2}
WordWithCount{word='world', count=1}
WordWithCount{word='flink', count=2}
WordWithCount{word='is', count=1}
WordWithCount{word='great', count=1}

通过这个简单的 WordCount 程序,你已经初步体验了 Flink 在实时数据流处理方面的基本操作流程。后续文章中,我们将深入探讨 Flink 的更多高级特性,如窗口操作、状态管理、Flink SQL 等,逐步提升你对 Flink 的掌握程度,构建更加复杂和强大的实时数据应用。

相关推荐
TDengine (老段)2 小时前
TDengine 数学函数 DEGRESS 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
TDengine (老段)2 小时前
TDengine 数学函数 GREATEST 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
字节数据平台3 小时前
火山引擎Data Agent再拓新场景,重磅推出用户研究Agent
大数据·人工智能·火山引擎
铭毅天下6 小时前
Elasticsearch 到 Easysearch 数据迁移 5 种方案选型实战总结
大数据·elasticsearch·搜索引擎·全文检索
跨境小新6 小时前
Facebook广告投放:地域定向流量不精准?x个优化指南
大数据·facebook
ZKNOW甄知科技7 小时前
客户案例 | 派克新材x甄知科技,构建全场景智能IT运维体系
大数据·运维·人工智能·科技·低代码·微服务·制造
币须赢8 小时前
688758赛分科技 阴上阴形态 洗盘上涨?
大数据
学掌门8 小时前
大数据知识合集之预处理方法
大数据
Elastic 中国社区官方博客9 小时前
Elasticsearch 推理 API 增加了开放的可定制服务
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
蒙特卡洛的随机游走9 小时前
Spark核心数据(RDD、DataFrame 和 Dataset)
大数据·分布式·spark