Kafka从入门到进阶

Kafka 3.x.x 入门到精通(06)——Kafka进阶 Kafka 3.x.x 入门到精通(06)👉👉👉👉Kafka进阶 阅读详情

1. Apache Kafka是一个分布式流平台

1.1 流平台有三个关键功能:

  1. 发布和订阅流记录,类似于一个消息队列或企业消息系统
  2. 以一种容错的持久方式存储记录流
  3. 在流记录生成的时候就处理它们

1.2 Kafka通常用于两大类应用:

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

  1. 构建实时流数据管道,在系统或应用程序之间可靠地获取数据
  2. 构建对数据流进行转换或输出的实时流媒体应用程序

1.3 有几个特别重要的概念:

Kafka is run as a cluster on one or more servers that can span multiple datacenters.

The Kafka cluster stores streams of records in categories called topics.

Each record consists of a key, a value, and a timestamp.

Kafka作为集群运行在一个或多个可以跨多个数据中心的服务器上

从这句话表达了三个意思:

  1. Kafka是以集群方式运行的
  2. 集群中可以只有一台服务器,也有可能有多台服务器。也就是说,一台服务器也是一个集群,多台服务器也可以组成一个集群
  3. 这些服务器可以跨多个数据中心

Kafka集群按分类存储流记录,这个分类叫做主题

这句话表达了以下几个信息:

  1. 流记录是分类存储的,也就说记录是归类的
  2. 我们称这种分类为主题
  3. 简单地来讲,记录是按主题划分归类存储的

每个记录由一个键、一个值和一个时间戳组成

1.4 Kafka有四个核心API:

  • Producer API :允许应用发布一条流记录到一个或多个主题
  • Consumer API :允许应用订阅一个或多个主题,并处理流记录
  • Streams API :允许应用作为一个流处理器,从一个或多个主题那里消费输入流,并将输出流输出到一个或多个输出主题,从而有效地讲输入流转换为输出流
  • Connector API :允许将主题连接到已经存在的应用或者数据系统,以构建并允许可重用的生产者或消费者。例如,一个关系型数据库的连接器可能捕获到一张表的每一次变更

(画外音:我理解这四个核心API其实就是:发布、订阅、转换处理、从第三方采集数据。)

在Kafka中,客户端和服务器之间的通信是使用简单的、高性能的、与语言无关的TCP协议完成的。

2. Topics and Logs(主题和日志)

一个topic是一个分类,或者说是记录被发布的时候的一个名字(画外音:可以理解为记录要被发到哪儿去)。

在Kafka中,topic总是有多个订阅者,因此,一个topic可能有0个,1个或多个订阅该数据的消费者。

对于每个主题,Kafka集群维护一个分区日志,如下图所示:

Kafka从入门到进阶

 

每个分区都是一个有序的、不可变的记录序列,而且记录会不断的被追加,一条记录就是一个结构化的提交日志(a structured commit log)。

分区中的每条记录都被分配了一个连续的id号,这个id号被叫做offset(偏移量),这个偏移量唯一的标识出分区中的每条记录。(PS:如果把分区比作数据库表的话,那么偏移量就是主键)

Kafka集群持久化所有已发布的记录,无论它们有没有被消费,记录被保留的时间是可以配置的。例如,如果保留策略被设置为两天,那么在记录发布后的两天内,可以使用它,之后将其丢弃以释放空间。在对数据大小方面,Kafka的性能是高效的,恒定常量级的,因此长时间存储数据不是问题。

Kafka从入门到进阶

 

事实上,唯一维护在每个消费者上的元数据是消费者在日志中的位置或者叫偏移量。偏移量是由消费者控制的:通常消费者在读取记录的时候会线性的增加它的偏移量,但是,事实上,由于位置(偏移量)是由消费者控制的,所有它可以按任意它喜欢的顺序消费记录。例如:一个消费者可以重置到一个较旧的偏移量来重新处理之前已经处理过的数据,或者跳转到最近的记录并从“现在”开始消费。

这种特性意味着消费者非常廉价————他们可以来来去去的消息而不会对集群或者其它消费者造成太大影响。

日志中的分区有几个用途。首先,它们允许日志的规模超出单个服务器的大小。每个独立分区都必须与宿主的服务器相匹配,但一个主题可能有多个分区,所以它可以处理任意数量的数据。第二,它们作为并行的单位——稍后再进一步。

(

画外音:简单地来说,日志分区的作用有两个:一、日志的规模不再受限于单个服务器;二、分区意味着可以并行。

什么意思呢?主题建立在集群之上,每个主题维护了一个分区日志,顾名思义,日志是分区的;每个分区所在的服务器的资源(比如:CPU、内存、带宽、磁盘等)是有限的,如果不分区(可以理解为等同于只有一个)的话,必然受限于这个分区所在的服务器,那么多个分区的话就不一样了,就突破了这种限制,服务器可以随便加,分区也可以随便加。

)

