Flink

本文详细介绍了Apache Flink的流处理和批处理,包括从Maven配置到WebUI设置,以及如何通过Socket和Kafka读取数据。文中展示了使用Scala和Java实现的WordCount示例,对比了流处理与批处理的区别,并提供了从Kafka消费数据的代码。此外,还讲解了开启Socket服务的不同方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Flink流处理批处理socket实时处理详细讲解及从Kafka读取数据实操


处理方式分为

  • 流式处理(离线)
  • 批处理(离线)
  • Scoket(使用流处理方式实时处理)

Maven文件

文件名:pom.xml

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <flink.version>1.10.1</flink.version>
        <java.version>1.8</java.version>
        <scala.binary.version>2.11.8</scala.binary.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>
    <dependencies>
        <!--导入flink对scala的依赖-->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-scala_2.11</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-clients_2.11</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <!--导入flink对java的依赖-->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-java</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <!--引入flink对批处理的依赖-->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-table_2.11</artifactId>
            <version>1.7.2</version>
        </dependency>
        <!--引入flink scala版本对流式处理的依赖 -->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-scala_2.11</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <!--引入flink java版本对流式处理的依赖-->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-java_2.11</artifactId>
            <version>${flink.version}</version>
        </dependency>
        <!--    &lt;!&ndash; 指定mysql-connector的依赖 &ndash;&gt;
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.38</version>
            </dependency>-->
        <!--log4j日志插件-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!-- scala编译插件 -->
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.1.6</version>
                <configuration>
                    <scalaCompatVersion>2.11</scalaCompatVersion>
                    <scalaVersion>2.11.12</scalaVersion>
                    <encoding>UTF-8</encoding>
                </configuration>
                <executions>
                    <execution>
                        <id>compile-scala</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile-scala</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- 打jar包插件(会包含所有依赖) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <!-- 可以设置jar包的入口类(可选) -->
                            <mainClass>com.kevin.batch.BatchWordCountScala</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Flink版本用1.10.2进行批处理时会报错,所以用1.10.1

开启WebUI

添加Pom文件

     <!--导入Flink的WebUI界面 端口号默认8081-->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-runtime-web_2.11</artifactId>
            <version>${flink.version}</version>
        </dependency>

在代码中修改:

	val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration())

代码详解

推荐先看完下面三种模式 ,再来看解释和区别比较清晰

流选择

StreamExecutionEnvironment流常用三种

//如果是在idea里面执行,会使用本地环境,在命令行里面执行jar文件,会使用当前的执行环境
StreamExecutionEnvironment.getExecutionEnvironment();
//使用本地环境
StreamExecutionEnvironment.createLocalEnvironment();
//使用远程环境,参数主机地址、端口号、需要提交的jar包
StreamExecutionEnvironment.createRemoteEnvironment(String host, int port, String... jarFiles);

开启WebUI:

StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration())

源码:

public static StreamExecutionEnvironment createRemoteEnvironment(String host, int port, Configuration clientConfig, String... jarFiles) {
    return new RemoteStreamEnvironment(host, port, clientConfig, jarFiles);
}

Configuration中可以修改web访问端口号(默认8081)其他设置应该也是可以生效的。

添加源

1.添加文件作为源

DataStream<String> text = env.readTextFile("f://words.txt");

2.添加输入流作为源

3.添加集合作为源

DataStream<Integer> text = env.fromElements(1, 2, 3, 4, 5);

4.添加地址作为源

DataStream<Tuple2<String, Integer>> dataStream = env.socketTextStream("localhost", 9999)

我们来查看socketTextStream源码:

@PublicEvolving
public DataStreamSource<String> socketTextStream(String hostname, int port) {
    return this.socketTextStream(hostname, port, "\n");
}
 
@PublicEvolving
public DataStreamSource<String> socketTextStream(String hostname, int port, String delimiter) {
    return this.socketTextStream(hostname, port, delimiter, 0L);
}
 
