Windows中的Kafka集群配置和Spring Cloud Stream操作kafka

 

操作环境

  Zk没有使用集群,只是一台单节点的机器,ip为192.168.1.74

  两台kafka的服务,ip为192.168.1.75,192.168.1.76

  服务器的操作系统都是windows的

  spring cloud stream kafka的版本号为2.2.1.RELEASE ,spring boot 版本号为2.1.8

1.配置kafka

 

配置项

192.168.1.75

192.168.1.76

备注

host.name

192.168.1.75

192.168.1.76

Kafka服务主机名称

broker.id

0

1

默认为0,kafka集群配置必须为每一个kafka服务设置id为唯一值

listeners

PLAINTEXT://192.168.1.75:9092

PLAINTEXT://192.168.1.76:9092

 

advertised.listeners

PLAINTEXT://192.168.1.75:9092

PLAINTEXT://192.168.1.76:9092

 

num.patitions

2

2

分区数,默认为1。这里有两个kafka服务器,所以设置为了2

zookeeper.connect

zk1:2181/kafka

zk1:2181/kafka

zk1是在hosts文件中自定义的域名,如果直接使用ip的话,可能连不上zk

 

 2.异常情况

一.开始的时候配置了num.partitions为1,然后创建了topic,这时再修改num.partitions为2,此时操作topic,会报The number of expected partitions was: 2, but 1 has been found instead。

  解决方式:

  删除topic,重新创建

  或者设置spring.cloud.stream.kafka.binder. autoAddPartitions=true(参见http://www.suoniao.com/article/5ea3999bfda6d615af0517e1)

二.报LEADER_NOT_AVAILABLE,这个可能是没有设置host.name造成的,

  解决方式:

  修改server.properties配置文件,增加host.name,然后重启各节点服务,同时注意防火墙端口是否互通。

 3.Spring cloud stream 中需要注意事项

  一. producer中的partitionCount设置,默认为1,虽然kafka服务器上设置了num.partitions=2,但是生产者发送消息的时候还是会发送到一个分区里。只有partitionCount设置成和num.partitions一致时,才会轮询发送到两个分区内,使用如下命令可以查看分区内的内容

./kafka-console-consumer.sh  --bootstrap-server localhost:9092 --from-beginning --topic WordCount --partition 0

   如果想将一类消息发送到同一个分区,可以设置

  

spring.cloud.stream.bindings.mychannel.producer.partitionKeyExpression=payload         #相当于kafka中的key-value中的key
spring.cloud.stream.bindings.mychannel.producer.partitionCount=2

 但是对于kafka来说,上上面的设置并不起作用。调试源代码的时候也发现是查找的spring.cloud.stream.kafka.bindings下的spl表达式。所以对于binder为kafka来说,还需要在发送消息的时候设置kafka_message_key,如:

Message<OperateTypeMessage> build = MessageBuilder.withPayload(“ss”)
                .setHeader("operateType", "update")
                .setHeader(KafkaHeaders.MESSAGE_KEY, "sysuser".getBytes())
                .setHeader(MessageHeaders.CONTENT_TYPE,"application/json")
                .build();
        boolean send = sinkSender.channel().send(build);

 另外设置kafka的key 的序列化方式为:

spring:
  kafka:
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer

 

  二. 消息同步的方式是异步还是同步,是设置sync属性,默认为true。虽然从字面解释上来说,sync指的是同步,而设置为true,那么就是同步了,但是实际操作中和看手册说明,如果要同步的方式的话,应该设置为false。

  三. 在试验的过程中,在同一个topic中插入了不同类型的实体消息,stream在消费的时候报异常

  四.  消费者中使用condition区分不同处理方式的消息

 @StreamListener(target = TestSink.CHANNEL_NAME,condition = "headers['operateType']=='update'")
    public void recive(OperateTypeMessage<List<User>> message, @Headers Map<String,Object> header){
        if(message != null){
            logger.info("received:"+message.getPayLoad().get(0).getUserAccount());
            logger.info("received:"+message.getPayLoad().get(0).toString());
        }
        logger.info("received:"+message);
        //System.out.println("received:"+payload);
    }

    @StreamListener(target = TestSink.CHANNEL_NAME,condition = "headers['operateType']=='create'")
    public void reciveMessage(OperateTypeMessage<List<User>> message, @Headers Map<String,Object> header) throws InterruptedException {
        if(message != null){
            logger.info("received:"+message.getPayLoad().size());
            logger.info("received:"+message.getPayLoad().get(0).toString());
        }
        logger.info("received:"+message);
        logger.info("sleep start-------------------------------------");
        //Thread.sleep(100000);
/*        for (int i = 0; i < 1000*10000 ; i++) {
            System.out.println(i);
        }*/
        logger.info("sleep end-------------------------------------");
        //System.out.println("received:"+payload);
    }

 

    如果是同一分区的数据,headers['operateType']=='create'和'update'是有序的

 五. 消费者分组的问题

  如果一个服务中有定义了多个通道(主题),不同通道的group名字不能命名成一样的,否则stream会按照一个主题处理。

而我项目中的配置如下:

spring:
  cloud:
  ###################  消息队列框架配置  ###################
    stream:            #
      kafka:
        binder:
          brokers: 1.1.1.1:9092,2.2.2.2:9092
        bindings:                    #spring cloud stream 实现的kafka绑定器的通用设置,只对kafka生效
          sysuser_input:
            consumer:
              enableDlq: true        #是否启动死信队列设置,默认为false,设置为true时,引起错误的消息会被发送到名为error.<destination>.<group>的主题中
          
          employee_input:
            consumer:
              enableDlq: true        #是否启动死信队列设置,默认为false,设置为true时,引起错误的消息会被发送到名为error.<destination>.<group>的主题中
          
      bindings:
        sysuser_input:
          destination: sys_user1     #消息主题名称,消费者可以监听多个主题,不同的主题用逗号隔开,但是如果设置了group则会报错,必须是匿名的group才可以监听多个主题
          group: user_001            #分组,命名规则是业务名称+单位名称,不同channel的group名字不能相同

        employee_input:
          destination: sys_employee2
          group: employee_001

 

posted @ 2021-03-15 09:30  八方鱼  阅读(1239)  评论(0)    收藏  举报