kafka的替代品redpanda部署与SpringBoot集成使用案例

一、Kafka与Redpanda对比分析

1.1 核心差异

特性 Apache Kafka Redpanda
架构 JVM-based,需要ZooKeeper C++编写,无外部依赖
性能 高吞吐量,相对较高延迟 更高吞吐量,更低延迟
资源占用 较高(JVM开销) 更低(原生编译)
部署复杂度 需要ZooKeeper协调 单二进制文件,简化部署
兼容性 原生Kafka协议 完全兼容Kafka协议
运维 成熟工具链 简化运维,内置监控

1.2 适用场景

选择Kafka的情况:

  • 已有Kafka技术栈和运维经验
  • 需要成熟的生态系统和工具链
  • 大规模企业级部署

选择Redpanda的情况:

  • 追求更高性能和更低延迟
  • 希望简化部署和运维
  • 资源受限环境
  • 快速原型开发

二、Redpanda部署配置

yaml 复制代码
version: '3.3'

services:
  redpanda-0:
    command:
      - redpanda
      - start
      - --kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092
      - --advertise-kafka-addr internal://redpanda-0:9092,external://192.168.8.108:19092
      - --pandaproxy-addr internal://0.0.0.0:8082,external://0.0.0.0:18082
      - --advertise-pandaproxy-addr internal://redpanda-0:8082,external://localhost:18082
      - --schema-registry-addr internal://0.0.0.0:8081,external://0.0.0.0:18081
      - --rpc-addr redpanda-0:33145
      - --advertise-rpc-addr redpanda-0:33145
      - --mode dev-container
      - --smp 1
      - --default-log-level=info
    image: redpandadata/redpanda:v25.3.1
    container_name: redpanda-0
    volumes:
      - redpanda-0:/var/lib/redpanda/data
    networks:
      - redpanda_network
    ports:
      - 18081:18081
      - 18082:18082
      - 19092:19092
      - 19644:9644

  console:
    container_name: redpanda-console
    image: redpandadata/console:v3.3.1
    networks:
      - redpanda_network
    entrypoint: /bin/sh
    command: -c 'echo "$$CONSOLE_CONFIG_FILE" > /tmp/config.yml; /app/console'
    environment:
      CONFIG_FILEPATH: /tmp/config.yml
      CONSOLE_CONFIG_FILE: |
        kafka:
          brokers: ["redpanda-0:9092"]
        schemaRegistry:
          enabled: true
          urls: ["http://redpanda-0:8081"]
        redpanda:
          adminApi:
            enabled: true
            urls: ["http://redpanda-0:9644"]
    ports:
      - 8080:8080
    depends_on:
      - redpanda-0

networks:
  redpanda_network:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.101.0.0/16

volumes:
  redpanda-0:

2.2 启动命令

bash 复制代码
# 启动服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f redpanda

# 停止服务
docker-compose down

三、Spring Boot 3集成案例

3.1 项目结构

bash 复制代码
src/
├── main/
│   ├── java/
│   │   └── com/example/redpandademo/
│   │       ├── RedpandaDemoApplication.java
│   │       ├── config/
│   │       │   └── KafkaConfig.java
│   │       ├── controller/
│   │       │   └── DemoController.java
│   │       ├── service/
│   │       │   ├── KafkaProducerService.java
│   │       │   └── KafkaConsumerService.java
│   │       └── events/
│   │           └── UserEvent.java
│   └── resources/
│       └── application.yml
└── test/
    └── java/
        └── com/example/redpandademo/
            └── RedpandaDemoApplicationTests.java

