spark day10

目录

SparkStreaming/StructuredStreaming

1.SparkStreaming

1.数据源

2.SparkStreaming运行:

3.流式处理:

4.作业运行

1.idea加依赖

2.xshell操作

3.idea使用

2.算子

1.转换算子

1.transform

         案例:弹幕过滤的功能/黑名单功能

2.updataStateByKey

        案例:累计问题

        checkpoint的作用

2.输出算子

1.print

2.foreachRDD 【写出数据】

        案例:将wc案例结果写到mysql中


SparkStreaming/StructuredStreaming

  • sprark提供实时计算的模块:SparkStreaming、StructuredStreaming
  • 实时处理(来一条数据处理一条数据)
    • storm
    • flink
    • event
  • 技术选型
    • 生产上使用
      • SparkStreaming、StructuredStreaming :10%
      • flink :90%        【开发角度来说简单】
      • storm :2%
    • 业务
      • 1.实时指标:差不多
      • 2.实时数仓
        • 1.代码 【不好维护】
        • 2.sql文件:flinksql维护实时数仓
  • 1.流处理/实时计算
    • 并非真正的实时处理,是近实时处理,来一批数据处理一批数据 远远不断的来
  • 2.批处理/离线计算
    • 一次性处理某一个批次的数据 数据是有始有终的

1.SparkStreaming

  • 1.数据源

    • kafka :流式引擎 + kafka 
    • flume :可以使用,没有数据缓冲作用,一般不用  
    • hdfs :很少使用
    • tpc sockets :测试 + 运营商数据(很早前使用的)
  • 2.SparkStreaming运行:

    • 1.receives live input data streams 接收数据
    • 2.divides the data into batches 把接收数据  拆分成batches
    • sparkstreaming=》 kafka
      • 1.5s钟处理一次数据
      • 2.会5s接收的数据切分成batch
      • 3.把batch 交给sparkengine 处理
      • 4.处理完结果·也是·batch
  • 3.流式处理:

    • 对Dstream进行转换操作
    • 实际上就是对Dstream里面的rdd进行操作
    • 对rdd进行操作就是对rdd里面分区的元素进行操作
    • 总结:程序入口
      • sparkstreaming :StreamingContext
      • sparkcore: sparkcontext 
      • sparksql: sparksession 
  • 4.作业运行

    • 官网:spark.apache.org/docs/latest/streaming-programming-guide.html#overview
    • 1.idea加依赖

      <!--sparkstreaming 依赖-->
      <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming_2.12</artifactId>
        <version>3.2.1</version>
      </dependency>
    • 2.xshell操作

      • 1.进入spark
      • 2.导包 
        import org.apache.spark._
        import org.apache.spark.streaming._
        import org.apache.spark.streaming.StreamingContext._ 
      • 3.构建StreamingContext
        val ssc = new StreamingContext(sc, Seconds(5))

         // Seconds(5) :每隔5s运行一次

      • 4.加载数据源
        val lines = ssc.socketTextStream("localhost", 9999)
      • 5.添加转换操作
        val words = lines.flatMap(_.split(" "))
        val pairs = words.map(word => (word, 1))
        val wordCounts = pairs.reduceByKey(_ + _)
        wordCounts.print()
      • 6.准备数据源
        • [hadoop@bigdata13 ~]$ nc -lk 9999
      • 7.作业启动
        ssc.start()       
        ssc.awaitTermination()
          
          如果没有数据就空跑
      • 8.查看job:bigdata13:4040

                 6条有效数据

        • 有效数据
    • 3.idea使用

      object SSSS {
        def main(args: Array[String]): Unit = {
          val conf = new SparkConf().setMaster("local[2]").setAppName("SSSS")
          val ssc = new StreamingContext(conf, Seconds(10))
          
          val lines = ssc.socketTextStream("bigdata13",9998)
          val words = lines.flatMap(_.split(" "))
          val pairs = words.map(word => (word, 1))
          val wordCounts = pairs.reduceByKey(_ + _)
          wordCounts.print()
      
          ssc.start()
          ssc.awaitTermination()
        }
      }

        [hadoop@bigdata13 ~]$ nc -lk 9998
       

      • 多个端口连接
          def main(args: Array[String]): Unit = {
            val conf = new SparkConf().setMaster("local[4]").setAppName("SSSS")
            val ssc = new StreamingContext(conf, Seconds(10))
        
            val lines = ssc.socketTextStream("bigdata13",9998)
            val lines1 = ssc.socketTextStream("bigdata13",9997)
            val lines2 = ssc.socketTextStream("bigdata13",9996)
            val words = lines.flatMap(_.split(" "))
            val pairs = words.map(word => (word, 1))
            val wordCounts = pairs.reduceByKey(_ + _)
            wordCounts.print()
            lines1.print()
            lines2.print()
        
            ssc.start()             // Start the computation
            ssc.awaitTermination()  // Wait for the computation to terminate
          }

