从kafka中获取数据写入到redis中

2 篇文章 0 订阅

大家: 

  好!从kafka中获取数据写入到redis中,需要用到spark中的redis客户端配置,请参考前面的博客(https://blog.csdn.net/zhaoxiangchong/article/details/78379883)。

第一步 要先将数据打入到kafka中,请参照我以前的博客 https://blog.csdn.net/zhaoxiangchong/article/details/78379927

说明: 尤其要注意kafka中的topic的名称,这两个一定要一致。

第二步,idea中部署kafka打入redis的代码,如下所示:

package Traffic


import java.text.SimpleDateFormat
import java.util.Calendar
import kafka.serializer.{StringDecoder, StringEncoder}
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}
import net.sf.json.JSONObject


/**
  * Created by Administrator on 2017/10/14.
  * 功能: 从kafka中获取数据写入到redis中
  *
  */
object CarEventAnalysis {
  def main(args: Array[String]): Unit = {
   //配置SparkStrteaming
    val conf=new SparkConf().setAppName("CarEventAnalysis").setMaster("local[2]")
    val sc=new SparkContext(conf)
    val ssc=new StreamingContext(sc,Seconds(5))
    val dbindex=1 //指定是用哪个数据库进行连接
    //从kafka中读取数据(用直连的方法)
    val topics=Set("car_event")
    // 只要和brokers相关的都要写全
    val brokers="192.168.17.108:9092"
    //配置kafka参数
    val kafkaParams=Map[String,String](
      "metadata.broker.list"->brokers,
    "serializer.class"->"kafka.serializer.StringEncoder"
    )
    //创建一个流  这是一个模板代码  参数中的两个String代表的是kafka的键值对的数据,及key和value
    val kafkaStream=KafkaUtils.createDirectStream[String,String,
                    StringDecoder,StringDecoder](ssc,kafkaParams,topics)
    //从kafka中将数据读出
    val events=kafkaStream.flatMap(line=>{
      //转换为object
      val data=JSONObject.fromObject(line._2) // ._2是真正的数据
//      println(data)
      //必须用Some修饰data option有两个子类 none 代表无值  some代表有值
      // 加上some表示一定有值,后面有x.getString和x.getInt,保证程序能知道有值
      Some(data)
    })
    //从kafka中取出卡口编号和速度数据
    val carspeed=events.map(x=>(x.getString("camer_id"),x.getInt("car_speed")))
    //把数据变成(camer_id,(car_speed,1))
        .mapValues((x:Int)=>(x,1.toInt))
      //每隔10秒计算一次前20秒的速度(4个rdd) Tuple2表示两个参数
      // (速度,数量)  (速度,数量)
      .reduceByKeyAndWindow((a:Tuple2[Int,Int], b:Tuple2[Int,Int]) =>
      {(a._1 + b._1,a._2 + b._2)},Seconds(20),Seconds(10))
    // carspeed  速度之和  数量之和
//    carspeed.map{case(key,value)=>(key,value._1/value._2.toFloat)}
     carspeed.foreachRDD(rdd=>{
       rdd.foreachPartition(partitionofRecords=>{
         //得到连接池的一个资源
         val jedis=RedisClient.pool.getResource
         // camer_id 卡口以及总的速度
         partitionofRecords.foreach(pair=>{
           val camer_id=pair._1  //卡口
           val total_speed=pair._2._1  //总的速度
           val count=pair._2._2  //总的数量
           val now=Calendar.getInstance().getTime() //获取当前的时间
           val minuteFormat=new SimpleDateFormat("HHmm") //获取分钟格式
           val dayFormat=new SimpleDateFormat("yyyyMMdd") //获取天格式
           val time = minuteFormat.format(now) //获取分钟
           val day = dayFormat.format(now)     //获取天


           //开始往redis中插入数据
           if(count!=0){
             jedis.select(dbindex)   //用选择的数据库
             // set进去一个map
             jedis.hset(day + "_" + camer_id, time ,total_speed + "_" + count)
             // 从redis中取数据
             val foreachdata=jedis.hget(day + "_" + camer_id, time)
             println(foreachdata)
           }
         })
         RedisClient.pool.returnResource(jedis)
       })
     })
    println("----------计算开始---------------------------")


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

 第三步: idea中运行第二步部署好的kafka打入redis的代码,程序截图如下所示:

说明: 这说明,kafka对应的topic中没有job为其打入数据。这正常,因为此时还没有往kafka中打数据,此步是为了测试代码的正确性

如果在没有引入依赖jar的情况下,此步是会报错的,截图如下所示:

说明: 需要引入ezmorph-1.0.6.jar, 以及三个依赖jar commons-collections-3.2.jar,commons-lang-2.3.jar,commons-pool2-2.2.jar, 共四个jar 

第四步: 运行第一步的往kafka中打数据的程序,截图以下所示:

说明: 1  截图显示,已经开始往kafka中打数据了

         2 此时的数据源,测试数据要造的多点,防止一会就把数据全部打到kafka中了

第五步:  此时kafka中有数据了,检查第三步的程序的运行结果,截图如下所示:

说明: 这就说明,kafka已经开始往redis中打数据了

第六步: 登录到redis的客户端,验证数据是否存入redis中

[root@hadoop ~]# redis-cli -p 12002
127.0.0.1:12002> select 1
OK
127.0.0.1:12002[1]> hgetall 20180824_310999015305
1) "2038"
2) "40_2"

