引用致谢:
https://www.cnblogs.com/xuwujing/p/8432984.html
一、概念
1.什么是Kafka?
Kafka是一种高吞吐量的分布发布-订阅消息系统,专为超高吞吐量的实时日志采集、实时数据同步、实时数据计算等场景来设计
2.主要分为
生产者API
消费者API
3.流处理架构
4.离散数据流(DStream)
DStream代表了一系列连续的RDDs
每个RDD都包含一个时间间隔内的数据
DStream既是输入的数据流,也是转换处理过的数据流
对DStream的转换操作即是对具体RDD操作
二、生产者API
这里在idea中使用kafka
1.添加 pom.xml文件依赖
<!--kafka-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.11.0.2</version>
</dependency>
2.具体实现类Demo01_KafkaProducer
package cn.kgc.kafka
import java.util.Properties
import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}
/**
* Created by wangchunhui on 2021/1/19 8:59
* 第一步:创建test topic
* 第二步:启动消费者控制台 kafka-console-consumer.sh --bootstrap-server singleNode:9092 --topic test
* 第三部:执行程序, 查看控制台输出 hello world
*/
object Demo01_KafkaProducer {
def main(args: Array[String]): Unit = {
// 创建配置
val props = new Properties()
// 设置Kafka集群
props.put("bootstrap.servers", "nodefour:9092")
// 设置ack
// 0: 不需要leader partition确认接收成功, 将消息发送到leader partition即可
// 1:需要等待leader partition确认接收成功
// -1(all): 需要等待leader partition以及ISR列表中的follower都确认接收成功
props.put("acks", "all")
// 设置key和value的序列化
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer")
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer")
// 创建一个Kafka的生产者
val producer = new KafkaProducer[String,String](props)
// 发送消息 三个参数: ①topic, ②key, ③value
producer.send(new ProducerRecord[String,String]("test","1001","zhangsan"))
// 关闭资源
producer.close()
}
}
3.在虚拟机中操作
kafka-console-consumer.sh --bootstrap-server hadoop100:9092 --topic abc --from-beginning --property print.key=true
三、消费者API
1.实现类Demo02_KafkaConsumer
package cn.kgc.kafka
import java.util
import java.util.Properties
import org.apache.kafka.clients.consumer.{ConsumerRecord, ConsumerRecords, KafkaConsumer}
/**
* Created by wangchunhui on 2021/1/19 9:34
*/
object Demo02_KafkaConsumer {
def main(args: Array[String]): Unit = {
// 创建一个配置
val props = new Properties()
// 配置Kafka集群的ip和端口号
props.put("bootstrap.servers", "nodefour:9092")
// 设置消费者组的id, 如果有多个相同id的消费者程序, 那么他们将在一个组当中
props.put("group.id", "testGroup1")
// 开启自动提交[默认就是开启]
props.put("enable.auto.commit", "true")
// 每隔5000ms提交一次
props.put("auto.commit.interval.ms", "1000") //默认值5000
// key和value的序列化
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
// 创建一个Consumer客户端
val consumer = new KafkaConsumer[String, String](props)
// consumer消费
val topics = new util.ArrayList[String]()
topics.add("test2")
// 订阅topic
consumer.subscribe(topics)
// 为了能够一直从Kafka中消费数据, 使用 while true 死循环
while (true) {
// 设置超时时间, 单位是毫秒, 返回一些条数据
val records: ConsumerRecords[String, String] = consumer.poll(1000)
// 对这些数据进行遍历输出
val iter: util.Iterator[ConsumerRecord[String, String]] = records.iterator()
while (iter.hasNext) {
val next: ConsumerRecord[String, String] = iter.next()
println(s"partition = ${next.partition()}, offset=${next.offset()}\nkey = ${next.key()}, value = ${next.value()}")
}
}
}
}
2.手动提交Offset
为什么要设置手动提交?
(1)自动提交是在kafka拉取到数据之后就直接提交,这样很容易丢失数据
(2)很多情况下我们需要从kafka成功拉取数据之后,对数据进行相应的处理之后再进行提交
具体实现类Demo03_KafkaConsumerManualOffset
package cn.kgc.kafka
import java.util
import java.util.Properties
import org.apache.kafka.clients.consumer.{ConsumerRecord, ConsumerRecords, KafkaConsumer}
/**
* Created by wangchunhui on 2021/1/19 10:16
*/
object Demo03_KafkaConsumerManualOffset {
def main(args: Array[String]): Unit = {
// 创建一个配置
val props = new Properties()
// 配置Kafka集群的ip和端口号
props.put("bootstrap.servers", "nodefour:9092")
// 设置消费者组的id, 如果有多个相同id的消费者程序, 那么他们将在一个组当中
props.put("group.id", "testGroup1")
// 关闭自动提交[默认就是开启]
props.put("enable.auto.commit", "false")
// key和value的反序列化
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
// 创建一个Consumer客户端
val consumer = new KafkaConsumer[String, String](props)
// consumer消费
val topics = new util.ArrayList[String]()
topics.add("test2")
// 订阅topic
consumer.subscribe(topics)
// 创建一个集合, 用来存放消息的个数
val buffer = new util.ArrayList[ConsumerRecord[String, String]]()
// 为了能够一直从Kafka中消费数据, 使用 while true 死循环
while (true) {
// 设置超时时间, 单位是毫秒, 返回一些条数据
val records: ConsumerRecords[String, String] = consumer.poll(1000)
// 对这些数据进行遍历输出
val iter: util.Iterator[ConsumerRecord[String, String]] = records.iterator()
while (iter.hasNext) {
val next: ConsumerRecord[String, String] = iter.next()
println(s"partition = ${next.partition()}, offset=${next.offset()}\nkey = ${next.key()}, value = ${next.value()}")
buffer.add(next)
}
if(buffer.size()>5){
// 手动提交offset有两种, 一种是同步阻塞方式, 一种是异步非阻塞方式
consumer.commitAsync()
// consumer.commitSync()
buffer.clear()
}
}
}
}