3. Distribution(分布)

日志的分区分布在集群中的服务器上,每个服务器处理数据,并且分区请求是共享的。每个分区被复制到多个服务器上以实现容错,到底复制到多少个服务器上是可以配置的。

Each partition is replicated across a configurable number of servers for fault tolerance.

每个分区都有一个服务器充当“leader”角色,并且有0个或者多个服务器作为“followers”。leader处理对这个分区的所有读和写请求,而followers被动的从leader那里复制数据。如果leader失败,followers中的其中一个会自动变成新的leader。每个服务器充当一些分区的“leader”的同时也是其它分区的“follower”,因此在整个集群中负载是均衡的。

也就是说,每个服务器既是“leader”也是“follower”。我们知道一个主题可能有多个分区,一个分区可能在一个服务器上也可能跨多个服务器,然而这并不以为着一台服务器上只有一个分区,是可能有多个分区的。每个分区中有一个服务器充当“leader”,其余是“follower”。leader负责处理这个它作为leader所负责的分区的所有读写请求,而该分区中的follow只是被动复制leader的数据。这个有点儿像HDFS中的副本机制。例如:分区-1有服务器A和B组成,A是leader,B是follower,有请求要往分区-1中写数据的时候就由A处理,然后A把刚才写的数据同步给B,这样的话正常请求相当于A和B的数据是一样的,都有分区-1的全部数据,如果A宕机了,B成为leader,接替A继续处理对分区-1的读写请求。

需要注意的是,分区是一个虚拟的概念,是一个逻辑单元。

4. Producers(生产者)

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

生产者发布数据到它们选择的主题中。生产者负责选择将记录投递到哪个主题的哪个分区中。要做这件事情,可以简单地用循环方式以到达负载均衡,或者根据一些语义分区函数(比如:基于记录中的某些key)

5. Consumers(消费者)

消费者用一个消费者组名来标识它们自己(PS:相当于给自己贴一个标签,标签的名字是组名,以表明自己属于哪个组),并且每一条发布到主题中的记录只会投递给每个订阅的消费者组中的其中一个消费者实例。消费者实例可能是单独的进程或者在单独的机器上。

如果所有的消费者实例都使用相同的消费者组,那么记录将会在这些消费者之间有效的负载均衡。

如果所有的消费者实例都使用不同的消费者组,那么每条记录将会广播给所有的消费者进程。

Kafka从入门到进阶

 

上图中其实那个Kafka Cluster换成Topic会更准确一些

一个Kafka集群有2个服务器,4个分区(P0-P3),有两个消费者组。组A中有2个消费者实例,组B中有4个消费者实例。

通常我们会发现,主题不会有太多的消费者组,每个消费者组是一个“逻辑订阅者”(以消费者组的名义订阅主题,而非以消费者实例的名义去订阅)。每个组由许多消费者实例组成,以实现可扩展性和容错。这仍然是发布/订阅,只不过订阅者是一个消费者群体,而非单个进程。

在Kafka中,这种消费方式是通过用日志中的分区除以使用者实例来实现的,这样可以保证在任意时刻每个消费者都是排它的消费,即“公平共享”。Kafka协议动态的处理维护组中的成员。如果有心的实例加入到组中,它们将从组中的其它成员那里接管一些分区;如果组中有一个实例死了,那么它的分区将会被分给其它实例。

(画外音:什么意思呢?举个例子,在上面的图中,4个分区,组A有2个消费者,组B有4个消费者,那么对A来讲组中的每个消费者负责4/2=2个分区,对组B来说组中的每个消费者负责4/4=1个分区,而且同一时间消息只能被组中的一个实例消费。如果组中的成员数量有变化,则重新分配。)

Kafka只提供分区下的记录的总的顺序,而不提供主题下不同分区的总的顺序。每个分区结合按key划分数据的能力排序对大多数应用来说是足够的。然而,如果你需要主题下总的记录顺序,你可以只使用一个分区,这样做的做的话就意味着每个消费者组中只能有一个消费者实例。

6. 保证

在一个高级别的Kafka给出下列保证:

  1. 被一个生产者发送到指定主题分区的消息将会按照它们被发送的顺序追加到分区中。也就是说,如果记录M1和M2是被同一个生产者发送到同一个分区的,而且M1是先发送的,M2是后发送的,那么在分区中M1的偏移量一定比M2小,并且M1出现在日志中的位置更靠前。
  2. 一个消费者看到记录的顺序和它们在日志中存储的顺序是一样的。
  3. 对于一个副本因子是N的主题,我们可以容忍最多N-1个服务器失败,而不会丢失已经提交给日志的任何记录。

7. Spring Kafka

Spring提供了一个“模板”作为发送消息的高级抽象。它也通过使用@KafkaListener注释和“监听器容器”提供对消息驱动POJOs的支持。这些库促进了依赖注入和声明式的使用。

