import java.util

import kafka.common.TopicAndPartition
import kafka.message.MessageAndMetadata
import kafka.serializer.StringDecoder
import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka.{HasOffsetRanges, KafkaUtils, OffsetRange}
import org.apache.spark.streaming.{Duration, StreamingContext}
import redis.clients.jedis.{Jedis, JedisPool, JedisPoolConfig} object KafkaDricteRedis {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("redis").setMaster("local[*]")
val ssc = new StreamingContext(conf,new Duration(5000)) val groupid = "GB01" //组名
val topic = "topic_bc"//topic 名
//在redis中以 groupid/topic作为唯一标识 ,存储分区偏移量
//在Reids 使用的时hash类型来存储
val gtKey = groupid+"/"+topic
//topic
val topics = Set(topic)
//zk地址
val zkQuorum = "hadoop01:2181,hadoop02:2181,hadoop03:2181"
//brokerList
val brokerList = "hadoop04:9092,hadoop05:9092,hadoop06:9092" val kafkaParams = Map(
// metadata.broker.list
"metadata.broker.list"->brokerList,
"group.id"->groupid,
"auto.offset.reset"->kafka.api.OffsetRequest.SmallestTimeString
//从头开始消费
)
//记录topic 、分区对应的偏移量偏移量,在创建InputDStream时作为参数传如
//从这个偏移量开始读取
var fromOffset = Map[TopicAndPartition,Long]()
var kafkaDStream :InputDStream[(String,String)] = null
// 获取一个jedis连接
val conn = getConnection()
// conn.flushDB()
//jd.hget(groupid+topic,"")
//获取全部的keys
val values: util.Set[String] = conn.keys("*")
//println(values)
// [GB01/wordcount3] 分区数 偏移量
//如果keys中包含 GB01/wordcount3这样的key,则表示以前读取过
if(values.contains(gtKey)){
//获取key 为GB01/wordcount3 下面所对应的(k,v) /** conn.hgetAll(gtKey) GB01/wordcount3:
* 1 888
* 2 888
* 3 888
* 4 888
*/
var allKey: util.Map[String, String] = conn.hgetAll(gtKey)
//导入后,可以把Java中的集合转换为Scala中的集合
import scala.collection.JavaConversions._
var list: List[(String, String)] = allKey.toList
//循环得到的(k,v)
//这里面的 k 对应的是分区, v对应的是偏移量
for (key <- list){ //这里的key是一个tuple类型
//new一个TopicAndPartition 把 topic 和分区数传入
val tp = new TopicAndPartition(topic,key._1.toInt)
//把每个topic 分区 对应的偏移量传入
fromOffset += tp -> key._2.toLong
println("分区"+key._1+"偏移量为"+key._2)
}
//这里的是把数据(key ,value)是kafka 的key默认是null,
//value 是kafka中的value
val messageHandler =(mmd:MessageAndMetadata[String,String])=>{
( mmd.key(),mmd.message())
}
//创建一个InputDStream
kafkaDStream= KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder,(String,String)](ssc,
kafkaParams,fromOffset,messageHandler)
}else{
//如果以前没有读取过,创建一个新的InputDStream
kafkaDStream= KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder](
ssc,kafkaParams,topics
) }
//用来更新偏移量,OffsetRange中可以获取分区及偏移量
var OffsetRangs = Array[OffsetRange]()
//
kafkaDStream.foreachRDD(kafkaRDD=> {
//这里面的RDD是kafkaRDD ,可以转换为HasOffsetRange
val ranges = kafkaRDD.asInstanceOf[HasOffsetRanges]
// 获取分区信息的集合
OffsetRangs = ranges.offsetRanges
//获取value,(key 默认是null,没有用)
val map: RDD[String] = kafkaRDD.map(_._2)
map.foreach(x=>print("")) //更新偏移量
for (o <- OffsetRangs){
//取出偏移量
val offset = o.untilOffset
//取出分区
val partition = o.partition
println("partition: "+partition)
println("offset: "+offset)
//把通过hset,把对应的partition和offset写入到redis中
conn.hset(gtKey,partition.toString,offset.toString)
}
}) ssc.start()
ssc.awaitTermination() }
//Jedis连接池
def getConnection(): Jedis ={
//new 一个JedisPoolConfig,用来设定参数
val conf = new JedisPoolConfig()
val pool = new JedisPool(conf,"192.168.121.12",6379)
//最大连接数
conf.setMaxTotal(20)
//最大空闲数
conf.setMaxIdle(20) val jedis = pool.getResource()
//密码
jedis.auth("test123")
jedis }

