[Spark]-结构化流之输出篇(待重修)

5.结构化流的输出

  一旦定义好了streaming DataFrame/Dataset的最终结果,剩下的就是一些计算输出了.为此,必须使用 DataStreamWriter通过 Dataset.writeStream() 返回.此时必须以下一个或多个

   输出落地 的详细信息:  Data format, location 等等

   输出模式(Output mode)

   查询名称(Query name)  可选,指定用于标识的查询的唯一名称

   触发器间隔(Trigger interval):可选地,指定触发间隔。如果没有指定,系统将检查尽快获得新数据前处理完成。如果一个触发时间错过了,因为前面的处理还没有完成,则系统将触发立即处理

   检查点位置(Checkpoint location) 对于可以保证 end-to-end fault-tolerance (端对端容错)能力的某些 output sinks ,请指定系统将写入所有 checkpoint (检查点)信息的位置。

                   这应该是与 HDFS 兼容的容错文件系统中的目录.

  5.1 输出模式

    追加(append)(默认) 这是默认的模式.在上次触发后,只有新行添加到结果表(result-table)才会触发。

             这是只支持那些查询,行添加到结果表永远不会改变,因为这种模式保证每一行将只输出一次。例如,只有选择查询,地图,flatMap,过滤,加入等将支持附加模式

    完全(complete) 每次触发时都会将整个结果表(result-table)输出.例如聚合结果等

    更新(update) 只有结果表在上次被触发后被更新才会触发

    不同的查询支持不同的输出模式,具体见下:

查询类型 支持模式描述
带聚合的查询聚合带事件时间的水印Append, Update, Complete

Append 使用水印来删除旧的聚集状态 窗口将在水印最终阈值的时候聚合.所以结果将在水印过期,最终结果确定的情况下添加进结果表

Update 使用水印来删除旧的聚集状态

Complete 不会使用水印来删除旧的聚集状态

不带水印的聚合Complete, Update由于没有使用水印,旧的聚集状态不会被删除.不支持append,因为对整数据的聚合结果会不断更新,不符合append的语义
mapGroupsWithStateUpdate 
flatMapGroupsWithState追加操作模式AppendflatMapGroupsWithState 之后允许 Aggregations (聚合)
 更新操作模式UpdateflatMapGroupsWithState 之后不允许 Aggregations (聚合)。
带join的查询Appendjoin不支持Update,Complete模式
其它查询Append, Update不支持Complete.因为非聚合数据的结果表,全部保存进结果表时不允许的

  5.2 输出落地

      5.2.1 落地文件

        落地文件,是适合长期保存.这里的文件是指HDFS等任何Hadoop支持的文件系统.

        落地文件,支持自动分区.并且支持有且仅有一次的容错        

          val query =
            streamingSelectDF
              .writeStream
              .format("parquet")
              .option("path", "文件保存路径")
              .partitionBy("zip", "day") //分区字段
              .trigger(ProcessingTime("25 seconds"))
              .start()

 

    5.2.2 落地Kafka

      kafka专章描述,具体见后

    5.2.3 落地控制台(debug使用)

       输出被直接打印到控台或者stdout日志

    5.2.4 落地Memory接收器(debug使用)

    5.2.5 foreach

       foreach落地,是用户自定义输出的一种方式.foreach需要用户实现 ForeachWriter 类.实际处理取决于用户如何实现.(foreach只能使用在Scala/Java中)

      它将在触发器(trigger)之后生成结果行时调用一个用户实现.

      注意: foreach的实现载体是多个executor中的某一个

      5.2.5.1 实现

        open: writer 初始化时执行(例如打开连接,开启事务等).它具有两个入参: version=>每个触发器单调递增的ID  partitionId =>分区ID.

           open将返回一个布尔值.当为false时,后续将不会产生任何调用.用户可以根据自己的逻辑,用这个返回值指出本次输出后续是否还有必要执行

        proccess:根据open的返回值决定是否需要执行.

        close:无论open返回什么值,close必然会执行.这里适合用户做一些资源回收操作       

            class WriterToMysql extends ForeachWriter[Row] {
            private var connection: Connection = null;
            
            override def open(partitionId: Long, version: Long): Boolean = {
                Class.forName("com.mysql.jdbc.Driver")
                connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&characterEncoding=UTF-8&useSSL=false", "root", "12abAB")
                return true
            }
            
            override def process(value: Row): Unit = {
                val stmt = connection.createStatement()
                try {
                stmt.execute(
                    s"""
                    |replace into `test`.`structured_streaming_window_watermark_app_test`
                    |(`window`,`word`,`count`)
                    |VALUES
                    |('${value.get(0).toString}','${value.get(1)}',${value.getLong(2)});
                    """.stripMargin)
                }
                finally {
                stmt.close()
                }
            }
            
            override def close(errorOrNull: Throwable): Unit = {
                try {
                if (connection != null) {
                    connection.close()
                }
                }
                finally {}
            }
            }
            //使用
            val query = windowWordCounts.writeStream.outputMode("update")
                .foreach(new WriterToMysql())
                .option("truncate", "false")
                .start();

    5.2.6 输出落地可以承载的输出模式

 

接收器支持的输出模式可选项容错机制备注
文件Appendpath支持容错(有且仅有一次)支持分区
kafkaAppend, Update, Complete详见kafka专章支持容错(最少一次) 
foreachAppend, Update, Complete 取决于foreach的实现 
控制台Append, Update, CompletenumRows:每次打印的行数(默认20),truncate:输出太长时截断(默认true)不支持容错 
内存Append, Complete 不支持容错,但重启时重建整张结果表 

  5.3 触发器

    Spark2.3 已经具有以下四种触发器

    默认触发器

      如果不设置任何触发器,将默认使用此触发器.触发规则是:上一个微批处理结束,启动下一个微批处理

    时间间隔触发(Fixed interval micro-batches)

      设置了触发间隔的触发器. 

        如果上一个微批处理在触发间隔前结束,会等待间隔时间结束后再触发.

        如果在触发间隔前还没有处理结束.后续暂时不会触发,会等待上个微批处理结束后再立即启动

      .trigger(Trigger.ProcessingTime("2 seconds"))

    只触发一次(One-time micro-batch)

      触发一次处理全部数据,然后自然停止.适合用在关闭集群时数据的最后处理和清理

      .trigger(Trigger.Once())

 

    连续触发器(Continuous with fixed checkpoint interval)

      连续处理是Spark2.3才提供的触发器.它是以一个低延迟,连续处理模式(没有间隔概念)的模式进行处理.

      .trigger(Trigger.Continuous("1 second"))

      不过很可惜,Spark2.3中连续处理依然只是一个实验版本,在此只做一个简单介绍.

        连续处理会启动多个长时间的运行的任务.这些任务不断地从源中读取数据、处理数据并不断地向接收器写入数据。查询所需的任务数量取决于查询可以并行地从源中读取多少个分区

          因此,在开始一个连续的处理查询之前,必须确保集群中有足够多的内核并行执行所有任务.(10分区的Kafka,必须至少有10个内核才能进行查询)

        现阶段连续处理只能接收Map系操作,还不支持聚合系操作.

        支持的数据源只Kafka,Rate两种

        不支持失败任务的重试.任何失败都会导致查询终止,必须手动的从检查点恢复.

      

转载于:https://www.cnblogs.com/NightPxy/p/9278881.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值