Kafka从入门到进阶

 

7.1 纯Java方式

 1 package com.cjs.example.quickstart;
 2 
 3 import org.apache.kafka.clients.consumer.ConsumerConfig;
 4 import org.apache.kafka.clients.consumer.ConsumerRecord;
 5 import org.apache.kafka.clients.producer.ProducerConfig;
 6 import org.apache.kafka.common.serialization.IntegerDeserializer;
 7 import org.apache.kafka.common.serialization.IntegerSerializer;
 8 import org.apache.kafka.common.serialization.StringDeserializer;
 9 import org.apache.kafka.common.serialization.StringSerializer;
10 import org.springframework.kafka.core.*;
11 import org.springframework.kafka.listener.KafkaMessageListenerContainer;
12 import org.springframework.kafka.listener.MessageListener;
13 import org.springframework.kafka.listener.config.ContainerProperties;
14 
15 import java.util.HashMap;
16 import java.util.Map;
17 
18 public class PureJavaDemo {
19 
20 /**
21 * 生产者配置
22 */
23 private static Map<String, Object> senderProps() {
24 Map<String, Object> props = new HashMap<>();
25 props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.101.5:9093");
26 props.put(ProducerConfig.RETRIES_CONFIG, 0);
27 props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
28 props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
29 props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
30 return props;
31 }
32 
33 /**
34 * 消费者配置
35 */
36 private static Map<String, Object> consumerProps() {
37 Map<String, Object> props = new HashMap<>();
38 props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.101.5:9093");
39 props.put(ConsumerConfig.GROUP_ID_CONFIG, "hello");
40 props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
41 props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
42 props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
43 props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
44 props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
45 return props;
46 }
47 
48 /**
49 * 发送模板配置
50 */
51 private static KafkaTemplate<Integer, String> createTemplate() {
52 Map<String, Object> senderProps = senderProps();
53 ProducerFactory<Integer, String> producerFactory = new DefaultKafkaProducerFactory<>(senderProps);
54 KafkaTemplate<Integer, String> kafkaTemplate = new KafkaTemplate<>(producerFactory);
55 return kafkaTemplate;
56 }
57 
58 /**
59 * 消息监听器容器配置
60 */
61 private static KafkaMessageListenerContainer<Integer, String> createContainer() {
62 Map<String, Object> consumerProps = consumerProps();
63 ConsumerFactory<Integer, String> consumerFactory = new DefaultKafkaConsumerFactory<>(consumerProps);
64 ContainerProperties containerProperties = new ContainerProperties("test");
65 KafkaMessageListenerContainer<Integer, String> container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);
66 return container;
67 }
68 
69 
70 public static void main(String[] args) throws InterruptedException {
71 String topic1 = "test"; // 主题
72 
73 KafkaMessageListenerContainer container = createContainer();
74 ContainerProperties containerProperties = container.getContainerProperties();
75 containerProperties.setMessageListener(new MessageListener<Integer, String>() {
76 @Override
77 public void onMessage(ConsumerRecord<Integer, String> record) {
78 System.out.println("Received: " + record);
79 }
80 });
81 container.setBeanName("testAuto");
82 
83 container.start();
84 
85 KafkaTemplate<Integer, String> kafkaTemplate = createTemplate();
86 kafkaTemplate.setDefaultTopic(topic1);
87 
88 kafkaTemplate.sendDefault(0, "foo");
89 kafkaTemplate.sendDefault(2, "bar");
90 kafkaTemplate.sendDefault(0, "baz");
91 kafkaTemplate.sendDefault(2, "qux");
92 
93 kafkaTemplate.flush();
94 container.stop();
95 
96 System.out.println("结束");
97 }
98 
99 }

运行结果:

Received: ConsumerRecord(topic = test, partition = 0, offset = 67, CreateTime = 1533300970788, serialized key size = 4, serialized value size = 3, headers = RecordHeaders(headers = [], isReadOnly = false), key = 0, value = foo)
Received: ConsumerRecord(topic = test, partition = 0, offset = 68, CreateTime = 1533300970793, serialized key size = 4, serialized value size = 3, headers = RecordHeaders(headers = [], isReadOnly = false), key = 2, value = bar)
Received: ConsumerRecord(topic = test, partition = 0, offset = 69, CreateTime = 1533300970793, serialized key size = 4, serialized value size = 3, headers = RecordHeaders(headers = [], isReadOnly = false), key = 0, value = baz)
Received: ConsumerRecord(topic = test, partition = 0, offset = 70, CreateTime = 1533300970793, serialized key size = 4, serialized value size = 3, headers = RecordHeaders(headers = [], isReadOnly = false), key = 2, value = qux)