sparkStreaming 与fafka直接方式 进行消费者偏移量的保存如redis 里面 避免代码改变与节点重启后的数据丢失与序列化问题的更多相关文章

  1. UserView--第二种方式(避免第一种方式Set饱和),基于Spark算子的java代码实现

      UserView--第二种方式(避免第一种方式Set饱和),基于Spark算子的java代码实现   测试数据 java代码 package com.hzf.spark.study; import ...

  2. -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

     本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法的区别 为什么wait( ...

  3. Linux服务器重启后IP变掉的处理方式

    工作中有一台服务器为物理机,重启后IP就变掉了,影响到了使用,于是将服务器上的IP配置为静态方式,问题得以解决,具体如下: 1.登陆Linux服务器,cd /etc/sysconfig/network ...

  4. sparkStreaming消费kafka-0.8方式:direct方式(存储offset到zookeeper)

    生产中,为了保证kafka的offset的安全性,并且防止丢失数据现象,会手动维护偏移量(offset) 版本:kafka:0.8 其中需要注意的点: 1:获取zookeeper记录的分区偏移量 2: ...

  5. Kafka连接SparkStreaming的两种方式

    第一种方式代码: import org.apache.spark.storage.StorageLevel import org.apache.spark.{HashPartitioner, Spar ...

  6. rocketmq 以广播方式实现消费者消费消息

    package com.bfxy.rocketmq.model; import java.util.List; import org.apache.rocketmq.client.consumer.D ...

  7. 利用反射快速给Model实体赋值 使用 Task 简化异步编程 Guid ToString 格式知多少?(GUID 格式) Parallel Programming-实现并行操作的流水线(生产者、消费者) c# 无损高质量压缩图片代码 8种主要排序算法的C#实现 (一) 8种主要排序算法的C#实现 (二)

    试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有120多个字段.现在合同每一次变更时都需要对合同原始信息进行归档一次,版本号依次递增.那么我们就要新建一张合同历史表, ...

  8. session 加入redis的实现代码方式

    session,中文经常翻译为会话,其本来的含义是 指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session.有时候我们可以看到这样的话&quo ...

  9. 初探内联方式的 onload="doSomething()"为何要加"()"?而js代码的 onload="doSomething" 和 addEventListener 为何不加"()"?

    问题引入:在看<Jquery基础教程>第四版的时,P34页有这样一段话 引用函数与调用函数 这里在将函数指定为处理程序时,省略了后面的圆括号,只使用了函数名.如果带着圆括号,函数会被立即调 ...

随机推荐

  1. 更改了react-redux 官方网站的todolist结构

    最近在学习胡子大哈的react小书,内容讲的由浅入深,很值得react,react-redux小白一读. 废话不多说直接上地址:http://huziketang.mangojuice.top/boo ...

  2. Mock an function to modify partial return value by special arguments on Python

    Mock an function to modify partial return value by special arguments on Python python mock一个带参数的方法,修 ...

  3. python基础类型—字典

    字典 字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据.python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必 ...

  4. js 读秒

    <input type="button" value=" 获取验证码 " class="verification right" &qu ...

  5. linux的基本操作(正则表达式)

    正则表达式 这部分内容可以说是学习shell脚本之前必学的内容.如果你这部分内容学的越好,那么你的shell脚本编写能力就会越强.所以不要嫌这部分内容啰嗦,也不要怕麻烦,要用心学习.一定要多加练习,练 ...

  6. react引入方式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. ajax方式提交表单数据并判断当前注册用户是否存在

    项目的目录结构 源代码: regservlet.java package register; import java.io.IOException; import java.io.PrintWrite ...

  8. Java编程基础篇第三章

    逻辑运算符 与(&)(&&),或(||)(|),非(!) &和&&的区别 &:无论&的左边真假,右边都进行运算 &&:当 ...

  9. 算法基础_递归_给定一个数字n,打印出所有的划分等式

    问题描述: 给定一个数字n,打印出所有的划分等式 例: n = 3 3 2+1 1+1+1 解题源代码: import java.util.Scanner; /** * 给定数字n,打印出其所有用加法 ...

  10. word2vec生成词向量和字向量

    生成字符向量的过程中需要注意: 1)在收集数据生成corpus时候,通过Word2Vec生成字向量的时候,产生了“ ”空格字符向量,但是加载模型是不会成功的.那么你不是生成的binary文件,就可以修 ...