【发布时间】:2017-10-13 19:46:58
【问题描述】:
我正在深入研究 Apache Kafka 和 Spring Cloud Stream 并观察到一些行为让我怀疑我做错了什么或者它是否按预期工作 - 我几乎怀疑:
出错时可能会丢失消息!?
我的设置尽可能简单。一个 Kafka 代理和一个只有 1 个分区的主题。具有默认设置的代理、主题、生产者和消费者(自动确认为 true)。
测试用例 1
- 产生
message1 - 产生
message2 - 启动一个消费者,它会在接收到任何消息时抛出 RuntimeException
- 消费
message1,重试 - 消费
message1,重试 - 消费
message1,重试 - 抛出异常
- 消费
message2,重试 - 消费
message2,重试 - 消费
message2,重试 - 抛出异常
- 停止并重新启动消费者
- 消费
message1,重试 - 消费
message1,重试 - 消费
message1,重试 - 抛出异常
- 消费
message2,重试 - 消费
message2,重试 - 消费
message2,重试 - 抛出异常
按预期工作。
测试用例 2
- 产生
message1 - 产生
message2 - 启动一个消费者,它会在接收到完全是
message1时抛出一个RuntimeException - 消费
message1,重试 - 消费
message1,重试 - 消费
message1,重试 - 抛出异常
- 成功消费
message2 - 产生
message3 - 成功消费
message3 - 停止并重新启动消费者
- 什么都没有发生,消费者等待新消息消费
message1 将被跳过,因为提交的偏移量已设置为message3。这就是困扰我的地方。只要之前的消息未成功处理,我不希望消费者继续处理消息。
有没有人遇到过同样的行为和/或可能可以指导我如何改变这种情况?
提前致谢!
更新:应要求,一些代码sn-ps
创建主题
kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test-topic
连接生产者
kafka-console-producer.sh --broker-list localhost:9092 --topic test-topic
创建一个maven项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/>
</parent>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
</dependencies>
添加以下application.yml
spring:
cloud:
stream:
bindings:
input:
destination: test-topic
contentType: text/plain
group: test-group
consumer:
header-mode: raw
kafka:
binder:
zkNodes: localhost:2181
brokers: localhost:9092
添加以下Application.java
@SpringBootApplication
@EnableBinding(Sink.class)
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@StreamListener(Sink.INPUT)
private void consume(Message<String> message) {
log.info("Received: {}", message.getPayload());
if ("message1".equals(message.getPayload())
throw new RuntimeException();
log.info("Successfully processed message {}", message.getPayload());
}
}
应该是这样的。运行应用程序并使用控制台生产者生成消息。
【问题讨论】:
-
如果只有一个分区,为什么消费者在testcase2中消费message1失败,却消费message2?
-
@herokingsley 我不知道,但这就是正在发生的事情。如果在尝试使用
message1失败后它不会消耗message2,那么我会很满意。 -
也许向我们展示一些代码或日志会有所帮助
-
@herokingsley 我在我的问题中添加了一些代码 sn-ps。
-
testcase1 的代码是什么样的?
标签: java apache-kafka spring-cloud-stream