@PublicEvolving
public DataStreamSource<String> socketTextStream(String hostname, int port, String delimiter, long maxRetry) {
    return this.addSource(new SocketTextStreamFunction(hostname, port, delimiter, maxRetry), (String)"Socket Stream");
}

一共3个方法,最多四个参数,hostname主机地址和port端口号是必须的,delimiter分割符,默认"\n",maxRetry最大重试时间,单位秒,默认0,代表出错立即停止连接,负数代表没有限制反复重连

流处理

对应离线的数据,则规划为有界流;

对于实时的数据划为无界流。

文件内容:

陈佳豪 50分钟
魏德仁	5分钟
狗 15小时
猪 5分钟

文件名:BatchWordCount.scala

import  org.apache.flink.api.scala._
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
/**
 * ClassName BatchWordCount
 * Description: 使用流处理方式编写WordCount
 * Create by 陈佳豪
 * Date 2021/10/22 1:29
 */
object BatchWordCount {
  def main(args: Array[String]): Unit = {
    val input = "D:\\MapReduce_test\\wordCountText\\input"
    //设置你的执行环境。 任务执行环境用于定义任务的属性、创建数据源以及最终启动任务的执行 设置批执行环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    	env.setParallelism(1)//并行度设置为1
      // 得到输入数据
    val text = env.readTextFile(input)
    //使用流式处理统计词频
    val value = text.flatMap(_.toLowerCase().split(" "))//将数据转换为小写,然后按照空格进行切分
      .map((_, 1))//将数据转化为(word,1)的形式
      .filter(_.nonEmpty)//filter过滤掉空的
      .keyBy(0)// keyBy(0)代表按照元组第一个元素进行分区
      .sum(1)//按照第一个字段求和
    value.print()
    env.execute("Streaming Count")

如果不添加env.setParallelism(1)设置并行度为一,运行结果前面的1> 代表并行度,也就是多线程的数量的编号

批处理

文件名:BatchWordCount.scala

import org.apache.flink.streaming.api.scala._
import org.apache.flink.api.scala.{DataSet, ExecutionEnvironment}
object BatchWordCount {
  def main(args: Array[String]): Unit = {
    val filePath = "D:\\MapReduce_test\\wordCountText\\input"
    //设置你的执行环境。 任务执行环境用于定义任务的属性、创建数据源以及最终启动任务的执行 设置批执行环境
    val env = ExecutionEnvironment.getExecutionEnvironment
    // get input data
    val text: DataSet[String] = env.readTextFile(filePath)
    //使用批处理统计处理词频
    val counts = text.flatMap(_.toLowerCase().split(" "))
      .map((_, 1)).groupBy(0).sum(1).print()
    //执行任务
    env.execute("Streaming Count")
  }
}

Scoket模式

scala的Scoket可以调用javaAPI,所以与java代码差不多

实现功能大体如下:客户端发送一个序列化参数,里面以空格分割几个参数,在服务端进行接收,并分割字符串,获取到一个字符串数组,然后对其进行模式匹配,返回不同的处理结果,写入到输出流中,客户端获取到返回的结果并打印。

开启Scoket服务

方式1:Java代码开启UDP
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.*;
import java.util.Scanner;
public class SocketForWordCount {
    public static void main(String[] args) throws IOException {
        // TCP通信,服务端口8888
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("开始等待连接...");
        Socket accept = serverSocket.accept();
        System.out.println("连接成功...");
        // 封装udp并发送数据
        Scanner sc = new Scanner(System.in);
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        try {
            String line = "";
            System.out.println("请输入单词串,各单词以空格分割.");
            while (!"#".equals(line = sc.nextLine())) {
                writer.write(line);
                writer.newLine();
                writer.flush();
                System.out.println("发送:" + line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            accept.close();
        }
    }
}

从Scoket读取数据之前要先开启Scoket服务(先运行SocketForWordCount类),然后再运行Scoket流

方式2:windows上部署netcat

下载链接:diegocr/netcat: NetCat for Windows (github.com)

​ 配置环境变量 netcat下载和运行时需要关闭火绒不然会报毒

输入命令:nc -lL -p 8888回车等待启动代码程序

方式3:Scala方式开启Scoket

懒得写

参考java改下就行

Scala版本代码

实时处理数据

​ Scala版本

	//设置执行环境 StreamExecutionEnvironment为流处理
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //指定数据源,读取socket
    val socketStream = env.socketTextStream("localhost", 8888, '\n')
    //对数据集指定转换操作逻辑
    val count = socketStream
      .flatMap(_.toLowerCase.split(" "))//读取数据转为小写然后按照空格切分
      .filter(_.nonEmpty)//filter过滤掉空的
      .map((_, 1))//将数据转化为(word,1)的形式
      .keyBy(0)// keyBy(0)代表按照元组第一个元素进行分区
      .sum(1)//按照第一个字段求和
    //将计算结果打印到控制台
    count.print()
    //指定任务名称并触发流式任务
    env.execute("Socket Stream")
  }

Java版本代码

实时处理数据

​ java版本

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;

// 获取Socket传过来的数据进行word count
public class SocketWordCount {
    public static void main(String[] args) throws Exception {
        // 1.创建流处理环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // 2. 从Socket获取数据
        DataStream<String>  inputDataStream = env.socketTextStream("localhost",8888);

        // 3.基于数据流进行计算
        //   3.1 map之后进行flat扁平化,转换为 word,count 的形式 如<hello,1>
        DataStream<Tuple2<String,Integer>> resultStream = inputDataStream.flatMap(new MyFlatMapper())
        //   3.2 keyBy类似于group by
                .keyBy(0)
                .sum(1);
        // 4.输出结果
        resultStream.print();
        // 5.启动流任务
        env.execute();
    }

    private static class MyFlatMapper implements FlatMapFunction<String, Tuple2<String,Integer>> {
        @Override
        public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
            // 1.按空格分词
            String[] words = value.split(" ");
            // 2.将word封装为二元组
            for (String word : words) {
                Tuple2<String,Integer> tuple2 = new Tuple2<>(word,1);
                // 使用out收集器收集数据
                out.collect(tuple2);
            }
        }
    }
}

批处理和流处理不同

(1)环境不同

批处理:

  val env = ExecutionEnvironment.getExecutionEnvironment

流处理:

val env = StreamExecutionEnvironment.getExecutionEnvironment

(2)启动不同

流处理:

env.execute(“Streaming Count”)

批处理:

启动程序即可。

读取Kafka消息队列的数据作为来源

Maven: pom.xml

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-kafka-0.11_2.11</artifactId>
    <version>1.10.0</version>
</dependency>

SourceForKafka.scala

import java.util.Properties
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011
/**
 * 以kafka消息队列的数据作为来源
 */
object SourceForKafka {
  def main(args: Array[String]): Unit = {
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
     //设置kafka相关参数 当然 这是最基础的配置 还可以添加其他的配置
    val properties: Properties = new Properties()
    properties.setProperty("bootstrap.servers", "10.30.59.160: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")
 	//创建kafka的DataSource 使用addsource方法
    //反序列化方案 SimpleStringSchema 将字节流转换成简单的字符串
    val kafkaDstream:DataStream[String] = env.addSource( new FlinkKafkaConsumer011[String]("sensor", new SimpleStringSchema(), properties))

    kafkaDstream.print("source for kafka")

    env.execute("source test job")
  }
}

开启kafka生产者

// kafka数据生产者
./bin/kafka-console-producer.sh --broker-list 10.30.59.160:9092 --topic sensor

ation.StringDeserializer")
properties.setProperty(“auto.offset.reset”, “latest”)
//创建kafka的DataSource 使用addsource方法
//反序列化方案 SimpleStringSchema 将字节流转换成简单的字符串
val kafkaDstream:DataStream[String] = env.addSource( new FlinkKafkaConsumer011[String](“sensor”, new SimpleStringSchema(), properties))

kafkaDstream.print("source for kafka")

env.execute("source test job")

}
}


开启kafka生产者

```shell
// kafka数据生产者
./bin/kafka-console-producer.sh --broker-list 10.30.59.160:9092 --topic sensor
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈沐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值