SpringBoot整合Kafka

202 阅读4分钟

先谈Kafka

为了方便通过kafka和zookeeper都通过docker来安装

1. 由于目前Kafka依赖zookeeper所以先安装zookeeper

  1. 拉取镜像

    docker pull zookeeper:latest

  2. 启动zookeeper,端口映射和文件挂载

    docker run -d --name zookeeper -p 2181:2181 -v /etc/localtime:/etc/localtime wurstmeister/zookeeper

2.搭建Kafka

  1. 拉取镜像

    docker pull wurstmeister/kafka

  2. 启动Kafka

    docker run -d --name kafka -p 9092:9092 -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=10.9.44.11:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://10.9.44.11:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -t wurstmeister/

  3. 参数说明

    -e KAFKA_BROKER_ID=0 在kafka集群中,每个kafka都有一个BROKER_ID来区分自己

    -e KAFKA_ZOOKEEPER_CONNECT=10.9.44.11:2181/kafka 配置zookeeper管理kafka的路径10.9.44.11:2181/kafka

    -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://10.9.44.11:9092 把kafka的地址端口注册给zookeeper

    -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 配置kafka的监听端口

    -v /etc/localtime:/etc/localtime 容器时间同步虚拟机的时间

再谈springboot

springboot跟kafka的关系就像与redis,mysql一样,可借助的外部力量。

  1. 引入kafka的依赖来连接kafka
<dependency>
   <groupId>org.springframework.kafka</groupId>
   <artifactId>spring-kafka</artifactId>
   <version>2.8.4</version>
</dependency>
  1. 通过application.yml来连接Kafka
spring:
  application:
    name: kafka-demo
  kafka:
    #kafka的地址  
    bootstrap-servers: 192.168.234.129:19092
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    consumer:
      group-id: test
      enable-auto-commit: true
      auto-commit-interval: 1000
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
  1. 向Kafka推送消息
//注入kafka模板
@Autowired
private KafkaTemplate kafkaTemplate;

//向kafka推送消息
public void send(){
    String msg = "hello kafka";
    kafkaTemplate.send("test_topic",msg);
}
  1. 通过注解消费Kafka消息
@Component
public class TestConsumer {
    //监听的主题名
    @KafkaListener(topics = "test_topic")
    public void listen (ConsumerRecord<?, ?> record) throws Exception {
        System.out.printf("coupon  topic = %s, offset = %d, value = %s \n", record.topic(), record.offset(), record.value());
    }
}
  1. 编程式使用kafka
@Test
void testPoll(){
    //手动创建配置文件
    Properties props = new Properties();
    props.put("bootstrap.servers", "192.168.234.129:19092");
    props.put("group.id", "test");

    //如果value合法,则自动提交偏移量
    props.put("enable.auto.commit", "true");

    //设置多久一次更新被消费消息的偏移量
    props.put("auto.commit.interval.ms", "1000");

    //设置会话响应的时间,超过这个时间kafka可以选择放弃消费或者消费下一条消息
    props.put("session.timeout.ms", "30000");

    props.put("key.deserializer",
            "org.apache.kafka.common.serialization.StringDeserializer");
    props.put("value.deserializer",
            "org.apache.kafka.common.serialization.StringDeserializer");
    KafkaConsumer consumer = new KafkaConsumer<String, String>(props);
    //配置发送的主题
    List<String> topics = Arrays.asList("test_topic","test_topic2");
    consumer.subscribe(topics);

    while (true){
        //拉取kafka的消息,此方式相较于注解可以获取多个主题的消息
        ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
        if(!records.isEmpty()){
            for(ConsumerRecord<String,String> record : records){
                //获取消费的值、偏移量、主题名
                System.out.println("membert value:"+record.value()+" "+"offset:"+record.offset()+" "+record.topic());
            }
        }
    }
}

再谈Kafka

kafka的整体架构

kafka2.jpg

Producer:Producer即生产者,消息的产生者,是消息的入口。

kafka cluster

Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……

Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。

Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!

Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。

Message:每一条发送的消息主体。

Consumer:消费者,即消息的消费方,是消息的出口。

Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!

Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。

主题分区与消费组

  1. 以上步骤,已经初步体验了通过kakfa进行了发收消息
  2. 下面介绍一下kafka的特性

kafka.jpg

  1. 上图(借图,如有侵犯望告知撤掉),描述了Kafka的P(分区)与C(消费者)之间发送消息的方式。

    • 可以看出每个分区只会向一组里面一个消费者发送消息
  2. 总之:

  • 如果所有的消费者都隶属于同一个消费组,那么所有的消息都会被均衡地投递给每一个消费者,即每条消息只会被一个消费者处理,这就相当于点对点模式的应用。

  • 如果所有的消费者都隶属于不同的消费组,那么所有的消息都会被广播给所有的消费者,即每条消息会被所有的消费者处理,这就相当于发布/订阅模式的应用。