Kafka+Spark Streaming本地词频统计

前几天简单了解了Hadoop(HDFS,MR,YRAN)之后,进一步了解一下现在使用比较多的Spark生态--Sprak Streaming。

简介

Spark Streaming is an extension of the core Spark API that enables scalable, high-throughput, fault-tolerant stream processing of live data streams.

Spark Streaming 是基于核心Spark API扩展的一个可扩展,高吞吐量,容错处理的实时流处理框架。

SparkStreamingProccess.jpg

其核心思想是 将接受的数据流进行数据分批处理,然后经过Spark 引擎处理以数据分片方式输出到结果流。

核心概念

StreamingContext

要初始化 Spark Streaming 程序,必须创建一个 StreamingContext 对象,它是所有 Spark Streaming 功能的主要入口点。

Discretized Streams (DStreams)

Discretized Stream 或 DStream 是 Spark Streaming 提供的基本抽象。 它表示一个连续的数据流,可以是从源接收到的输入数据流,也可以是通过转换输入流生成的处理后的数据流。 在内部,DStream 由一系列连续的 RDD 表示,这是 Spark 对不可变的分布式数据集的抽象。 DStream 中的每个 RDD 都包含来自某个区间的数据,如下图所示。

RDD.jpg

对 DStream 应用的任何操作都会转换为对底层 RDD 的操作。对行 DStream 中的每个 RDD 应用 flatMap 操作以生成单词 DStream 的 RDD。 这如下图所示。

RDDOPERATION.jpg

这块就比较像Spring5的 WebFlux里中的 FlatMap操作。

Input DStreams and Receivers

Input DStreams是DStreams 从流源接收的输入数据流的代表。

每个输入 DStream(除了文件流,本节稍后讨论)都与一个接相关联的Receiver。

词频统计代码

搭建Kafka

可以参考我另外一篇云服务器安装Kafka集群

本地生产者测试代码

为了测试方便,我使用SpringBoot 去搭建一个Kafka生产者的demo

工程目录如下

producerDemo.jpg

pom文件



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.5.5
         
    
    com.example
    demok
    0.0.1-SNAPSHOT
    demok
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.kafka
            spring-kafka
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.kafka
            spring-kafka-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    



YML 配置文件

spring:
  kafka:
    bootstrap-servers: xxx.xxx.xxx.xxx:9092  #你的KAFKA地址
    producer:
      # 发生错误后,消息重发的次数。
      retries: 0
      #当有多个消息需要被发送到同一个分区时,生产者会把它们放在同一个批次里。该参数指定了一个批次可以使用的内存大小,按照字节数计算。
      batch-size: 16384
      # 设置生产者内存缓冲区的大小。
      buffer-memory: 33554432
      # 键的序列化方式
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 值的序列化方式
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      # acks=0 : 生产者在成功写入消息之前不会等待任何来自服务器的响应。
      # acks=1 : 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。
      # acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。
      acks: 1
    consumer:
      # 自动提交的时间间隔 在spring boot 2.X 版本中这里采用的是值的类型为Duration 需要符合特定的格式,如1S,1M,2H,5D
      auto-commit-interval: 1S
      # 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
      # latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)
      # earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录
      auto-offset-reset: earliest
      # 是否自动提交偏移量,默认值是true,为了避免出现重复数据和数据丢失,可以把它设置为false,然后手动提交偏移量
      enable-auto-commit: false
      # 键的反序列化方式
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      # 值的反序列化方式
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    listener:
      # 在侦听器容器中运行的线程数。
      concurrency: 5
      #listner负责ack,每调用一次,就立即commit
      ack-mode: manual_immediate
      missing-topics-fatal: false


KafkaProducer

package com.example.demok.producer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