7.2 更简单一点儿,用SpringBoot

 1 package com.cjs.example.quickstart;
 2 
 3 import org.apache.kafka.clients.consumer.ConsumerRecord;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.boot.CommandLineRunner;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.kafka.annotation.KafkaListener;
 9 import org.springframework.kafka.core.KafkaTemplate;
10 
11 @Configuration
12 public class JavaConfigurationDemo {
13 
14 @KafkaListener(topics = "test")
15 public void listen(ConsumerRecord<String, String> record) {
16 System.out.println("收到消息: " + record);
17 }
18 
19 @Bean
20 public CommandLineRunner commandLineRunner() {
21 return new MyRunner();
22 }
23 
24 class MyRunner implements CommandLineRunner {
25 
26 @Autowired
27 private KafkaTemplate<String, String> kafkaTemplate;
28 
29 @Override
30 public void run(String... args) throws Exception {
31 kafkaTemplate.send("test", "foo1");
32 kafkaTemplate.send("test", "foo2");
33 kafkaTemplate.send("test", "foo3");
34 kafkaTemplate.send("test", "foo4");
35 }
36 }
37 }

application.properties配置

spring.kafka.bootstrap-servers=192.168.101.5:9092
spring.kafka.consumer.group-id=world

8. 生产者

 1 package com.cjs.example.send;
 2 
 3 import org.apache.kafka.clients.producer.ProducerConfig;
 4 import org.apache.kafka.common.serialization.IntegerSerializer;
 5 import org.apache.kafka.common.serialization.StringSerializer;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.kafka.core.DefaultKafkaProducerFactory;
 9 import org.springframework.kafka.core.KafkaTemplate;
10 import org.springframework.kafka.core.ProducerFactory;
11 
12 import java.util.HashMap;
13 import java.util.Map;
14 
15 @Configuration
16 public class Config {
17 
18 public Map<String, Object> producerConfigs() {
19 Map<String, Object> props = new HashMap<>();
20 props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.101.5:9092");
21 props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
22 props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
23 return props;
24 }
25 
26 public ProducerFactory<Integer, String> producerFactory() {
27 return new DefaultKafkaProducerFactory<>(producerConfigs());
28 }
29 
30 @Bean
31 public KafkaTemplate<Integer, String> kafkaTemplate() {
32 return new KafkaTemplate<Integer, String>(producerFactory());
33 }
34 
35 }
 1 package com.cjs.example.send;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.boot.CommandLineRunner;
 5 import org.springframework.kafka.core.KafkaTemplate;
 6 import org.springframework.kafka.support.SendResult;
 7 import org.springframework.stereotype.Component;
 8 import org.springframework.util.concurrent.ListenableFuture;
 9 import org.springframework.util.concurrent.ListenableFutureCallback;
10 
11 @Component
12 public class MyCommandLineRunner implements CommandLineRunner {
13 
14 @Autowired
15 private KafkaTemplate<Integer, String> kafkaTemplate;
16 
17 public void sendTo(Integer key, String value) {
18 ListenableFuture<SendResult<Integer, String>> listenableFuture = kafkaTemplate.send("test", key, value);
19 listenableFuture.addCallback(new ListenableFutureCallback<SendResult<Integer, String>>() {
20 @Override
21 public void onFailure(Throwable throwable) {
22 System.out.println("发送失败啦");
23 throwable.printStackTrace();
24 }
25 
26 @Override
27 public void onSuccess(SendResult<Integer, String> sendResult) {
28 System.out.println("发送成功," + sendResult);
29 }
30 });
31 }
32 
33 @Override
34 public void run(String... args) throws Exception {
35 sendTo(1, "aaa");
36 sendTo(2, "bbb");
37 sendTo(3, "ccc");
38 }
39 
40 
41 }

运行结果:

发送成功,SendResult [producerRecord=ProducerRecord(topic=test, partition=null, headers=RecordHeaders(headers = [], isReadOnly = true), key=1, value=aaa, timestamp=null), recordMetadata=test-0@37]
发送成功,SendResult [producerRecord=ProducerRecord(topic=test, partition=null, headers=RecordHeaders(headers = [], isReadOnly = true), key=2, value=bbb, timestamp=null), recordMetadata=test-0@38]
发送成功,SendResult [producerRecord=ProducerRecord(topic=test, partition=null, headers=RecordHeaders(headers = [], isReadOnly = true), key=3, value=ccc, timestamp=null), recordMetadata=test-0@39]

9. 消费者@KafkaListener

 1 package com.cjs.example.receive;
 2 
 3 import org.apache.kafka.clients.consumer.ConsumerConfig;
 4 import org.apache.kafka.clients.consumer.ConsumerRecord;
 5 import org.apache.kafka.common.serialization.IntegerDeserializer;
 6 import org.apache.kafka.common.serialization.StringDeserializer;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.context.annotation.Configuration;
 9 import org.springframework.kafka.annotation.KafkaListener;
