ITPub博客

首页 > 数据库 > 数据库开发技术 > 大数据实战项目第2步——实时消费数据源

大数据实战项目第2步——实时消费数据源

原创 数据库开发技术 作者:安瑞哥是码农 时间:2022-08-09 17:36:18 0 删除 编辑

上一篇文章中已经模拟了数据源如何生成,以及如何接入到你大数据平台中的kafka集群,老实说,步骤非常简单,只需要一个简单脚本和一个Filebeat的配置文件(寥寥几行),就搞定了。

然后这个实战项目的第1步的整个过程在周日的直播间,我也详细做了描述和解释,不知道各位小伙伴是否已经完全掌握。

但是直播间里有人看到我的模拟生成实时数据的脚本,说每1秒钟生成1条数据,这个量是不是太小了?好吧,确实,这样生成数据确实效率有点低,那咱就改进一下,每1秒钟生成100条可不可以?

具体改进后的脚本如下:
#!/usr/bin/env bash
#########################################
##
#Desc: 模拟真实的数据生产行为,将原始数据文件的内容逐行读到准备区文件中
#
#Author: Anryg
#
##########################################
set -o nounset #必须使用初始化之后的变量
set -o errexit #命令执行过程中如果有报错,直接退出整个脚本
###################################################
#
# _LOG
#
####################################################
# $1 - message
# $2 - log file
_LOG() {
        message="[$(date +'%Y-%m-%d %H:%M:%S') ${0##*/}] $1"
        echo ${message}
        if [[ $# == 2 ]]; then
                echo ${message} >>$2  ##指定日志文件
        fi
}
#################################################
current_dir=$(cd `dirname $0`; pwd)  ##获取程序所在的绝对路径
batch_num=100    #推送100条数据到kafka之后,sleep一次
current_num=0    ##当前已经推送kafka数量的计数器

while read line
    do
        echo "${line}" >> staging.csv ##将读取的数据写入到准备区文件中
        let current_num+=1  ##推送次数自增
        if [[ ${current_num} -eq ${batch_num} ]]; then
            sleep 1  ##每间隔1秒写一次
            current_num=0 ##计数器归位
        fi
    done < $1  ##指定数据源文件

_LOG "数据文件写入完毕..." ${current_dir}/staging.log

exit 0



怎么样?是不是瞬间感觉高大上了一点点,作为一个大数据开发,我是希望你能掌握一些shell脚本的技能,这样以后对你的程序员生涯是非常有帮助的。

好了,接下来步入正题,数据源既然已经模拟流的方式写入到了kafka集群,那么接下来,就是该spark粉墨登场了。


|为什么用structured streaming
用spark的哪个功能来消费数据呢?前面在架构中提到,为了贴合场景需求,咱用structured streaming(我知道你脑海中会有很多小问号,为什么不用flink?放心,后续咱再把它玩起来,一个个来,行不行,当你把这个学会,flink对你来说那就是小意思)。

这是个spark推出的用来代替spark streaming的一款实时流式计算引擎,相比spark streaming每次数据处理时必须要设置流的批次时间,structured streaming优化了这一步骤,对流数据的获取效率可以做到as fast as possible。

啥意思呢?就是你CPU能调度的多快,我poll数据的效率理论上就可以达到多高,上次直播间也做了演示,确实可以做到实时的数据获取。

当然,如果你非得纠结它的底层实现机制,说它还是有延迟的,官方说它的延迟时间为1毫秒,Emm...,你在乎这个1毫秒吗?反正我不在乎。


好了,虽然上次在直播间讲了这个structured streaming的实例代码,但是很多同学不一定完全理解了,这里我把它再次贴出来,供你参考。
package com.anryg.bigdata.streaming

import java.util.concurrent.TimeUnit

import com.alibaba.fastjson.JSON
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.streaming.{OutputMode, Trigger}

/**
  * @DESC:  从kafka读取上网行为数据
  * @Auther: Anryg
  * @Date: 2022/08/08 09:56
  */

object StructuredStreamingFromKafka {

    def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setAppName("StructuredStreamingFromKafka").setMaster("local[*]")
        val spark = SparkSession.builder().config(conf).getOrCreate()

        val rawDF = spark.readStream
            .format("kafka") //确定数据源的来源格式
            .option("kafka.bootstrap.servers", "192.168.211.107:6667") //指定kafka集群的地址,理论上写一个broker就可以了
            .option("subscribe","test")  //指定topic
            //.option("group.id","test9999") /**不再用该方式来绑定offset,而是每个程序有个唯一的id,该id跟checkpointLocation绑定,虽然group.id属性在运行中依然保留,但是不再跟offset绑定*/
            .option("failOnDataLoss",false)  //如果读取数据源时,发现数据突然缺失,比如被删,则是否马上抛出异常
            .option("fetchOffset.numRetries",3)  //获取消息的偏移量时,最多进行的重试次数
            //.option("maxOffsetsPerTrigger",100)/**用于限流,限定每次读取数据的最大条数,不指定则是as fast as possible*/
            .option("startingOffsets","latest")  //第一次消费时,读取kafka数据的位置
            .load()

        import spark.implicits._
        val ds = rawDF.selectExpr("CAST(value AS STRING)")  //将kafka中的数据的value转为为string,原始为binary类型
                        .map(row => {
                            val line = row.getAs[String]("value") //获取row对象中的field,其实也只有一个field
                            val rawJson = JSON.parseObject(line)      //原始string是一个json,对其进行解析
                            val message = rawJson.getString("message")  //获取业务数据部分
                            val msgArray = message.split(",")  //指定分隔符进行字段切分
                            msgArray
                        }).filter(_.length == 9)  //只留字段数为9的数据
                        .map(array => (array(0),array(1),array(2),array(3),array(4),array(5),array(6),array(7),array(8))) //将其转化成为元组,为了方便下一步赋予schema
                        .toDF("client_ip","domain","time","target_ip","rcode","query_type","authority_record","add_msg","dns_ip") //给裸数据添加字段名

        ds.printSchema() //打印schema,确认没有问题
        
        val query = ds.writeStream
            .outputMode(OutputMode.Append())  //指定数据的写入方式
            .format("console")  //指定外部输出介质
            //.trigger(Trigger.ProcessingTime(60,TimeUnit.SECONDS))/**每60秒执行一次,不指定就是as fast as possible*/
            .option("checkpointLocation","hdfs://192.168.211.106:8020/tmp/offset/test/kafka_datasource-05") /**用来保存offset,用该目录来绑定对应的offset,如果该目录发生改变则程序运行的id会发生变化,类比group.id的变化*/
            .start()

        query.awaitTermination()
    }

}


为了方便,我就直接一个main方法一镜到底了(正式开发环境你可不能这样哈),所有代码都进行了注释,你应该都能理解哈,有任何疑问可以群里讨论。

另外,把相应的这个工程的pom文件也贴出来,供你参考:
    <dependencies>
        <!--主要提供SparkConf和SparkContext对象-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.12</artifactId>
            <version>3.2.0</version>
        </dependency>
      <!--主要提供SparkSession对象-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.12</artifactId>
            <version>3.2.0</version>
        </dependency>
      <!--主要提供Structured streaming读取kafka-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql-kafka-0-10_2.12</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!--通过json转换-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
        <!--hdfs客户端依赖-->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client-api</artifactId>
            <version>3.3.1</version>
        </dependency>
    </dependencies>

我希望你能根据我给你的这个模板代码和pom文件配置,可以把structured streaming用起来。


|最后
好了,这个项目的第2步就这样完成了,非常简单,有木有?

但是我想告诉你的是,前面2步都是基础,你一定要亲手去实践,从第三步开始,难度就会一点点加大,我希望你能够跟上。


PS:这个周末会继续直播,带你开始第3步的操作,并在直播间教大家如何正确、高效的阅读官方文档,以及spark源码...



我这有一个高质量的大数据学习讨论群,不怎么扯淡、偶尔活跃气氛、大部分时间都在讨论技术,你在群里的几乎任何大数据相关的问题,都可以得到解答,要不要进来试试呢?拉你进群啊...


原文作者:安瑞哥是码农;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2022-02-16

  • 博文量
    228
  • 访问量
    115433