Kafka

文章目录

  • 消息中间件的对比
  • 概述
  • 环境搭建
    • Zookeeper
    • Kafka
  • 分区
    • 分区策略
    • 高可用机制
  • 生产者
    • 发送类型
      • 同步发送
      • 异步发送
  • 消费者
    • 消费者组
    • 消息有序性
    • 提交和偏移量
      • 手动提交偏移量
  • SpringBoot集成Kafka

消息中间件的对比

  1. Kafka
    采用发布/订阅模型,以高吞吐量和低延迟为设计目标。
    核心概念是日志(log)和分区(partition),它将消息持久化到磁盘,并允许以高效的方式进行批量读写。
    设计目标是提供高吞吐量的数据流处理能力,适合处理海量数据和高并发场景。
    Kafka 在需要处理大规模数据流、实时数据处理、日志收集和分析等场景中表现出色。它常用于大数据应用、日志处理、指标监控、流式处理等场景。

  2. RabbitMQ
    基于 AMQP(Advanced Message Queuing Protocol)协议的消息队列系统,它采用传统的消息队列模型,支持广泛的消息传递模式(如点对点、发布/订阅、请求/响应等)。
    RabbitMQ 提供丰富的特性,如消息优先级、消息延迟、消息死信队列等,使得它更适合于一些需要灵活消息传递和处理的场景。
    RabbitMQ 常用于任务分发、异步通信、事件驱动架构等场景。

  3. RocketMQ
    高吞吐、低延迟、保证消息顺序性
    适用于可靠性要求比较高的金融互联网领域

概述

Kafka_第1张图片

Kafka_第2张图片

  • producer:发布消息的对象称之为主题生产者(Kafka topic producer)
  • topic: Kafka将消息分门别类,每一类的消息称之为一个主题( Topic)
  • consumer:订阅消息并处理发布的消息的对象称之为主题消费者(consumers)
  • broker:已发布的消息保存在一组服务器中,称之为Kafka集群。集群中的每一个服务器都是一个代理(Broker)。消费者可以订阅一个或多个主题(topic),并从Broker拉数据,从而消费这些已发布的消息。

环境搭建

Zookeeper

ZooKeeper 是一个分布式协调服务,它提供了一个可靠的分布式系统的基础设施,用于协调和管理分布式应用程序的状态信息。
ZooKeeper 主要关注分布式系统的一致性和可靠性,提供了分布式锁、队列、通知机制等基础功能,并支持分布式协调和领导选举。

而同样作为注册中心的Nacos,是一个动态服务发现、配置管理和服务治理平台,旨在简化微服务架构下的服务注册、发现和配置管理。提供了服务注册与发现、动态配置管理、服务健康监测和流量管理等功能,以帮助构建弹性、可伸缩和可靠的微服务架构。因此更适用于构建和管理微服务架构,处理服务注册与发现、动态配置、服务健康监测等场景。

Kafka对Zookeeper强依赖,因此需要先运行zookeeper容器

  1. 拉取镜像
docker pull zookeeper:3.4.14
  1. 创建容器
docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14

Kafka

  1. 拉取镜像
docker pull wurstmeister/kafka:2.12-2.3.1
  1. 创建容器
docker run -d --name kafka \
--env KAFKA_ADVERTISED_HOST_NAME=192.168.133.128 \
--env KAFKA_ZO0KEEPER_CONNECT=192.168.133.128:2181 \
--env KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.133.128:9092\
--env KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 \
--env KAFKA_HEAP_OPTS="-Xmx256M -Xms256M"\
-p 9092:9092 \
wurstmeister/kafka:2.12-2.3.1
  1. 导入依赖
<dependency>
    <groupId>org.apache.kafkagroupId>
    <artifactId>kafka-clientsartifactId>
dependency>
  1. 生产者代码实现
//设置kafka基本信息
Properties properties = new Properties();
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFTG,"192.168.133.128:9092");//kafka链接地址
properties.put(ProducerConfig.KEY_SERIALITZER_CLASS_CONFTG,"org.apache.kafka.common.serialization.stringserializer");//消息key的序列化器
properties.put(ProducerConfig.VALUE_SERIAIZER_CLASS_CONFTG,"org.apache.kafka.common.serialization.stringSerializer");//消息value的序列化器

//创建生产者对象
KafkaProducer<String,String> producer = new KafkaProducer<String,String>(properties);
//发送消息
ProducerRecord<String,String> record = new ProducerRecord<String,String>("topic","key","value");
producer.send(record) ;
//关闭消息通道(必须关闭,否则消息发送不成功)
producer.close();
  1. 消费者代码实现
//连接信息
Properties properties = new Properties();
properties.put(ConsumerConfig.B00TSTRAP_SERVERS_CONFIG,"192.168.133.128:9092");
//指定消费者组
properties.put(ConsumerConfig.GROUP_ID_CONFIG,"group1");
//反序列化的key和vaLlue
properties.put(ConsumerConfig.KEY_DESERIALIER_CLASS_CONFTG, "ong.apache.kafka.common.serialization.StringDeserializer");
properties.put(ConsumerConfig.VALUE_DESERLIALIZER_CLASS_CONFIG ,"ong.apache.kafka.common.serialization.StringDeserializer");

//创建消费者对象
KafkaConsumer<String,string> consumer = new KafkaConsumer<String,String>(properties);
//订阅主题
consumer.subscribe(Collections.singletonList("topic"));
while(true){
	//获取消息(每秒拉取一次)
	ConsumerRecords<String,String> consumerRecords = consumer.poll(Duration.ofMillis(1000));
}