10 import org.springframework.kafka.annotation.TopicPartition;
11 import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
12 import org.springframework.kafka.config.KafkaListenerContainerFactory;
13 import org.springframework.kafka.core.ConsumerFactory;
14 import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
15 import org.springframework.kafka.listener.AbstractMessageListenerContainer;
16 import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
17 import org.springframework.kafka.listener.config.ContainerProperties;
18 import org.springframework.kafka.support.Acknowledgment;
19 import org.springframework.kafka.support.KafkaHeaders;
20 import org.springframework.messaging.handler.annotation.Header;
21 import org.springframework.messaging.handler.annotation.Payload;
22 
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 
27 @Configuration
28 public class Config2 {
29 
30 @Bean
31 public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Integer, String>> kafkaListenerContainerFactory() {
32 ConcurrentKafkaListenerContainerFactory<Integer, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
33 factory.setConsumerFactory(consumerFactory());
34 factory.setConcurrency(3);
35 ContainerProperties containerProperties = factory.getContainerProperties();
36 containerProperties.setPollTimeout(2000);
37 // containerProperties.setAckMode(AbstractMessageListenerContainer.AckMode.MANUAL_IMMEDIATE);
38 return factory;
39 }
40 
41 private ConsumerFactory<Integer,String> consumerFactory() {
42 return new DefaultKafkaConsumerFactory<>(consumerProps());
43 }
44 
45 private Map<String, Object> consumerProps() {
46 Map<String, Object> props = new HashMap<>();
47 props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.101.5:9092");
48 props.put(ConsumerConfig.GROUP_ID_CONFIG, "hahaha");
49 // props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
50 props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
51 props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
52 return props;
53 }
54 
55 
56 @KafkaListener(topics = "test")
57 public void listen(String data) {
58 System.out.println("listen 收到: " + data);
59 }
60 
61 
62 @KafkaListener(topics = "test", containerFactory = "kafkaListenerContainerFactory")
63 public void listen2(String data, Acknowledgment ack) {
64 System.out.println("listen2 收到: " + data);
65 ack.acknowledge();
66 }
67 
68 @KafkaListener(topicPartitions = {@TopicPartition(topic = "test", partitions = "0")})
69 public void listen3(ConsumerRecord<?, ?> record) {
70 System.out.println("listen3 收到: " + record.value());
71 }
72 
73 
74 @KafkaListener(id = "xyz", topics = "test")
75 public void listen4(@Payload String foo,
76 @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) Integer key,
77 @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition,
78 @Header(KafkaHeaders.RECEIVED_TOPIC) String topic,
79 @Header(KafkaHeaders.OFFSET) List<Long> offsets) {
80 System.out.println("listen4 收到: ");
81 System.out.println(foo);
82 System.out.println(key);
83 System.out.println(partition);
84 System.out.println(topic);
85 System.out.println(offsets);
86 }
87 
88 }

9.1 Committing Offsets

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

如果enable.auto.commit设置为true,那么kafka将自动提交offset。如果设置为false,则支持下列AckMode(确认模式)。

消费者poll()方法将返回一个或多个ConsumerRecords

  • RECORD :处理完记录以后,当监听器返回时,提交offset
  • BATCH :当对poll()返回的所有记录进行处理完以后,提交偏offset
  • TIME :当对poll()返回的所有记录进行处理完以后,只要距离上一次提交已经过了ackTime时间后就提交
  • COUNT :当poll()返回的所有记录都被处理时,只要从上次提交以来收到了ackCount条记录,就可以提交
  • COUNT_TIME :和TIME以及COUNT类似,只要这两个中有一个为true,则提交
  • MANUAL :消息监听器负责调用Acknowledgment.acknowledge()方法,此后和BATCH是一样的
  • MANUAL_IMMEDIATE :当监听器调用Acknowledgment.acknowledge()方法后立即提交

10. Spring Boot Kafka

10.1 application.properties

spring.kafka.bootstrap-servers=192.168.101.5:9092

10.2 发送消息

 1 package com.cjs.example;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.kafka.core.KafkaTemplate;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RestController;
 7 
 8 import javax.annotation.Resource;
 9 
10 @RestController
11 @RequestMapping("/msg")
12 public class MessageController {
13 
14 @Resource
15 private KafkaTemplate<String, String> kafkaTemplate;
16 
17 @RequestMapping("/send")
18 public String send(String topic, String key, String value) {
19 kafkaTemplate.send(topic, key, value);
20 return "ok";
21 }
22 
23 }