/**
 * description: KafkaProducer 
* date: 2021/10/22 9:32
* author: Neal
* version: 1.0
*/ @Component public class KafkaProducer { @Autowired private KafkaTemplate kafkaTemplate; //自定义topic public static final String TOPIC_TEST = "test"; public void send(String str) { //发送消息 ListenableFuture> future = kafkaTemplate.send(TOPIC_TEST, str); future.addCallback(new ListenableFutureCallback>() { @Override public void onFailure(Throwable throwable) { System.out.println(TOPIC_TEST + " - 生产者 发送消息失败:" + throwable.getMessage()); } @Override public void onSuccess(SendResult stringObjectSendResult) { System.out.println(TOPIC_TEST + " - 生产者 发送消息成功:" + stringObjectSendResult.toString()); } }); } }

测试类 DemokApplicationTests

package com.example.demok;

import com.example.demok.producer.KafkaProducer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class DemokApplicationTests {

    @Autowired
    private KafkaProducer kafkaProducer;

    @Test
    void contextLoads() {
        //声明三条消息
        String[] arrStr = {"Deer,Bear,River","Car,Car,River","Deer,Car,Bear"};
        //循环向Kafka发送消息
        for (int i = 0; i < 3; i++) {
            kafkaProducer.send(arrStr[i]);
        }
    }
}

生产者代码样例很简单,就是像上一篇文章一样,将3行数据写入数组中,循环发送到Kafka的test Topic 中。

Spark Streaming 词频统计代码

词频统计代码工程目录很简单 就一个类 我就不贴图了直接贴代码,我使用的是Scala 2.11.8 版本

pom文件




  4.0.0

  org.example
  kafkaSparkStream
  1.0-SNAPSHOT

  kafkaSparkStream
  
  http://www.example.com

  
    UTF-8
    1.8
    1.8
    3.2.0
  

  
    
      org.apache.spark
      spark-core_2.12
      ${spark.version}
    
    
      org.apache.spark
      spark-streaming_2.12
      ${spark.version}
    
    
      org.apache.spark
      spark-streaming-kafka-0-10_2.12
      ${spark.version}
    
    
      junit
      junit
      4.11
      test
    
  

  
    
      
        
        
          maven-clean-plugin
          3.1.0
        
        
        
          maven-resources-plugin
          3.0.2
        
        
          maven-compiler-plugin
          3.8.0
        
        
          maven-surefire-plugin
          2.22.1
        
        
          maven-jar-plugin
          3.0.2
        
        
          maven-install-plugin
          2.5.2
        
        
          maven-deploy-plugin
          2.8.2
        
        
        
          maven-site-plugin
          3.7.1
        
        
          maven-project-info-reports-plugin
          3.0.0
        
      
    
  


统计代码

package org.example.ss
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
/**
 * description: App 
* date: 2021/10/23 14:47
* author: Neal
* version: 1.0
*/ object App { def main(args: Array[String]): Unit = { //Spark配置 val sparkConfig = new SparkConf() .setAppName(this.getClass.getSimpleName) .setMaster("local[2]") //初始化 Stream上下文 10秒计算一次 val ssc = new StreamingContext(sparkConfig,Seconds(10)) //Kafka 参数配置 val kafkaParams = Map[String, Object]( "bootstrap.servers" -> "xxx.xxx.xxxx.xxx:9092", //kafka地址,集群可以以逗号分隔 "key.deserializer" -> classOf[StringDeserializer], //序列化类 "value.deserializer" -> classOf[StringDeserializer], //序列化类 "group.id" -> "use_a_separate_group_id_for_each_stream", "auto.offset.reset" -> "latest", //消费最新的消息 "enable.auto.commit" -> (false: java.lang.Boolean) //不自动提交 ) //设置消费主题 val topics = Array("test") //初始化 连接Kafka 获取到InputStream val stream = KafkaUtils.createDirectStream[String, String]( ssc, PreferConsistent, Subscribe[String, String](topics, kafkaParams) ) stream //取出消息,逗号分隔后,将每一个值放入Map中 key 为值,value 为1 .flatMap(_.value().split(",").map((_,1))) //使用key 值进行计算 .reduceByKey(_ + _).print() //启动 SparkStreaming ssc.start() ssc.awaitTermination() } }

这里由于Spark 是Scala语言写的,因此如果想理解里面函数以及对应的参数符号含义,建议去简单看一下Scala 的相关教程入门一下就可以看懂了。

测试以及结果

启动Spark Streaming 词频统计程序

启动后可以看到如下输出

ss_re1.jpg

该输出会10秒一刷新,因为代码中配置的是每10S计算一次

启动生产者测试代码,向Kafka发送数据

producer_re.jpg

可以看到生产者发送了3条消息到Kafka

查看计算结果

我们回到频次统计程序的输出页面,可以看到其计算后的输出结果。

ss_re2.jpg

小结

由于是简单的Spark Streaming的应用,只是为了熟悉Spark 流处理计算框架,为以后的技术方案做技术积累。

你可能感兴趣的:(Kafka+Spark Streaming本地词频统计)