分区

每一个分区都是一个顺序的、不可变的消息队列,并且可以持续的添加。分区中的消息都被分了一个序列号,称之为偏移量(offset),在每个分区中此偏移量都是唯一的。
Kafka_第3张图片

分区策略

分区策略 说明
轮询策略 按顺序轮流将每条数据分配到每个分区中
随机策略 每次都随机地将消息分配到每个分区
按键保存策略 生产者发送数据的时候,可以指定一个key,计算这个key的hashCode值,按照hashCode的值对不同消息进行存储

高可用机制

  1. Broker
    Kafka的服务器端由被称为Broker的服务进程构成,即一个Kafka集群由多个Broker组成
    这样如果集群中某一台机器宕机,其他机器上的Broker也依然能够对外提供服务。这其实就是Kafka 提供高可用的手段之一

  2. 备份机制
    Kafka_第4张图片

Kafka 中消息的备份又叫做副本(Replica)Kafka定义了两类副本:
领导者副本(Leader Replica)>追随者副本(Follower Replica)
Kafka_第5张图片

  • ISR (in-sync replica)需要同步复制保存的follower
    如果leader失效后,需要选出新的leader,选举的原则如下:
    第一:选举时优先从ISR中选定,因为这个列表中follower的数据是与leader同步的
    第二:如果ISR列表中的follower都不行了,就只能从其他follower中选取

生产者

发送类型

同步发送

直接使用KafkaProducer的send()方法,返回的是Future对象,再调用get()方法就知道是否发送成功

异步发送

调用KafkaProducer的send(ProducerRecord record, new Callback())方法

producer.send(record,new Callback() {
	@override
	public void onCompletion(RecordMetadata recordMetadata,Exception e) {
		if(e!=null){
			e.printstackTrace();
		}
		system.out.println(recordMetadata.offset());
	}
});

指定回调函数Callback(),服务器在返回时会调用Callback()方法,可用于异常处理等

消费者

消费者组

Kafka_第6张图片
消费者组(Consumer Group)︰指的就是由一个或多个消费者组成的群体
一个发布在Topic上消息被分发给此消费者组中的一个消费者
所有的消费者都在一个组中,那么这就变成了queue模型
所有的消费者都在不同的组中,那么就完全变成了发布-订阅模型

消息有序性

发送顺序和接收顺序一致
topic分区中消息只能由消费者组中的唯一一个消费者处理,所以消息肯定是按照先后顺序进行处理的。但是它也仅仅是保证Topic的一个分区顺序处理,不能保证跨分区的消息先后处理顺序。所以,如果你想要顺序的处理Topic的所有消息,那就只提供一个分区。

提交和偏移量

kafka不会像其他JMS队列那样需要得到消费者的确认,消费者可以使用kafka来追踪消息在分区的位置(偏移量)。消费者会往一个叫做_consumer_offset的特殊主题发送消息,消息里包含了每个分区的偏移量。如果消费者发生崩溃或有新的消费者加入群组,就会触发再均衡
Kafka_第7张图片

手动提交偏移量

//手动提交偏移量
properties.put(consumerConfig.ENABLE_AUTO_COMNMNIT_CONFIG,false);

ConsumerRecords<String,String> consumerRecords = consumer.poll(Duration.ofMillis(1000));

//同步和异步组合提交
try {
	while(true){
		ConsumerRecords<String,String> records = consumer.poll(Duration.ofMillis(1000));
		for (ConsumerRecord<String,string> record : records) {
			system.out.println(record.value());
			system.out.println(record.key());
		}
		//先使用异步提交
		consumer.commitAsync();
	}
}catch (Exception e){
	e.printstackTrace();
	system.out.println("记录错误信息: "+e);
}finally {
	try {
		//异步提交失败再同步提交
		consumer.commitsync();
	}finally {
		consumer.close();
	}
}

SpringBoot集成Kafka

  1. 导入依赖

<dependency>
	<groupId>org.springframework.kafkagroupId>
	<artifactId>spring-kafkaartifactId>
	<exclusions>
		<exclusion>
			<groupid>org.apache.kafkagroupId>
			<artifactId>kafka-clientsartifactid>
		exclusion>
	exclusions>
dependency>
<dependency>
	<groupId>org.apache.kafkagroupId>
	<artifactId>kafka-clientsartifactId>
dependency>
  1. 配置文件
server:
	port: 9991
spring:
	application:
		name: kafka-demo
	kafka:
		bootstrap-servers: 192.168.133.128:9092	#kafka地址
		producer:
			retries: 10	#重试次数
			key-serializer: org.apache.kafka.common.serialization.stringSerializer
			value-serializer: org.apache.kafka.common.serialization.stringSerializer
		consumer:
			group-id: test-hello-group	#组名称
			key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
			value-deserializer: org.apache.kafka.common.serialization.stringDeserializer
  1. 生产者
@Autowired
private KafkaTemplate<String,string> kafkaTemplate;

@GetMapping("/hello")
public String hello(){
	//第一个参数: topics
	//第二个参数:消息内容
	kafkaTemplate.send("kafka-hello","Hello");
	return "ok";
}
  1. 消费者
@Component
public class HelloListener {
	@KafkaListener(topics = "kafka-hello"})
	public void onMessage(String message){
		if(!Stringutils.isEmpty(message)){
			system.out.println( message);
		}
	}
}

你可能感兴趣的:(Spring,kafka,分布式)