2.算子

1.转换算子

  • 1.transform

    • transform:DStream 和 rdd之间数据进行交换的算子
    • 处理需求
      • 一个数据来自mysql数据/hdfs上文本数据 【最小】围标
      • 一个数据来自于kafka sss读取形成DStream数据【最大】主业务
    • 案例:弹幕过滤的功能/黑名单功能

      • 离线
        object SparkSQLCoreBlockListApp {
        
          def main(args: Array[String]): Unit = {
            val spark: SparkSession = SparkSession.builder().appName("SparkSQL01").master("local[2]").getOrCreate()
            val sc = spark.sparkContext
        
            val log = sc.parallelize(List(
              "good",
              "演技好好",
              "爱了爱了",
              "哭死",
              "真帅",
              "丑死了",
              "退出娱乐圈",
              "黑子"
            ))
        
            val black = sc.parallelize(List(
              "丑死了",
              "退出娱乐圈",
              "黑子"
            ))
        
            val log_kv = log.map(line => (line, 1))
            val black_kv = black.map(line => (line, true))
            log_kv.leftOuterJoin(black_kv)
              .filter(_._2._2.getOrElse(false) != true)
                .map(_._1).foreach(println(_))
        
            spark.stop()
          }
        }

          

      • 实时
        object SparkStreamingSQLCoreBlockListApp {
        
          def main(args: Array[String]): Unit = {
            val conf = new SparkConf().setMaster("local[2]").setAppName("SSSS01")
            val ssc = new StreamingContext(conf, Seconds(10))
        
            val sc = ssc.sparkContext
        
            val logs: ReceiverInputDStream[String] = ssc.socketTextStream("bigdata13", 9527)
        
            val black = sc.parallelize(List(
              "丑死了",
              "退出娱乐圈",
              "黑子"
            ))
        
            //弹幕显示
            val log_kv = logs.map(word => (word, 1))
            val black_kv = black.map(line => (line, true))
        
            val result = log_kv.transform(rdd => {
              rdd.leftOuterJoin(black_kv)
                .filter(_._2._2.getOrElse(false) != true)
                .map(_._1)
            })
            result.print()
        
            ssc.start()
            ssc.awaitTermination()
          }
        }

         

  • 2.updataStateByKey

    • 用于解决有状态问题
    • 案例:累计问题

      • 统计 从现在时间点开始  b出现的累计次数?
      • 代码
        object SSS01 {
          def main(args: Array[String]): Unit = {
            val conf = new SparkConf().setMaster("local[2]").setAppName("SSSS01")
            val ssc = new StreamingContext(conf, Seconds(10))
        
            //指定checkpoint
          ssc.checkpoint("file:///D:\\iccn\\software\\xxl\\untitled3\\untitled5\\Data\\checkpoint")
            val lines = ssc.socketTextStream("bigdata13", 9999)
            val words = lines.flatMap(_.split(" "))
            val pairs = words.map(word => (word, 1))
            val wordCounts = pairs.updateStateByKey(updateFunction)
            wordCounts.print()
        
            ssc.start()
            ssc.awaitTermination()
          }
        
          def updateFunction(newValues: Seq[Int], preValues: Option[Int]): Option[Int] = {
            // newValues : (a,1)(a,1)(a,1)   => a,<1,1,1>
            // preValues :  none
            val curr_sum = newValues.sum
            val pre_sum = preValues.getOrElse(0)
            Some(curr_sum+pre_sum)
          }
        
        }
    • 总结
      • 1.指定checkpoint:维护当前批次和以前的累计批次的数据state
      • 2.checkpoint目录生产上得指定到hdfs上进行存储
        • 存在问题:checkpoint每个批次都会产生文件(hsfs扛不住)
    • checkpoint的作用

      • (针对sparkstreaming来说)【生产上不能用】
      • 1.作用
        • 1.维护状态
        • 2.为了容错
        • 3.恢复实时计算作业【挂掉之后可以恢复起来】
      • 2.两大类数据【checkpoint的存储】
        • 1.Metadata 元数据
          • Configuration 【作业中的配置文件】
          • DStream operations 【作业code中的操作算子】
          • Incomplete batches 【未完成的批次】
        • 2.Data
          • 每个批次中真正传过来的数据和状态
      • 3.使用checkpoint的时间点
        • 1.使用带有状态的转换算子
        • 2.恢复作业时使用
      • 4.checkpoint的使用
        object SSS02 {
          def main(args: Array[String]): Unit = {
            val checkpointDirectory="file:///D:\\iccn\\software\\xxl\\untitled3\\untitled5\\Data\\checkpoint01"
            val ssc = StreamingContext.getActiveOrCreate(checkpointDirectory,functionToCreateContext)
            ssc.start()
            ssc.awaitTermination()
          }
        
          def functionToCreateContext(): StreamingContext = {
            val conf = new SparkConf().setMaster("local[2]").setAppName("SSSS02")
            val ssc = new StreamingContext(conf, Seconds(10))
            ssc.checkpoint("file:///D:\\iccn\\software\\xxl\\untitled3\\untitled5\\Data\\checkpoint01")
        
            val lines = ssc.socketTextStream("bigdata13", 9999)
            val words = lines.flatMap(_.split(" "))
            val pairs = words.map(word => (word, 1)).map(x=>(x._1,2))
            val wordCounts = pairs.updateStateByKey(updateFunction)
            wordCounts.print()
            ssc
          }
        
          def updateFunction(newValues: Seq[Int], preValues: Option[Int]): Option[Int] = {
            // newValues : (a,1)(a,1)(a,1)   => a,<1,1,1>
            // preValues :  none
            val curr_sum = newValues.sum
            val pre_sum = preValues.getOrElse(0)
            Some(curr_sum+pre_sum)
          }
        }

         重新启动后数据也还存在

      • 6.checkpoint缺点:
        • 1.小文件多
        • 2.修改代码程序就用不了【修改业务逻辑代码】
        • checkpoint 用不了生产上 =>累计批次指标统计问题 updateStateByKey这个算子 也用不了
      • 7.实现累计批次统计需求
        • 一: 100%来处理 
          • 1.把每个批次数据 写到外部存储 
          • 2.然后利用外部存储系统再统计即可
        • 二:90%都没有解决 
                 checkpoint 【解决 checkpoint 导致修改代码 报错问题+小文件问题解决】