10.3 接收消息

 1 package com.cjs.example;
 2 
 3 import org.apache.kafka.clients.consumer.ConsumerRecord;
 4 import org.springframework.kafka.annotation.KafkaListener;
 5 import org.springframework.kafka.annotation.KafkaListeners;
 6 import org.springframework.stereotype.Component;
 7 
 8 @Component
 9 public class MessageListener {
10 
11 /**
12 * 监听订单消息
13 */
14 @KafkaListener(topics = "ORDER", groupId = "OrderGroup")
15 public void listenToOrder(String data) {
16 System.out.println("收到订单消息:" + data);
17 }
18 
19 /**
20 * 监听会员消息
21 */
22 @KafkaListener(topics = "MEMBER", groupId = "MemberGroup")
23 public void listenToMember(ConsumerRecord<String, String> record) {
24 System.out.println("收到会员消息:" + record);
25 }
26 
27 /**
28 * 监听所有消息
29 *
30 * 任意时刻,一条消息只会发给组中的一个消费者
31 *
32 * 消费者组中的成员数量不能超过分区数,这里分区数是1,因此订阅该主题的消费者组成员不能超过1
33 */
34 // @KafkaListeners({@KafkaListener(topics = "ORDER", groupId = "OrderGroup"),
35 // @KafkaListener(topics = "MEMBER", groupId = "MemberGroup")})
36 // public void listenToAll(String data) {
37 // System.out.println("啊啊啊");
38 // }
39 
40 }
11. pom.xml

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.cjs.example</groupId>
 <artifactId>cjs-kafka-example</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>
 <name>cjs-kafka-example</name>
 <description></description>
 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.0.4.RELEASE</version>
 <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 <java.version>1.8</java.version>
 </properties>
 <dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.kafka</groupId>
 <artifactId>spring-kafka</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
 </plugin>
 </plugins>
 </build>
</project>

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

Kafka从入门到精通:全栈开发者的进阶指南 本文是 Kafka 全攻略文章,全面介绍 Kafka 技术。开篇阐述其在大数据与分布式系统中的关键地位;接着从安装搭建入手,讲解环境准备、下载安装及服务启动验证;深入剖析 Topic、Partition 等核心概念,配合 Java 客户端实战及命令行操作;并探讨性能优化、高级特性,涵盖生产者、消费者及集群调优;还涉及运维管理,包括监控、故障排查与数据备份恢复;最后展望 Kafka 发展趋势与挑战,为开发者提供从入门到进阶的全面技术指引。 阅读详情

相关推荐

4D毫米波雷达与激光雷达融合评测:3种主流融合框架在极端天气下的性能对比

本文深度评测了4D毫米波雷达与激光雷达在极端天气下的三大融合框架性能,包括前融合、特征级融合和后融合。通过实测数据对比,揭示了多传感器融合在暴雨、浓雾等恶劣环境中的显著优势,为自动驾驶感知系统提供了关键的技术参考和工程实践指南。

weixin_28677005的博客 331

spring-kafka中ContainerProperties.AckMode详解

本文是一个深入讨论如何通过优化 Kafka 的消费者确认模式来提升 I/O 密集型系统性能的案例研究。首先分享了一个实际的性能问题,通过改变一行代码中的 Kafka 消费者确认模式配置,系统性能提升了几十倍。这引出了文章的主题:Spring-Kafka 中的七种确认模式(包括两种手动确认模式和五种自动确认模式)的详细介绍和比较。作者不仅解释了每种确认模式的工作原理,还提供了关于何时以及如何选择适合的确认模式的实用建议。这篇文章是那些需要处理大量 I/O 操作,特别是使用 Kafka 的开发人员、架构师的

xindoo 1689

【时空数据分析#06】实战:基于Python与ArcGIS的NDVI长期趋势制图与分级

本文详细介绍了基于Python与ArcGIS进行NDVI长期趋势制图与分级分析的完整工作流。通过整合MODIS卫星数据,利用ArcGIS进行空间处理与栅格转换,结合Python进行时序统计与趋势计算,最终生成直观的植被变化趋势分级图,为生态评估与环境监测提供可靠的空间分析工具。

lilh34434的博客 477

Spring Boot中并发批量处理Kafka消息

在项目开发中,kakfa是我们经常使用的消息中间件,用于上下游解耦合,或者对流量“削峰填谷”。 kafka的写性能非常高,但是消息的消费速度依赖于消费者的处理速度。因此,经常会碰到kafka消息队列拥堵的情况。这时,我们不能直接清理整个topic,因为还有别的服务正在使用该topic,只能额外启动一个相同名称的consumer-group来加快消息消费(如果该topic只有一个分区,实际上再启动一个新的消费者,没有作用)。 官方文档在https://docs.spring.io/spring-kafka

WorldMvp的专栏 3353

【逆向实战】Unity游戏资源提取与解密全攻略:从AssetBundle到libil2cpp.so的破解技巧

本文详细介绍了Unity游戏资源提取与解密的完整流程,涵盖从AssetBundle到libil2cpp.so的破解技巧。通过AssetStudio和Il2CppDumper等工具,读者可以学习如何提取未加密资源、处理加密文件,并掌握动态dump技术。文章还提供了自动化脚本编写和常见问题解决方案,帮助逆向工程爱好者高效完成资源提取任务。