3.2 Maven依赖配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>redpanda-demo</artifactId>
    <version>1.0.0</version>
    
    <properties>
        <java.version>17</java.version>
        <confluent.version>7.5.1</confluent.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>io.confluent</groupId>
            <artifactId>kafka-avro-serializer</artifactId>
            <version>${confluent.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>kafka</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3.3 应用配置

application.yml

yaml 复制代码
spring:
  application:
    name: redpanda-demo
  kafka:
    bootstrap-servers: localhost:19092
    properties:
      schema.registry.url: http://localhost:18081
    
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
      acks: all
      properties:
        retries: 3
        linger.ms: 10
        batch.size: 16384
    
    consumer:
      group-id: redpanda-demo-group
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring.json.trusted.packages: "com.example.redpandademo.events"

server:
  port: 8080

logging:
  level:
    com.example.redpandademo: DEBUG
    org.apache.kafka: WARN

3.4 配置类

KafkaConfig.java

kotlin 复制代码
package com.example.redpandademo.config;

import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.TopicBuilder;

@Configuration
public class KafkaConfig {
    
    @Bean
    public NewTopic userEventsTopic() {
        return TopicBuilder.name("user-events")
                .partitions(3)
                .replicas(1)
                .build();
    }
    
    @Bean
    public NewTopic orderEventsTopic() {
        return TopicBuilder.name("order-events")
                .partitions(5)
                .replicas(1)
                .build();
    }
}

3.5 消息实体类

UserEvent.java

typescript 复制代码
package com.example.redpandademo.events;

import java.time.LocalDateTime;

public class UserEvent {
    private String userId;
    private String eventType;
    private String email;
    private LocalDateTime timestamp;
    
    public UserEvent() {}
    
    public UserEvent(String userId, String eventType, String email) {
        this.userId = userId;
        this.eventType = eventType;
        this.email = email;
        this.timestamp = LocalDateTime.now();
    }
    
    // Getter和Setter方法
    public String getUserId() { return userId; }
    public void setUserId(String userId) { this.userId = userId; }
    
    public String getEventType() { return eventType; }
    public void setEventType(String eventType) { this.eventType = eventType; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public LocalDateTime getTimestamp() { return timestamp; }
    public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
    
    @Override
    public String toString() {
        return String.format("UserEvent{userId='%s', eventType='%s', email='%s', timestamp=%s}",
                userId, eventType, email, timestamp);
    }
}

3.6 消息生产者服务

KafkaProducerService.java

typescript 复制代码
package com.example.redpandademo.service;

import com.example.redpandademo.events.UserEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
public class KafkaProducerService {
    
    private static final Logger log = LoggerFactory.getLogger(KafkaProducerService.class);
    
    private final KafkaTemplate<String, Object> kafkaTemplate;
    
    public KafkaProducerService(KafkaTemplate<String, Object> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }
    
    public void sendUserEvent(String topic, UserEvent userEvent) {
        CompletableFuture<SendResult<String, Object>> future = 
            kafkaTemplate.send(topic, userEvent.getUserId(), userEvent);
        
        future.whenComplete((result, ex) -> {
            if (ex == null) {
                log.info("消息发送成功: topic={}, key={}, partition={}, offset={}",
                        topic, userEvent.getUserId(), 
                        result.getRecordMetadata().partition(),
                        result.getRecordMetadata().offset());
            } else {
                log.error("消息发送失败: topic={}, key={}, error={}",
                        topic, userEvent.getUserId(), ex.getMessage());
            }
        });
    }
    
    public void sendWithCallback(String topic, String key, String message) {
        CompletableFuture<SendResult<String, Object>> future = 
            kafkaTemplate.send(topic, key, message);
        
        future.whenComplete((result, ex) -> {
            if (ex == null) {
                log.info("简单消息发送成功: topic={}, key={}, message={}",
                        topic, key, message);
            } else {
                log.error("简单消息发送失败: topic={}, key={}", topic, key, ex);
            }
        });
    }
}

3.7 消息消费者服务

KafkaConsumerService.java

typescript 复制代码
package com.example.redpandademo.service;

import com.example.redpandademo.events.UserEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;

@Service
public class KafkaConsumerService {
    
    private static final Logger log = LoggerFactory.getLogger(KafkaConsumerService.class);
    
    @KafkaListener(topics = "user-events", groupId = "user-group")
    public void consumeUserEvent(@Payload UserEvent userEvent,
                                @Header(KafkaHeaders.RECEIVED_KEY) String key,
                                @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
                                @Header(KafkaHeaders.OFFSET) long offset) {
        log.info("收到用户事件: key={}, partition={}, offset={}, event={}",
                key, partition, offset, userEvent);
        
        processUserEvent(userEvent);
    }
    
    @KafkaListener(topics = "order-events", groupId = "order-group")
    public void consumeOrderEvent(String message) {
        log.info("收到订单事件: {}", message);
        processOrderEvent(message);
    }
    
    private void processUserEvent(UserEvent userEvent) {
        log.info("处理用户事件: {}", userEvent.getEventType());
        
        switch (userEvent.getEventType()) {
            case "REGISTER":
                log.info("新用户注册: {}", userEvent.getEmail());
                break;
            case "LOGIN":
                log.info("用户登录: {}", userEvent.getEmail());
                break;
            default:
                log.info("未知用户事件类型: {}", userEvent.getEventType());
        }
    }
    
    private void processOrderEvent(String message) {
        log.info("处理订单事件: {}", message);
    }
}

3.8 REST控制器

DemoController.java

less 复制代码
package com.example.redpandademo.controller;

import com.example.redpandademo.events.UserEvent;
import com.example.redpandademo.service.KafkaProducerService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/kafka")
public class DemoController {
    
    private final KafkaProducerService kafkaProducerService;
    
    public DemoController(KafkaProducerService kafkaProducerService) {
        this.kafkaProducerService = kafkaProducerService;
    }
    
    @PostMapping("/user-event")
    public String sendUserEvent(@RequestParam String userId,
                               @RequestParam String eventType,
                               @RequestParam String email) {
        UserEvent userEvent = new UserEvent(userId, eventType, email);
        kafkaProducerService.sendUserEvent("user-events", userEvent);
        return "用户事件发送成功";
    }
    
    @PostMapping("/message")
    public String sendMessage(@RequestParam String topic,
                             @RequestParam String key,
                             @RequestParam String message) {
        kafkaProducerService.sendWithCallback(topic, key, message);
        return "消息发送成功";
    }
    
    @GetMapping("/health")
    public String health() {
        return "Spring Boot 3 + Redpanda 服务运行正常";
    }
}

3.9 主应用类

RedpandaDemoApplication.java

typescript 复制代码
package com.example.redpandademo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RedpandaDemoApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(RedpandaDemoApplication.class, args);
    }
}
相关推荐
q***09802 小时前
Spring Boot 2.7.x 至 2.7.18 及更旧的版本,漏洞说明
java·spring boot·后端
程序员爱钓鱼2 小时前
Python 编程实战 · 进阶与职业发展:数据分析与 AI(Pandas、NumPy、Scikit-learn)
后端·python·trae
程序员爱钓鱼2 小时前
Python 编程实战 · 进阶与职业发展:Web 全栈(Django / FastAPI)
后端·python·trae
q***56382 小时前
Spring Boot 中 RabbitMQ 的使用
spring boot·rabbitmq·java-rabbitmq
IT_陈寒3 小时前
90%的Python开发者不知道:这5个内置函数让你的代码效率提升300%
前端·人工智能·后端
c***93773 小时前
springboot使用logback自定义日志
java·spring boot·logback
i***66503 小时前
SpringBoot中整合RabbitMQ(测试+部署上线 最完整)
spring boot·rabbitmq·java-rabbitmq
我的虾分发3 小时前
虾分发平台提供多种价格套餐
后端