开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看详情
简介
Kafka当前作为Apache开源项目,最早由Linkedin公司开发,使用Scala和jAVA进行编写,它是一个分布式的,支持分区,多副本基于Zookeeper协调的分布式消息系统,可以应用在基于Hadoop的批处理系统,低延迟的实时系统,日志/消息服务等场景;
特性
高吞吐量,低延迟:即时普通硬件KafKa也可以每秒处理几十万数百万消息;
可扩展性:支持集群热扩展,无需停机即可扩展机器,支持Hadoop并行加载数据
持久可靠性:消息被持久化保存到本地磁盘,支持数据备份防止数据丢失;
容错性:是分布式、分区、复制和容错的,当集群中副本数量为n,则允许n-1个节点失败,允许集群节点失败;
高并发:单节点支持上千个客户端,并保证零停机和零数据丢失;
基础概念
Topic:主题,接受Kafka消息,不同的Topic分开存储在不同的物理区域,类似于分库分表后的数据库逻辑表;
Partition:分区,每个主题可以包含多个分区,一个分区代表一个提交日志,消息最终追加到分区,然后以先入先出的顺序进行读取,但是无法保证整体消息消费顺序,也是通过分区来保证伸缩性与数据冗余;可以设置分区为1来保证消息顺序;
Replicas:副本,分区可以有多个副本,副本保存在节点(broker)上,多个副本只有一个leader,该副本可以对外提供服务,每个节点保存多个不同主题的分区的副本信息;AR为所有副本统称,ISR为与主副本保持同步的副本,从主副本中拉取消息,可以在主副本出现问题后选举产生新的主副本,OSR具有滞后性的副本,不参与主副本选举;
Producer:消息生产者,向Kafka特定的主题中发送消息,默认情况下通过轮询来将消息均衡发布到主题的所有分区中;也可以通过自定义的分区器来根据规则分发消息;
Consumer:消息消费者,负责主动拉取Kafka中的消息,每个消费者属于配置给定的消费者组,当消费者失效时也会被其他同组消费者进行消费;消息消费的状态保存在Consumer中;
ConsumerGroup:消费者组,多个consumer可以组成消费者组,每条消息只能被组中一个消费者消费,可以被不同组的多个消费者消费,当创建消费者组时需要指定对应的消费者组id(ConsumerGroupId)
Message:在生产者与消费者之间进行传递的对象实体,存储传递的信息;
简单整合Kafka
//引入依赖
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
//设置Yml文件
kafka-producer:
#(必填)#用于建立与kafka集群的连接,这个list仅仅影响用于初始化的hosts,来发现全部的servers。
bootstrapServers: 192.168.18.224:9092
#(必填)#topic名称
producerTopic: control_topic
#(默认,可不填)#强制刷新metadata的周期,即使leader没有变化
metadataMaxAgeMs: 300000
#***用来设置一个batch的最大字节数byte。当设置为0时,表示完全禁用batch的功能。如果batch.size设置过大,
#!***那么可能造成内存浪费,因为每个发送到不同partition的record都需要预先分配一块batch.size大小的内存。
#(默认,可不填)
batchSize: 1048576
# acks=0时,producer不会等待确认,直接添加到socket等待发送;
# acks=1时,等待leader写到local log就行;
# acks=all或acks=-1时,等待isr中所有副本确认
#(默认,可不填)
acks: 1
#***延迟发送消息记录的时间,producer在发送消息记录record的时候,会将发送到同一个partition的records压缩在batch中。
#***但通常这只发生在records到达速度快于records发送速度的情况下,很容易理解:如果发送速度大于record到达速度,则每来一个record都会被立即发送出去,
#***根本不存在将多个records压缩为一个的可能。
#(默认,可不填)
lingerMs: 0
#(默认,可不填)#发生错误时,重传次数。当开启重传时,需要将`max.in.flight.requests.per.connection`设置为1,否则可能导致失序
retries: 0
#***Producer可以用来缓存数据的内存大小。该值实际为RecordAccumulator类中的BufferPool,即Producer所管理的最大内存。
#***如果数据产生速度大于向broker发送的速度,producer会阻塞max.block.ms,超时则抛出异常
#(默认,可不填)
bufferMemory: 33554432
#(默认,可不填)#当向server发出请求时,这个字符串会发送给server,目的是能够追踪请求源
clientId: ""
#(默认,可不填)#TCP发送缓冲区(SO_SNDBUF)的大小,若send.buffer.bytes设为-1,则使用操作系统的默认值。
sendBufferBytes: -1
#(默认,可不填)#TCP接收缓冲区(SO_RCVBUF)大小,当receive.buffer.bytes设置为-1,则使用操作系统默认的大小。
receiveBufferBytes: -1
#(默认,可不填)#一个请求request中最大字节数,用于限制producer发送的单个请求request中,record batches的最大数量,以避免单个请求数据过于巨大。
maxRequestSize: 1048576
#(默认,可不填)#重连间隔时间,避免producer客户端过于紧密循环地重连kafka服务broker。该值针对的是所有client到broker的连接。
reconnectBackoffMs: 50
#(默认,可不填)#当一个producer到指定的partition的请求request失败时,在重连之前,需要等待的毫秒数。这是为了避免在某些失败的场景下,过于密集地重复发送请求。
retryBackoffMs: 100
#(默认,可不填)#Producer用于压缩数据的压缩类型,取值:none, gzip, snappy, or lz4
compressionType: gzip
#(默认,可不填)#关闭达到该时间的空闲连接
connectionsMaxIdleMs: 540000
#(默认,可不填)#client等待请求响应的最大时间,如果在这个时间内没有收到响应,客户端将重发请求,超过重试次数发送失败
requestTimeoutMs: 30000
#(默认,可不填)#控制block的时长,当buffer空间不够或者metadata丢失时产生block
maxBlockMs: 60000
#启动消费者yml文件加入kafka-consumer.enable = true.
# 消费者属性
kafka-consumer:
enable: true
#(必填)#kafka指定IP端口
kafkaServers: 192.168.18.224:9092
#(必填)#自定义消费者Topic
consumerTopic: topic_robot_cruise
#(必填)#自定义消费者组
consumerGroupId: mx_topic_20221018001
#(默认,可不填)#是否自动提交office
consumerEnableAutoCommit: false
#(默认,可不填)#超时时间
consumerSessionTimeout: 15000
#(默认,可不填)#消费提交个数
consumerAutoCommitInterval: 2000
#(默认,可不填)#消费方式:earliest最前消费,latest最新消费
consumerAutoCommitOffsetReset: latest
#(默认,可不填)#自定义消费者个数
consumerConcurrency: 3
消息发送与接收
/**
* Kafka工具类
* @author wangw
*/
@Component
@ConditionalOnClass(name = "org.springframework.kafka.core.KafkaTemplate")
public class KafkaUtil {
private static KafkaTemplate<String, String> kafkaTemplate;
@Autowired(required = true)
public void setKafkaTemplate(KafkaTemplate<String, String> kafkaTemplate) {
KafkaUtil.kafkaTemplate = kafkaTemplate;
}
//发送到指定分区
public static void send(String topic, String data) {
kafkaTemplate.send(topic, data);
}
//指定key作为hash散列,相同key可以发送到同一个分区
public static void send(String topic, String key, String data) {
kafkaTemplate.send(topic, key, data);
}
}
---
//调用发送测试生产者发送
KafkaUtil.send(KafkaTopicConst.ALARM_LAMP_CONTROL, jsonString);
---
//测试消费者消费
@Slf4j
@Service
public class BytLocationConsumer implements KafkaMessageInterface {
@Override
@KafkaListener(topics={KafkaTopicConst.ROBOT_CRUISE} ,containerFactory = "kafkaListenerContainerFactory")
public void handleMessage(List<ConsumerRecord<?, ?>> records, Acknowledgment ack){
for (ConsumerRecord consumerRecord : records) {
String val = consumerRecord.value().toString();
System.out.println(val);
}
ack.acknowledge();
}
}