weixin_29012765的博客 1048

SAP S4业务伙伴(BP)实战指南:从角色分配到数据同步的完整流程

本文详细解析了SAP S4业务伙伴(BP)功能,从基础概念到实战操作,涵盖角色分配、数据同步及常见问题排查。通过BP机制,企业可高效管理客户、供应商等多重身份,实现数据共享和动态切换,显著提升主数据管理效率。特别适合SAP实施顾问和ERP管理员参考。

y2z3a4b5c的博客 870

Spring-Kafka系列(3)—— SpringKafka消费者监听MessageListener

之前已经介绍了通过和工具来消费数据。下面介绍SpringKafka消费数据的方式——kafka消息监听器。Kafka的消息监听一般可以分为:1.单条数据监听;2.批量数据监听。是的消息监听器接口,也是一个函数式接口,利用接口的方法可以实现消费数据。 基于此接口可以实现单条数据消息监听器接口、多条数据消息监听器接口、带ACK机制的消息监听器和MessageListenerGenericMessageListener单条数据监听器BatchMessageListener批量数据监听器AckowledgingMe

SpringBoy的博客 7338

从零搭建一个虚拟ECU:手把手用Autosar CP模块模拟汽车灯控系统(基于Vector工具链)

本文详细介绍了如何使用Vector工具链从零搭建一个基于Autosar CP架构的虚拟ECU系统,模拟汽车灯光控制功能。通过环境搭建、模块配置、通信栈设置到灯光控制逻辑实现的全流程指导,帮助开发者掌握Autosar CP模块术语的实际应用,并提供了系统集成与测试的实用方案。

weixin_42628688的博客 312

Kafka入门及进阶

目录第1章 Kafka入门 1. 简介 1.1 消息队列简介 1.2 Kafka简介 1.3 Kafka的优势 1.4 哪些公司在使用Kafka 1.5 Kafka生态圈介绍 1.6 Kafka版本 2. 环境搭建 2.1 搭建Kafka集群 2.2 目录结构分析 2.3 ...

码灵的博客 701

无需Python环境!纯C#上位机+OpenCVSharp4+ONNX Runtime实现YOLOv8摄像头实时流检测,工业级稳定

摘要 工业自动化C#开发中,传统Python方案实现视觉检测功能存在环境依赖、内存泄漏和性能不稳定等问题。本文提出基于.NET 8+OpenCVSharp4+ONNX Runtime的纯C#方案,通过实际案例验证其优势: 零Python依赖,支持离线部署 内存稳定(380MB/72h),检测延迟<80ms 检测精度达漏检率<0.1%,误检率<0.5% 保留原有业务逻辑代码,3天完成适配 方案采用分层架构设计,支持多种硬件平台和操作系统,提供从模型导出到部署的全流程指导,为工业视觉检测提供高

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 196

12S BMS 核心设计:基于 STM32H743+BQ34Z100 的 SOC/SOH 实现与全链路技术解析(上)

本文详细介绍了基于STM32H743和BQ34Z100的12串锂电池管理系统(BMS)设计。该系统采用主控制器+专用电量监测计架构,可实现高精度SOC(±1%)和SOH(±2%)估算,支持36V-50.4V电压范围。硬件设计包括电压/电流采样、温度测量、保护电路等模块,软件实现基于HAL库开发,采用DMA方式提高I2C通信效率。系统通过TI专利的ImpedanceTrack™算法实现三维融合估算,并具备完善的保护功能。该设计适用于电动工具、轻型电动车等中功率设备,具有精度高、响应快。

bother3000的博客 1393

Kafka入门到进阶

概念 Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理

chenyl 838

Higress 入门:初探阿里云原生 AI 网关

Higress 是一款由阿里巴巴推出的云原生 API 网关,其内核基于 Istio 和 Envoy。与传统 API 网关不同,它深度聚焦于 AI 场景,支持国内外众多主流模型供应商,如 OpenAI、百度文心一言等,还兼容基于 vllm/ollama 等自建的 DeepSeek 模型,能够满足不同类型企业对 AI 能力集成与管理的需求。Higress 作为一款功能强大的云原生 API 网关,在 AI 时代展现出独特的优势。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 1866

Kafka入门和进阶

什么是Kafka Kafka 是一个分布式的基于 发布/订阅模式 的流式平台,主要应用于大数据实时处理领域。 它有三个关键能力: 1.订阅发布记录流,它类似于企业中的消息队列 或 企业消息传递系统 2.以容错的方式存储记录流 3.实时记录流 Kafka 的应用 作为消息系统 作为存储系统 作为流处理器 Kafka 可以建立流数据管道,可靠性的在系统或应用之间获取数据。 建立流式应用传输和响应数据。 Kafka 作为消息系统 Kafka 作为消息系统,它有三个基本组件 Producer : 发

