Kafka, RabbitMQ and Pulsar measured side by side on ordering, replay and consumer scaling by driving the three client libraries directly, plus an operational-footprint measurement of each broker's own distribution. Nine tests, three brokers started without Docker, and every number in the documentation regenerated by scripts/run-all.sh.
2.8 KiB
prev: Operational footprint · README · next: The decision table
6. What Spring adds, and what Boot 4 no longer gives you for free
The measurements in this module drive the client libraries directly, so that what is being compared is the brokers rather than three sets of Spring defaults. In an application you would use the Spring integrations, and they are not equivalent to one another.
| Kafka | RabbitMQ | Pulsar | |
|---|---|---|---|
| project | Spring for Apache Kafka 4.1.1 | Spring AMQP 4.1.1 | Spring for Apache Pulsar 2.0.7 |
| starter | spring-boot-starter-kafka |
spring-boot-starter-amqp |
spring-boot-starter-pulsar |
| listener | @KafkaListener |
@RabbitListener |
@PulsarListener |
| template | KafkaTemplate |
RabbitTemplate |
PulsarTemplate |
| retry / DLQ | DefaultErrorHandler, @RetryableTopic |
dead-letter exchange, container error handler | DeadLetterPolicy on the listener |
All three are Boot-managed at 4.1.1, so you do not pin their versions.
The Boot 4 trap that applies to all three
In Spring Boot 4, depending on a messaging library directly rather than through its Boot starter
means you have no auto-configuration. The auto-configuration classes moved out of
spring-boot-autoconfigure into per-technology modules that only the starters bring:
| depending on | what you lose | how it presents |
|---|---|---|
org.springframework.kafka:spring-kafka |
spring-boot-kafka |
No qualifying bean of type KafkaTemplate<...> — the context starts fine |
org.springframework.amqp:spring-rabbit |
spring-boot-amqp |
no RabbitTemplate, no RabbitAdmin |
org.springframework.pulsar:spring-pulsar |
spring-boot-pulsar |
no PulsarTemplate |
Every Boot 3 tutorial gets this wrong now, and the symptom is a missing bean rather than anything that names the cause. Use the starters.
The Jackson fork, in both Kafka and RabbitMQ
Boot 4 moved to Jackson 3 (tools.jackson), and both messaging projects ship converters for
both generations. A 2 in the class name means the previous Jackson — which is the opposite
of the convention you would guess:
- Spring Kafka:
JsonSerializer/JsonDeserializerare Jackson 2;JacksonJsonSerializer,JacksonJsonDeserializerandJacksonJsonSerdeare Jackson 3. - Spring AMQP:
Jackson2JsonMessageConverteris Jackson 2;JacksonJsonMessageConverteris Jackson 3.
Picking the wrong one gives you SerializationException: Can't serialize data, whose cause is
Java 8 date/time type java.time.Instant not supported by default — a message about date types
for what is really a wrong-library problem.
The kafka-basics and rabbitmq modules in this repository cover both stacks in detail.
next: The decision table