说明: 结果的意思是,在20180824的20点38分,在卡口310999015305,共有2辆车通过,这2辆车的总速度是40

说明: 1  因为程序中redis中的key值的时间是按照当前日期来的,所以显示了20180824日,而非测试数据中的日期。而在实际的生产中,数据中的日期和当前日期是很相近的,因为是实时计算

   

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过在Flink使用Kafka消费者的`FlinkKafkaConsumer`类来读取Kafka消息,并使用`FlinkKafkaConsumer`提供的`assignTimestampsAndWatermarks`方法指定用于生成Watermark的时间戳生成器。然后,你可以使用Flink的`redis`客户端库来将偏移量写入Redis。 具体的实现步骤如下: 1. 创建`FlinkKafkaConsumer`实例并指定Kafka主题和消费者组。 ``` FlinkKafkaConsumer consumer = new FlinkKafkaConsumer(topic, new SimpleStringSchema(), properties); consumer.setStartFromEarliest(); // 从最早的消息开始消费 ``` 2. 使用`assignTimestampsAndWatermarks`方法为Kafka消息生成Watermark。 ``` consumer.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks() { private long currentTimestamp = Long.MIN_VALUE; @Override public long extractTimestamp(String element, long previousElementTimestamp) { // 从消息提取时间戳 long timestamp = Long.parseLong(element.split(",")[0]); currentTimestamp = Math.max(timestamp, currentTimestamp); return timestamp; } @Override public Watermark getCurrentWatermark() { // 根据最大时间戳生成Watermark return new Watermark(currentTimestamp == Long.MIN_VALUE ? Long.MIN_VALUE : currentTimestamp - 1); } }); ``` 3. 使用Flink的`redis`客户端库将偏移量写入Redis。 ``` DataStream<String> stream = env.addSource(consumer); stream.map(new MapFunction<String, Tuple2<String, Long>>() { @Override public Tuple2<String, Long> map(String value) throws Exception { // 从消息提取偏移量 long offset = Long.parseLong(value.split(",")[1]); return new Tuple2<>("offset", offset); } }).addSink(new RedisSink<>(redisConfig, new RedisOffsetMapper())); ``` 其,`RedisOffsetMapper`是一个实现了`RedisMapper`接口的类,用于将偏移量写入Redis。 ``` public class RedisOffsetMapper implements RedisMapper<Tuple2<String, Long>> { @Override public RedisCommandDescription getCommandDescription() { return new RedisCommandDescription(RedisCommand.SET); } @Override public String getKeyFromData(Tuple2<String, Long> data) { return data.f0; } @Override public String getValueFromData(Tuple2<String, Long> data) { return data.f1.toString(); } } ``` 这样,当Flink从Kafka读取消息时,就会自动生成Watermark,并将偏移量写入Redis

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值