SparkStreaming动态读取kafka生产者生产的数据并将它存入MySQL数据库

本文介绍了如何使用Spark Streaming从Kafka生产者获取实时数据,进行词频统计,并将结果持久化到MySQL数据库的过程。通过环境配置、代码实现和测试步骤,展示了数据流处理的基本流程。

SparkStreaming动态读取kafka生产者生产的数据并将它存入MySQL数据库


关于使用sparkstreaming读取kafka生产者生产的数据,并且将每一次输入的数据进行词频统计,然后将结果存储到MySQL数据库中。学习记录~

一、环境准备

  • zookeeper
  • kafka

二、编写程序

在idea中编写SparkStreaming代码:

import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe

case class Word(
               wordName: String,
               count:Int
               )
object KafkaDemo {
  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setMaster("local[2]").setAppName("KafkaDemo")
    val streamingContext = new StreamingContext(conf,Seconds(5))
    val sc = streamingContext.sparkContext
    
    val kafkaParams = Map[String,Object](
      "bootstrap.servers" -> "ethan002:9092", //从那些broker消费数据
      "key.deserializer" -> classOf[StringDeserializer], //发序列化的参数,因为写入kafka的数据经过序列化
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "use_a_separate_group_id_for_each_stream", //指定group.id
      "auto.offset.reset" -> "latest",//指定消费的offset从哪里开始:① earliest:从头开始  ;② latest从消费者启动之后开始
      "enable.auto.commit" -> (false: java.lang.Boolean)
      //是否自动提交偏移量 offset 。默认值就是true【5秒钟更新一次】,
      // true 消费者定期会更新偏移量 groupid,topic,parition -> offset ;
     // "false" 不让kafka自动维护偏移量     手动维护偏移
    )
    //    数组中存放的是在kafka中创建的topic
    val topics = Array("first", "t100")
    val stream = KafkaUtils.createDirectStream[String, String](
      streamingContext,
      PreferConsistent,
      Subscribe[String, String](topics, kafkaParams) //订阅主题
    )
    val mapDStream: DStream[(String, String)] = stream.map(record => (record.key, record.value)) //转换格式

    //对从kafka生产的一次消息进行词频统计
    val resultRDD: DStream[(String, Int)] = mapDStream.flatMap(_._2.split(" ")).map((_, 1)).reduceByKey(_ + _)

    //将DStream中的数据存储到mysql数据库中
    resultRDD.foreachRDD(
      rdd=>{
      rdd.foreach(
        data=>{
          val url = "jdbc:mysql://localhost:3306/hadoop?useUnicode=true&characterEncoding=UTF-8"
          val user = "root"
          val password = "123456"
          Class.forName("com.mysql.jdbc.Driver").newInstance()
          var conn: Connection = DriverManager.getConnection(url,user,password)
          val sql = "insert into word(wordName,count) values(?,?)"
          var stmt : PreparedStatement = conn.prepareStatement(sql)
          stmt.setString(1,data._1.toString)
          stmt.setString(2,data._2.toString)
          stmt.executeUpdate()
          conn.close()
      })
    })
    // 打印
    resultRDD.print()

    // 启动
    streamingContext.start()

    // 等待计算采集器的执行
    streamingContext.awaitTermination()
  }
}


三、进行测试

  • 启动zookeeper
    bin/zkServer.sh start

  • 启动kafka
    bin/kafka-server-start.sh ./config/server.properties
    在这里插入图片描述

  • 启动kafka的producer进程
    kafka-console-producer.sh --broker-list ethan002:9092 --topic first
    在这里插入图片描述

  • 运行SparkStreaming程序

  • 在kafka的producer进程输入数据

    [root@ethan002 ~]# kafka-console-producer.sh --broker-list ethan002:9092 --topic first
    >hello world
    >hello world
    >world hello
    >hello world
    
  • 查看结果

    1. idea控制台中查看结果
      在这里插入图片描述

    2. 在mysql中查看
      在这里插入图片描述