2.输出算子

  • 1.print

  • 2.foreachRDD 【写出数据】

    • 案例:将wc案例结果写到mysql中

      • 1.在mysql中建表
        create table wc(
        	word varchar(10),
        	cnt int(10)
        );

          在bigdata数据库中

      • 2.idea中建立与mysql连接
        import java.sql.{Connection, DriverManager}
        
        object MySQLUtil {
          /**
            * 获取mysql 连接
            * @return
            */
          def getConnection()={
            Class.forName("com.mysql.jdbc.Driver")
            DriverManager.getConnection("jdbc:mysql://bigdata13:3306/bigdata","root","123456")
          }
          /**
            * 关闭mysql 连接
            * @param connection
            */
          def closeConnection(connection: Connection)={
            if (connection !=null){
              connection.close()
            }
          }
        }
      • 3.初步写出代码
        object SSSS3 {
          def main(args: Array[String]): Unit = {
            val conf = new SparkConf().setMaster("local[2]").setAppName("SSSS3")
            val ssc = new StreamingContext(conf, Seconds(10))
            val lines = ssc.socketTextStream("bigdata13",9998)
        
            val words = lines.flatMap(_.split(" "))
            val pairs = words.map(word => (word, 1))
            val wordCounts = pairs.reduceByKey(_+_)
            wordCounts.print()
        
            //output:data => mysql
            wordCounts.foreachRDD({ rdd =>
              rdd.foreach(pair => {
                val conn: Connection = MySQLUtil.getConnection()
        
                //val sql = s"inster into wc(word,cnt) values('${pair._1}','${pair._2}')"
                val sql=s"insert into wc(word,cnt) values('${pair._1}','${pair._2}')"
                conn.createStatement().execute(sql)        //数据写出
                conn.close()           //关闭连接
              })
            })
        
            ssc.start()
            ssc.awaitTermination()
          }
        }

         

      • 4.优化mysql连接次数
        • 1.rdd.foreachPartition
          • mysql 连接次数 会减少  rdd有多少个分区 就有多少个连接【生产上用它足够】
            wordCounts.foreachRDD({ rdd =>
              //减少mysql连接 高效
              //rdd.coalesce(10).foreachPartition(规定分区数)
              rdd.foreachPartition(partion => {
                val conn: Connection = MySQLUtil.getConnection()
                partion.foreach(pair =>{
                  val sql=s"insert into wc(word,cnt) values('${pair._1}','${pair._2}')"
                  conn.createStatement().execute(sql)        //数据写出
                })
                conn.close()           //关闭链接
              })
            })
        • 2.使用连接池
      • 5.sparksql的方式写出【推荐】
        //output:data => mysql
        wordCounts.foreachRDD({ rdd =>
          // sparksql 的方式写出  推荐
          val spark = SparkSession.builder.config(rdd.sparkContext.getConf).getOrCreate()
          import spark.implicits._
        
          val df = rdd.toDF("word","cnt")
          df.printSchema()
          df.show()
        
          val url="jdbc:mysql://bigdata13:3306/bigdata"
          val table="wc"
          val properties = new Properties()
          properties.setProperty("user", "root")
          properties.setProperty("password", "123456")
          df.write.mode(SaveMode.Append).jdbc(url,table,properties)
        })

          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值