BWone的博客 656

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Kafka进阶指南:从入门到精通,深入解析Kafka技术细节

在当前的科技浪潮中,Kafka已然成为众多互联网巨头的心头好,其在业务领域的应用也愈发广泛。我们不一定需要精通它,但至少要掌握如何使用。这样,在工作中不断提升自己的能力,才能有足够的底气与老板或人力资源部门讨论薪资增长。否则,如果只是埋头苦干,996不停歇,而业务能力并未得到提升,那么终将被公司淘汰。你扪心自问,你真的配得上更高的薪水吗?最后,我想说的是,学习并非难事,关键在于持之以恒。尤其在步入职场后,继续学习更是难能可贵。对程序员来说,学习是立业之本,放弃学习就意味着被市场淘汰。

Reische的博客 1160

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

消息队列之Kafka入门到进阶

1 Kafka概述 1.1 消息队列 (1)点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除) 点对点模型通常是一个基于拉取或者轮询的消息传送模型,这种模型从队列中请求信息,而不是将消息推送到客户端。这个模型的特点是发送到队列的消息被一个且只有一个接收者接收处理,即使有多个消息监听者也是如此。 (2)发布/订阅模式(一对多,数据生产后,推送给所有订阅者) 发布订阅模型则是一个基于推送的消息传送模型。发布订阅模型可以有多种不同的订阅者,临时订阅者只在主动监听主题时才接收消息,而持久..

luostudent的博客 562

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

kafka目录导读(入门到进阶)

一、部署 1.1、安装部署 二、概念及理论 2.1、 2.2、kafka文件存储 三、整合 3.1、kafka+flume 3.2、flume+kafka+storm flume之kafkaSink strom之KafkaSpout 测试 问题

chbxw 756

【消息中间件】Kafka从入门到精通

本章作为Kafka软件的入门章节,介绍了一些消息传输系统中的基本概念以及单机版Windows系统中Kafka软件的基本操作。如果仅从操作上,感觉Kafka和数据库的功能还是有点像的。比如:数据库可以创建表保存数据,kafka可以创建主题保存消息。Java客户端程序可以通过JDBC访问数据库:保存数据、修改数据、查询数据,kafka可以通过生产者客户端生产数据,通过消费者客户端消费数据。

本博客旨在记录软件开发中的点滴进步,特别是围绕Java后端开发领域的深度学习与实践总结。在这里,你可以找到关于Spring全家桶、并发编程、微服务架构以及数据库优化等方面的原创文章。欢迎在博客下方留言与我交流,期待与志同道合的你一起探讨技术 3577

Kafka 实战 - 通俗易懂 !Kafka 开发快速入门看这篇就够了

Kafka是一个分布式、高吞吐量、低延迟的流处理平台,最初由LinkedIn开发,后捐赠给Apache基金会并成为顶级项目。它主要用于构建实时数据管道和流应用,支持发布-订阅模型的消息传递,常用于日志收集、消息系统、用户行为追踪、流式处理等场景。通过以上步骤和示例,您可以快速上手Kafka开发,从环境搭建到编写简单的生产者和消费者程序。为了帮助您快速入门Kafka开发,我们将以通俗易懂的方式逐步介绍关键概念、环境搭建、基本操作以及编程实践。在Java项目中引入Kafka客户端库(如。

qq_33240556的博客 830

【Kafka系列·入门第五篇】Kafka实操进阶:Topic/Partition管理 + 消息可靠性配置

本文是Kafka实操进阶指南,重点讲解Topic/Partition管理、消息可靠性配置和常见故障排查。首先需确保Kafka环境正常运行。主要内容包括:1) Topic管理操作(查询、修改分区、删除等);2) 消息可靠性配置(ACK机制、副本策略、持久化);3) 常见问题排查方法。文章提供Windows/Linux双环境命令和Java代码示例,帮助开发者掌握Kafka核心功能,解决实际开发中的可靠性问题。

qq_29757467的博客 430

【Kafka系列·入门第八篇】Kafka生产监控与运维进阶:Prometheus+Grafana可视化+消息追踪

本文详细介绍了在3节点Kafka生产集群中搭建Prometheus+Grafana监控体系的完整方案。通过部署Kafka Exporter采集核心指标,配置Prometheus进行数据存储和告警,再结合Grafana实现可视化展示。文章提供了从环境准备、组件安装到配置优化的全流程指导,包括Kafka Exporter在3节点上的部署步骤、Prometheus的数据采集配置以及Grafana面板的导入方法。该方案支持实时监控集群负载、消息积压等关键指标,实现生产环境下的智能运维和快速故障排查。所有步骤均经过生

qq_29757467的博客 524
上一篇: Spring Cloud中异常处理的套路
下一篇: Elasticsearch 快速开始
javaQQ群 866865133
博客等级 码龄8年 59粉丝 309原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值