大数据学习之路108-spark streaming基于redis历史state统计

我们之前使用spark streaming做过基于mysql的历史state统计,但是当时的方法很笨,因为写到mysql中第一是性能不好,第二是编码麻烦,所以一般不会有人那么做。而且当时的数据来源是socket。

所以现在我们的业务就是:

通过一个客户端工具实时的写数据到kafka中,然后通过spark streaming实时的监控并消费出来。写入到redis中进行实时的统计。

首先我们需要写一个客户端程序实时的生成一个字符串写入到kafka

所以我们就先写一个Java类,让这个类负责实时的生成数据写入kafka

代码如下:

package com.xiaoniu.kafka;
 
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
 
import java.util.Properties;
import java.util.Random;
import java.util.UUID;
 
public class GenerateWord {
    public static void main(String[] args) throws InterruptedException {
        //封装配置参数
        Properties props = new Properties();
        //kafka的brokers列表
        props.setProperty("bootstrap.servers", "marshal:9092,marshal01:9092,marshal02:9092,marshal03:9092,marshal04:9092,marshal05:9092");
        //key和value的序列化方式,因为需要网络传输所以需要序列化
        props.setProperty("key.serializer", StringSerializer.class.getName());
        props.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
       //创建一个生产者的客户端实例
        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(props);
        while(true){
            Thread.sleep(500);
            //生成一个随机的key
            String key = UUID.randomUUID().toString();
            //随机生成一个单词
            int base = 97;
            int acciCode = new Random().nextInt(26)+base;
            char word = (char)acciCode;
            System.out.println("word"+word);
            ProducerRecord<String, String> record = new ProducerRecord<>("wordcount2", key, String.valueOf(word));
            kafkaProducer.send(record);
            System.out.println("record = "+record);
        }
 
    }
}


在执行这段代码之前,我们先要在kafka中创建topic -----> wordcount2
在这里插入图片描述

创建完topic之后我们就可以执行这个程序了。

接下来我们就要集成redis了。

首先我们需要导入redis的pom依赖:

		<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

接下来我们需要封装一个redis连接池。但我们需要连接的时候就去连接池里拿。拿到连接就执行写操作。


package com.test.utils
 
import org.apache.commons.pool.impl.GenericObjectPool
import org.apache.commons.pool2.impl.GenericObjectPoolConfig
import redis.clients.jedis.{Jedis, JedisPool}
 
/**
  * 一个简单的人redis连接池
  */
object JPools {
     private val poolConfig = new GenericObjectPoolConfig()
  //连接池中最大的空闲连接数,默认是8
     poolConfig.setMaxIdle(5)
  //只支持最大的连接数,连接池中最大的连接数,默认是8
     poolConfig.setMaxTotal(2000)
  //连接池是私有的不能公开访问
  private val pool: JedisPool = new JedisPool(poolConfig,"marshal")
 
  /**
    * 对外提供一个可以从连接池获取连接的方法
    * @return
    */
  def getJedis = {
    val resource: Jedis = pool.getResource
    resource.select(0)
    resource
  }
}

然后直连kafka获取数据并写入redis,redis有一个hincrBy方法,这个方法可以根据key自增规定的值。

代码如下:


package com.test.sparkStreaming
 
import com.test.utils.JPools
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.log4j.{Level, Logger}
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import redis.clients.jedis.Jedis
 
 
/**
  * 将kafka+spark_redis整合词频统计
  */
object MyNetWorkWordCountRedis {
  def main(args: Array[String]): Unit = {
    Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
    val sparkConf: SparkConf = new SparkConf().setAppName("MyNetworkWordCount").setMaster("local[2]")
    //定义一个采样时间,每隔两秒采集一次数据
    val ssc: StreamingContext = new StreamingContext(sparkConf,Seconds(2))
    //创建一个消费者id
    val groupId = "day14_002"
    //定义一个主题
    val topic = "wordcount2"
 
    /**
      * kafka参数列表
      */
    val kafkaParams = Map[String,Object](
      "bootstrap.servers" -> "marshal:9092,marshal01:9092,marshal02:9092,marshal03:9092,marshal04:9092,marshal05:9092",
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> groupId,
      "auto.offset.reset" -> "earliest",
      "enable.auto.commit" -> (false:java.lang.Boolean)
 
    )
    //连接到kafka数据源
    val stream: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream(
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](Array(topic), kafkaParams)
    )
    stream.foreachRDD(rdd => {
      val reduced = rdd.map(_.value()).map((_,1)).reduceByKey(_+_)
       reduced.foreachPartition(
         it =>{
           val jedis: Jedis = JPools.getJedis
           it.foreach(
             y => {
               jedis.hincrBy("wordcount",y._1.toString,y._2.toLong)
             }
           )
           jedis.close()
         }
       )
    })
     ssc.start()
    ssc.awaitTermination()
  }
}

运行截图如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值