kafka -> sparkStreaming -> kafka

序列化还可以这样写(就是说的代码中直接写在KafkaProducer后面)
(序列化、lazy、广播变量 )这是一套放在一起写比较好

场景是让变量这样在foreachRDD外面写producer 变量,不在里面创建多次 写在外面只一次就可以
但是要序列化 还要加lazy,最好再广播一下

1… with Serializable 直接在语句 变量后面 跟序列化声明

2.然后有时候不使用java的Map 要导入scala的集合使用

import scala.collection.JavaConversions.__

好处:

广播变量节省数据传输
lazy延迟创建

package Kafka010


import Kafka010.Utils.MyKafkaUtils
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.clients.producer.{KafkaProducer, ProducerConfig, ProducerRecord, RecordMetadata}
import org.apache.kafka.common.serialization.StringSerializer
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.{Seconds, StreamingContext}

/**
 * Created by Shi shuai RollerQing on 2019/12/24 19:47
 * kafka -> sparkStreaming -> kafka
 */

object Kafka010Demo07 {


  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName(s"${this.getClass.getCanonicalName}")
    val ssc = new StreamingContext(conf, Seconds(5))

    //读数据
    val groupID = "SparkKafka010"
    val topics = List("topicB")
    val kafkaParams: Map[String, String] = MyKafkaUtils.getKafkaConsumerParams(groupID, "false")
    val ds: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream[String, String](
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](topics, kafkaParams)
    )

    //写数据 kafka Producer配置
    val kafkaProducerParams: Map[String, String] = Map(
      ProducerConfig.BOOTSTRAP_SERVERS_CONFIG -> "hadoop01:9092,hadoop02:9092,hadoop03:9092",
      ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG -> classOf[StringSerializer].getName,
      ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG -> classOf[StringSerializer].getName
    )

    //懒加载、序列化、 广播producer
    import scala.collection.JavaConversions._
    lazy val producer = new KafkaProducer[String, String](kafkaProducerParams) with Serializable
    val bc = ssc.sparkContext.broadcast(producer)

    ds.foreachRDD(rdd => {
      //代表对数据进行处理
      if(! rdd.isEmpty()){
        rdd.foreachPartition(iter => {
          val producer: KafkaProducer[String, String] with Serializable = bc.value
          iter.foreach(msg => {
            val record: ProducerRecord[String, String] = new ProducerRecord[String, String]("topicB", null, msg.value())
            producer.send(record)
            //需要发送结果的话 需要.get
            //val value: Future[RecordMetadata] = producer.send(record)
            val metadata: RecordMetadata = producer.send(record).get

            metadata.topic()
            println(" metadata.partition() = " + metadata.partition())
            println(" metadata.offset() = " + metadata.offset())
            println(" metadata.topic() = " + metadata.topic())
          })
        })
      }

    })
    ssc.start()
    ssc.awaitTermination()
  }

}

使用pyspark读取kafka的数据_spark


依赖啥的在前几篇文章

前几篇的小总结

流式处理典型的问题:

1、数据输出到外部存储
2、应用的监控
3、Offset的管理
4、广播变量的更新
5、状态的管理(借助外部存储)

需要以下几个程序:
1、接口参数
2、offset相关问题
(偏移量自动/手动提交;设置/保存偏移量的位置;__consumer_offsets的观察)
3、管理offset(redis)
4、广播变量更新
5、监控
(05老版本,获取json串并解析;06新版本,加监听;WordCountWithMonitor 适用于批处理程序)
6、kafka 2 kafka
(01 普通程序;02 序列化producer、广播变量、懒加载)

工具类:
KafkaUtils
RedisUtils
KafkaProducer

下面笔记比较乱:

kafka接口
receiver :
        旧版高阶API 
        旧版低阶API 
        zk  会单独起一个receiver去接收数据,造成很多问题,比如说OOM 只有这一个接收数据 可能存不下 挂掉 数据丢失  为了避免这个 使用WAL(实际上就是开启checkpoint放进hdfs 安全了 但造成性能下降)
Direct :
         010 新版高阶API  已经没有receiver方式的代码了  只有Direct方式了  新版API只存到 __consumer_offset
        kafka

        旧版 API 0.8~0.9 有这两种方式
        好多API都不向下兼容


        存到zk或是_consumer_offset是系统管理的,而checkpoint是自定义管理的,
        可以放到各种地方
                    1.mysql 2.redis 3.hdfs 3.hbase 4.zk  5.等等等
                    这只是可不可以
                    不是好不好

                    所以合适的是,hbase性能好,但有点大材小用,     hbase也有事务,叫行事务
                                 mysql 优点支持事务, ACID,稳定
                                 
                    checkpoint最大的问题是应用程序不能升级,系统不能保证升级


        kafkaAPI 0.8版本 缺省的情况下,即默认,有两种方式为receiver和direct
        receiver就是将offset存到zk
        direct有两种方式,一类就是直接不存offset,一直都是消费最新的数据,不管偏移量
                        另一类如果0.8版本的direct要存offset就是要手动存,自己写代码维护,
                            那就任意了,可以存到hdfs rdbms redis等等,最简单的方式就是checkpoint,但它有很多问题,一般不使用
5.offset :

offset一般自定义存到redis
1.设置offset----》怎么读出来
2.写offset -----》 怎么写

dStream
   消费数据时,先存计算结果再存offset 会造成重复消费数据的可能
             先存offset再存计算结果可能造成丢失数据,一般不使用

    然后进一步想,要么使用事务,要么使用幂等,才能比较好处理这个问题(尽可能exactly once)
                不过这都不一定 看业务 看情况
         
    DStream的输出算子 foreachRDD(rdd)   driver
               rdd 写到mysql  用 foreachPartition(item => ...  结果)  executor

               存在的地方都不一样 所以一般用事务不好使
6.广播变量:一般是用来做优化
BC   broadcast  ---->  在driver上,程序起来的时候只执行一次
        DS.foreachRDD(rdd => )
7.写外部存储:
kafka ------->   SparkStreaming --------> kafka 

rdd.foreachPartition(  
        item =>
        通常在里面建立连接即executor,一般不在外面即driver建立连接(麻烦,需要连接序列化)
        )

套路一般都是这样的,变得就是些外部存储建立连接的方式不同
笔记:
__consumer_offset看某个topic偏移量

首先看看在哪个分区
假设group-id为KafkaUtils10,则计算 ().hashcode % 50 = 48

那么使用命令(此命令只针对kafka0.11以上版本 低版本好像要去掉.group.)

kafka新版API中,自动管理offset,缺省情况下,offset 5s提交
redis:数据结构
要获取Metrics信息,监控

1.加监听:

SparkStreaming,spark程序也能加监听

只适合spark 2.2.0以上版本 ssc. addSparkStreamingListener

2.老办法:解析Metrics的json串信息 好像是http请求之类的返回json串

而且一般请求的4040端口有一定可能被占用的,可能是4041、4042 所以还需要验证此端口的appID是不是同一个

项目中大都是把相似的功能放在一起