Spring Kafka,使用嵌入式Kafka进行测试

Spring Kafka,使用嵌入式Kafka进行测试,spring,spring-boot,apache-kafka,spring-kafka,Spring,Spring Boot,Apache Kafka,Spring Kafka,我们通过Servicetest和嵌入式卡夫卡观察到一种奇怪的行为 该测试是一个Spock测试,我们使用JUnit规则KafkameBedded并传播BrokerSassString,如下所示: @ClassRule @Shared KafkaEmbedded embeddedKafka = new KafkaEmbedded(1) @Autowired KafkaListenerEndpointRegistry endpointRegistry def setupSpec() { S

我们通过Servicetest和嵌入式卡夫卡观察到一种奇怪的行为

该测试是一个Spock测试,我们使用JUnit规则KafkameBedded并传播BrokerSassString,如下所示:

@ClassRule
@Shared
KafkaEmbedded embeddedKafka = new KafkaEmbedded(1)

@Autowired
KafkaListenerEndpointRegistry endpointRegistry

def setupSpec() {
    System.setProperty("kafka.bootstrapServers",  embeddedKafka.getBrokersAsString())
}
通过检查KafkameBedded的代码,使用KafkameBedded(int count)构造一个实例将导致一个Kafka服务器,每个主题有两个分区

为了解决测试中的分区分配和服务器客户端同步问题,我们遵循SpringKafka的ContainerTestUtils类中的策略

public static void waitForAssignment(KafkaMessageListenerContainer<String, String> container, int partitions)
        throws Exception {

        log.info(
            "Waiting for " + container.getContainerProperties().getTopics() + " to connect to " + partitions + " " +
                "partitions.")

        int n = 0;
        int count = 0;
        while (n++ < 600 && count < partitions) {
            count = 0;
            container.getAssignedPartitions().each {
                TopicPartition it ->
                    log.info(it.topic() + ":" + it.partition() + "; ")
            }

            if (container.getAssignedPartitions() != null) {
                count = container.getAssignedPartitions().size();
            }
            if (count < partitions) {
                Thread.sleep(100);
            }
        }
     }
请注意[…]指示省略的行

我们将
metadata.max.age.ms
设置为3000毫秒 因此,它尝试频繁刷新元数据信息

现在让我们困惑的是,如果我们等待两个分区连接,等待就会超时。只有当我们等待一个分区连接时,经过一段时间后,一切都会成功运行


我们是否理解错了代码,在嵌入式Kafka中每个主题有两个分区?只有一个被分配给我们的听众是正常的吗?

我无法解释你所看到的片状;是的,默认情况下每个主题有2个分区。我刚刚运行了一个框架容器测试,看到了这个

09:24:06.139 INFO  [testSlow3-kafka-consumer-1][org.springframework.kafka.listener.KafkaMessageListenerContainer] partitions revoked:[]
09:24:06.611 INFO  [testSlow3-kafka-consumer-1][org.springframework.kafka.listener.KafkaMessageListenerContainer] partitions assigned:[testTopic3-1, testTopic3-0]

我无法解释你看到的片状;是的,默认情况下每个主题有2个分区。我刚刚运行了一个框架容器测试,看到了这个

09:24:06.139 INFO  [testSlow3-kafka-consumer-1][org.springframework.kafka.listener.KafkaMessageListenerContainer] partitions revoked:[]
09:24:06.611 INFO  [testSlow3-kafka-consumer-1][org.springframework.kafka.listener.KafkaMessageListenerContainer] partitions assigned:[testTopic3-1, testTopic3-0]

对于测试,重要的是设置
spring.kafka.consumer.auto offset reset=earlime
,以避免竞争条件(消费者对生产者的顺序或时间),请参阅

从版本2.5开始,ConsumerOps方法将ConsumerConfig.AUTO\u OFFSET\u RESET\u CONFIG设置为最早。这是因为,在大多数情况下,您希望使用者使用在测试用例中发送的任何消息。ConsumerConfig默认值是最新的,这意味着在使用者开始之前,测试已经发送的消息将不会收到这些记录。要恢复到以前的行为,请在调用方法后将属性设置为latest


对于测试,重要的是设置
spring.kafka.consumer.auto offset reset=earlime
,以避免竞争条件(消费者对生产者的顺序或时间),请参阅

从版本2.5开始,ConsumerOps方法将ConsumerConfig.AUTO\u OFFSET\u RESET\u CONFIG设置为最早。这是因为,在大多数情况下,您希望使用者使用在测试用例中发送的任何消息。ConsumerConfig默认值是最新的,这意味着在使用者开始之前,测试已经发送的消息将不会收到这些记录。要恢复到以前的行为,请在调用方法后将属性设置为latest


我们最初看到的不稳定是关于时间安排和将话题分配给消费者。基本上是()所解决的问题。关于我发现的分区,是什么让我困惑。预先创建主题时,在before()方法中使用构造函数中配置的分区数。当隐式创建主题时,分区数的默认值似乎是1。对我来说,这是同一个问题。当@EmbeddedKafka注释中未声明主题时,将仅自动创建一个分区,该分区由代理属性
num.partitions
控制,默认为1。在最近的SpringKafka测试版本中,您可以在嵌入式代理上设置属性。我们最初看到的不稳定之处是关于时间和向消费者分配主题。基本上是()所解决的问题。关于我发现的分区,是什么让我困惑。预先创建主题时,在before()方法中使用构造函数中配置的分区数。当隐式创建主题时,分区数的默认值似乎是1。对我来说,这是同一个问题。当@EmbeddedKafka注释中未声明主题时,将仅自动创建一个分区,该分区由代理属性
num.partitions
控制,默认为1。在最近的spring kafka测试版本中,您可以在嵌入式代理上设置属性。当我们有多个消费者加入到测试中的同一组中时,当发生再平衡时,测试将失败(但不总是在10%左右),这似乎与这里的日志一致。我注意到使用spring嵌入式kafka库时出现了类似的问题。当我们有多个消费者加入到测试中的同一组中时,当发生再平衡时,测试将失败(但不总是在10%左右),这似乎与这里的日志一致。