Kafka直连方式存储MySQL

记得在之前写了一篇是MySQL基础使用的,这次就用MySQL来保存Direct方式的偏移量。
代码如下:

package kafka1
import kafka.common.TopicAndPartition
import kafka.message.MessageAndMetadata
import kafka.serializer.StringDecoder
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka.KafkaCluster.Err
import org.apache.spark.streaming.kafka.{HasOffsetRanges, KafkaCluster, KafkaUtils}
import org.apache.spark.streaming.{Duration, StreamingContext}
import scalikejdbc.{DB, SQL}
import scalikejdbc.config.DBs


/*
将偏移量保存到mysql中
 */
class DirectMySQL {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("ssom").setMaster("local[2]")
    val ssc = new StreamingContext(conf,Duration(3000))
    //一系列基本配置
    val groupid="gp0123"
    val brokerList="192.168.85.200:9092,192.168.85.201:9092,192.168.85.202:9092"
    val topic="topic009"
    val topics=Set(topic)
    //设置kafka的配置
    val kafkas=Map(
      "metadata.broker.list"->brokerList,
      "group.id"->groupid,
      "auto.offset.reset"->kafka.api.OffsetRequest.SmallestTimeString
    )
    //加载配置
    DBs.setup()
    //这一块我们就不需要再进行查询zk中的offset,直接查询Mysql中的Offset数据
    val fromdbOffset:Map[TopicAndPartition,Long]=
      DB.readOnly{
        implicit session =>
          //每个分组下的所有消息
          SQL(s"select * from offsets where groupid='${groupid}'")
              .map(m=>(TopicAndPartition(
                m.string("topic"),m.int("partitions")),m.long("untiloffsets")))
            .toList().apply()
      }.toMap //最后要toMap一下,因为前面的返回值已经给定
    //创建一个InputDStream,然后根据offset读取数据
    var kafkaStream:InputDStream[(String,String)]=null
    //从MySQL中获取数据,进行判断
    if(fromdbOffset.size==0){
      //如果程序第一次启动
      kafkaStream=KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder](ssc,kafkas,topics)
    }else{
      //如果程序不是第一次启动
      //首先获取Topic和Partition、Offset
      var checkOffsets=Map[TopicAndPartition,Long]()
      //加载kafka的配置
      val kafkaCluster = new KafkaCluster(kafkas)
      //首先获取kafka中的所有Topic partition offset
      val earliesOffsets: Either[Err,
        Map[TopicAndPartition, KafkaCluster.LeaderOffset]] =
        kafkaCluster.getEarliestLeaderOffsets(fromdbOffset.keySet)
      //然后开始进行比较大小,用Mysql中的offset和kafka的offset进行比较
      if(earliesOffsets.isRight){
        //取到我们需要的Map
        val topicAndPartitionOffset:
          Map[TopicAndPartition, KafkaCluster.LeaderOffset] =
          earliesOffsets.right.get
        //比较直接进行比较大小
        fromdbOffset.map(owner=>{
          //取我们kafka汇总的offset
          val topicOffset = topicAndPartitionOffset.get(owner._1).get.offset
          //进行比较不允许重复消费,取最大的
          if(owner._2>topicOffset){
            owner
          }else{
            (owner._1,topicOffset)
          }
        })
      }
      val messageHandler = (mmd:MessageAndMetadata[String,String])=>{
        (mmd.key(),mmd.message())
      }
      kafkaStream= KafkaUtils.createDirectStream[String,String,
        StringDecoder,StringDecoder,
        (String,String)](ssc,kafkas,checkOffsets,messageHandler)
    }
    //开始处理数据流,和ZK一样
    kafkaStream.foreachRDD(kafkaRDD=>{
      //首先获取的数据转换,获取Offset,后面更新的时候使用
      val offsetRanges = kafkaRDD.asInstanceOf[HasOffsetRanges].offsetRanges
      val lines = kafkaRDD.map(_._2)
      lines.foreach(println)
      //更新偏移量
      DB.localTx(
        implicit session =>
          //收取所有topic paratition offset
       for(os<-offsetRanges){
         /*SQL("update offsets set groupid=?,topic=?,partitions=?,untilOffset=?")
           .bind(groupid,os.topic,os.partition,os.untilOffset).update().apply()*/
         SQL("replace into offsets(groupid ,topic,partitions,untilOffset) values(?,?,?,?)")
           .bind(groupid,os,topic,os.partition,os.untilOffset).update().apply()

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

通过这三篇博客的介绍,相信大家对存储Offset也有了一定的理解了吧。当然这三种方式都能存储Offset,所以选择哪种方式其实都一样的,看你喜欢哪种方式就可以选择哪种。

									 summed up by JiaMingcan
									 转载请署名:JiaMingcan
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值