目前仅仅是对每一次读取kafka的数据分别进行一个词频统计,我将继续努力实现对词频的连续累计统计的程序。
<think>我们参考提供的引用内容来构建两个Python脚本:一个生产者(producer_json.py)将JSON格式数据发送到Kafka,一个消费者(consumer_json.py)从Kafka读取JSON数据写入MySQL数据库。引用[2]和[3]提供了发送JSON数据生产者示例。引用[1]和[4]提供了消费者从Kafka读取消息的示例。引用[1]还展示了如何将消息解析为JSON。我们需要在消费者的基础上增加写入MySQL的步骤。步骤:1.生产者:将数据序列化为JSON格式,然后发送到Kafka。2.消费者:从Kafka读取消息,解析JSON,然后将数据写入MySQL数据库。由于引用中没有直接提供写入MySQL的示例,我们将结合引用[1]的解析步骤,添加MySQL插入操作。注意:-我们假设已经有一个MySQL数据库且创建了相应的表。-需要安装kafka-python和pymysql库。可以使用pip安装:```pipinstallkafka-pythonpymysql```下面我们分别编写两个脚本。###生产者脚本:producer_json.py这个脚本将生成JSON格式的数据发送到Kafka。我们模拟一些简单的数据,例如包含id和timestamp的数据。```python#producer_json.pyimportjsonimporttimeimportdatetimefromkafkaimportKafkaProducer#配置Kafka服务器地址bootstrap_servers=['localhost:9092']#主题名称topic_name='json_data_topic'#创建生产者,使用value_serializer将值序列化为JSON字符串producer=KafkaProducer(bootstrap_servers=bootstrap_servers,value_serializer=lambdam:json.dumps(m).encode('utf-8'))#发送5条消息作为示例foriinrange(5):#构造一条数据,可以是字典形式data={'id':i,'message':f'message_{i}','timestamp':datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S')}#发送到Kafkaproducer.send(topic_name,data)print(f"Sent:{data}")time.sleep(1)#关闭生产者producer.close()```###消费者脚本:consumer_json.py这个脚本从Kafka读取JSON数据,解析后写入MySQL数据库。我们需要先配置MySQL连接信息。这里假设MySQL中有一个数据库`test_db`,其中有一张表`json_data`,表结构为:```sqlCREATETABLE`json_data`(`id`INT,`message`VARCHAR(100),`timestamp`DATETIME);```消费者脚本如下:```python#consumer_json.pyimportjsonimportpymysqlfromkafkaimportKafkaConsumer#配置Kafkabootstrap_servers=['localhost:9092']topic_name='json_data_topic'#创建消费者consumer=KafkaConsumer(topic_name,bootstrap_servers=bootstrap_servers,auto_offset_reset='earliest',#从最早的消息开始读取group_id='my-group',#消费者组,如果不设置会读取所有消息(包括历史),设置后只读取未消费的消息value_deserializer=lambdam:json.loads(m.decode('utf-8'))#反序列化为JSON对象)#MySQL配置mysql_config={'host':'localhost','port':3306,'user':'root','password':'your_password',#修改为你的MySQL密码'db':'test_db','charset':'utf8mb4'}#连接到MySQLconnection=pymysql.connect(**mysql_config)try:withconnection.cursor()ascursor:#持续消费消息formsginconsumer:#获取消息的值,已经是字典形式data=msg.valueprint(f"Received:{data}")#构造SQL语句(根据表结构)sql="INSERTINTO`json_data`(`id`,`message`,`timestamp`)VALUES(%s,%s,%s)"#执行SQLcursor.execute(sql,(data['id'],data['message'],data['timestamp']))connection.commit()print("InsertedintoMySQLsuccessfully")finally:connection.close()```###注意事项:1.确保Kafka服务运行在localhost:9092,且已经创建了主题`json_data_topic`(或者脚本可以自动创建,需要Kafka配置允许自动创建主题)。2.MySQL配置需要根据实际环境修改,包括用户名、密码、数据库名和表名。3.在消费者脚本中,我们使用了消费者组(group_id),这样在多个消费者的情况下可以实现负载均衡。如果不设置group_id,则默认不会加入消费者组,会读取所有消息(包括历史消息)。###运行步骤:1.启动Kafka服务器。2.创建主题(如果Kafka配置不允许自动创建):```kafka-topics.sh--create--bootstrap-serverlocalhost:9092--replication-factor1--partitions1--topicjson_data_topic```3.启动消费者脚本(它会等待消息到来)。4.启动生产者脚本,它将发送5条消息。然后可以在消费者脚本中看到插入MySQL的日志,也可以在MySQL中查询表数据。§§相关问题§§1.如何处理Kafka消费者中的错误和重试机制?2.如何优化Kafka生产者以提高发送效率?3.MySQL插入操作出现主键冲突时如何解决?</think> ### Python实现Kafka处理JSON数据存储到MySQL 我将为您提供完整的解决方案,包含`producer_json.py`和`consumer_json.py`两个脚本,实现JSON数据发送到Kafka、消费后存入MySQL的完整流程。 --- ### **1. producer_json.py - 生产者脚本** ```python # producer_json.py from kafka import KafkaProducer import json import time import datetime # Kafka配置 BOOTSTRAP_SERVERS = 'localhost:9092' TOPIC_NAME = 'json_topic' # 创建生产者实例,指定JSON序列化器 producer = KafkaProducer( bootstrap_servers=BOOTSTRAP_SERVERS, value_serializer=lambda m: json.dumps(m).encode('utf-8') ) # 模拟生成JSON格式数据 sample_data = [ {"user_id": 101, "name": "张三", "action": "login", "timestamp": datetime.datetime.now().isoformat()}, {"user_id": 102, "name": "李四", "action": "purchase", "timestamp": datetime.datetime.now().isoformat()}, {"user_id": 103, "name": "王五", "action": "logout", "timestamp": datetime.datetime.now().isoformat()} ] # 发送数据Kafka for data in sample_data: producer.send(TOPIC_NAME, data) print(f"已发送: {data}") time.sleep(1) # 模拟延迟 # 确保所有消息发送完成 producer.flush() producer.close() ``` --- ### **2. consumer_json.py - 消费者脚本** ```python # consumer_json.py from kafka import KafkaConsumer import json import pymysql # Kafka配置 BOOTSTRAP_SERVERS = 'localhost:9092' TOPIC_NAME = 'json_topic' # MySQL配置 MYSQL_HOST = 'localhost' MYSQL_USER = 'root' MYSQL_PASSWORD = 'your_password' # 替换为实际密码 MYSQL_DB = 'kafka_data' # 创建消费者实例 consumer = KafkaConsumer( TOPIC_NAME, bootstrap_servers=BOOTSTRAP_SERVERS, auto_offset_reset='earliest', value_deserializer=lambda m: json.loads(m.decode('utf-8')) ) # 连接到MySQL connection = pymysql.connect( host=MYSQL_HOST, user=MYSQL_USER, password=MYSQL_PASSWORD, database=MYSQL_DB, cursorclass=pymysql.cursors.DictCursor ) # 确保表存在 with connection.cursor() as cursor: cursor.execute(""" CREATE TABLE IF NOT EXISTS user_actions ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, name VARCHAR(50), action VARCHAR(20), timestamp DATETIME ) """) connection.commit() # 处理消息写入MySQL for message in consumer: data = message.value print(f"已接收: {data}") with connection.cursor() as cursor: sql = """ INSERT INTO user_actions (user_id, name, action, timestamp) VALUES (%s, %s, %s, %s) """ cursor.execute(sql, ( data['user_id'], data['name'], data['action'], data['timestamp'] )) connection.commit() print("数据已写入MySQL\n") # 关闭连接 connection.close() ``` --- ### **运行准备** 1. **前置依赖**: ```bash pip install kafka-python pymysql ``` 2. **MySQL准备**: ```sql CREATE DATABASE kafka_data; -- consumer会自动创建表 ``` 3. **启动Kafka**: ```bash # 创建主题 kafka-topics --create --topic json_topic --bootstrap-server localhost:9092 ``` --- ### **执行流程** 1. 运行生产者: ```bash python producer_json.py ``` ``` 已发送: {'user_id': 101, 'name': '张三', ...} 已发送: {'user_id': 102, 'name': '李四', ...} ``` 2. 运行消费者: ```bash python consumer_json.py ``` ``` 已接收: {'user_id': 101, 'name': '张三', ...} 数据已写入MySQL ``` --- ### **关键技术点** 1. **JSON序列化**: - 生产者使用`value_serializer=json.dumps` - 消费者使用`value_deserializer=json.loads` - 确保二进制数据与JSON双向转换[^2][^1] 2. **MySQL交互**: - 使用`pymysql`执行参数化SQL - 自动创建表结构 - 事务提交保证数据一致性[^1] 3. **Kafka配置**: - `auto_offset_reset='earliest'`:从最早消息开始消费 - `group_id`可选(默认不设置) - 支持多分区消费能力[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

似懂非dong

你的肯定使我加倍努力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值