Kafka集群搭建踩坑记录

Kafka集群搭建踩坑记录

最近在学习kafka,但是在用虚拟机跑的时候,动不动就会卡死,内存不足之类的,于是想用docker来搭建kafka的运行环境。当然也踩了不少的坑,写一篇博文记录一下。

这里我们先不搭建集群的kafka,而是搭建单机的。

Zookeeper环境搭建

弄Kafka不搞zookeeper那是不可能的,因此我们先开始弄zookeeper的环境。

首先我们在docker里新建一个内网环境:

docker network create docker_net # 接下来zookeeper和kafka都在这个内网里实现连通

docker-compose-zookeeper.yml文件如下:

version: '1.0'

networks:
  # 使用外部网络,即在docker中的自定义网络
  docker_net:
    external: true

services:
  zoo:
  	# 指定的镜像名
    image: zookeeper
    restart: unless-stopped
    # 这里我们修改了docker中的hostname,内网里可以直接用zoo来代替其IP地址
    hostname: zoo
    container_name: zoo
    ports:
      - 2182:2181
      #配置zookeeper的id与其服务器
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server=zoo:2888:3888
    # 挂载linux中的文件
    volumes:
      - ./zookeeper/zoo1/data:/data
      - ./zookeeper/zoo1/datalog:/datalog
	# 选择内网网络
    networks:
      - docker_net

执行命令开启zookeeper

docker-compose -f docker-compose-zookeeper.yml up -d

进入其中查看zookeeper的启动状态

docker exec -it zoo /bin/bash

bin/zkServer.sh status #最后得出zookeeper执行成功

Kafka集群搭建

这里需要好好说一下

还是先看docker-compose-kafka.yml的文件该怎么写

这里还是需要记录一下两个概念,这里引用一下这篇文章的解释:listeners和advertised.listeners

  • listeners: 学名叫监听器,其实就是告诉外部连接者要通过什么协议访问指定主机名和端口开放的 Kafka 服务。
  • advertised.listeners:和 listeners 相比多了个 advertisedAdvertised 的含义表示宣称的、公布的,就是说这组监听器是 Broker 用于对外发布的。

比如说:

listeners: INSIDE://172.17.0.10:9092,OUTSIDE://172.17.0.10:9094
advertised_listeners: INSIDE://172.17.0.10:9092,OUTSIDE://<公网 ip>:端口
kafka_listener_security_protocol_map: "INSIDE:SASL_PLAINTEXT,OUTSIDE:SASL_PLAINTEXT"
kafka_inter_broker_listener_name: "INSIDE"

advertised_listeners 监听器会注册在 zookeeper 中;

当我们对 172.17.0.10:9092 请求建立连接,kafka 服务器会通过 zookeeper 中注册的监听器,找到 INSIDE 监听器,然后通过 listeners 中找到对应的 通讯 ip 和 端口;

同理,当我们对 <公网 ip>:端口 请求建立连接,kafka 服务器会通过 zookeeper 中注册的监听器,找到 OUTSIDE 监听器,然后通过 listeners 中找到对应的 通讯 ip 和 端口 172.17.0.10:9094

总结:advertised.listeners在docker中的作用在于将内部的listeners注册到zookeeper中,从而可以被外界访问到

version: '1.0'

networks:
  docker_net:
    external: true

services:
  kafka:
    # 这个镜像时候docker-hub上比较火的kafka镜像。更新的比较勤快
    image: wurstmeister/kafka
    restart: unless-stopped
    container_name: kafka
    ports:
      - "9093:9092"
    # 相当于docker --link zoo, 可以通过这个实现kafka的镜像访问zoo
    external_links:
      - zoo
    environment:
      KAFKA_BROKER_ID: 1
      # 将会通知给其他生产者和消费者的主机名。会注册在zookeeper中 -- 这里需要改为宿主机的IP地址
      # 这里没有写listners的IP,因为它为空的时候其实就是暴露的本地IP,localhost,而我们通过advertised.listeners其实就是建立了kafka的本地IP和外部宿主机之间的IP互通
      KAFKA_ADVERTISED_HOST_NAME: 10.181.56.101                 ## 修改:宿主机IP
      KAFKA_ADVERTISED_PORT: 9093                            # 修改:宿主机映射port
      # 注册到zookeeper中,暴露给外界,从而可以从外界调用到
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://10.181.56.101:9093    ## 绑定发布订阅的端口。修改:宿主机IP
      KAFKA_ZOOKEEPER_CONNECT: "zoo:2181"
    volumes:
      - "./kafka/kafka1/docker.sock:/var/run/docker.sock"
      - "./kafka/kafka1/data/:/kafka"
    networks:
      - docker_net

接着通过以下命令执行;

docker-compose -f docker-compose-kafka.yml up -d

我们通过java代码进行调试

生产者

public class ProducerStart {

    private static final String brokerList = "dennis-1:9092"; //这里的dennis-1是我的虚拟机主机名hostname
    private static final String topic = "heima"; // 最开始看的黑马的视频学的

    public static void main(String[] args) throws InterruptedException {
        Properties properties = new Properties();

        //设置Key序列化器
        //properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());

        //设置重试次数
        properties.put(ProducerConfig.RETRIES_CONFIG, 10);

        //设置值序列化器
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        //设置集群地址
        properties.put("bootstrap.servers", brokerList);

        KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
//        //封装了发送的消息
        ProducerRecord<String, String> record = new ProducerRecord<>(topic, "kafka-demo",
                "hello,kafka run");

        for (int i = 0; i < 10; i++) {
            TimeUnit.SECONDS.sleep(3);
            producer.send(record, (metadata, e) -> {
                if (e == null) {
                    System.out.println("topic:" + metadata.topic());
                    System.out.println("partitions:" + metadata.partition());
                    System.out.println("offset:" + metadata.offset());
                }
            });
        }

        producer.close();

    }
}

image-20200527090737423

测试成功,可以发布。

消费者

接下来我们来测试消费者的订阅

public class ConsumerStart {
    private static final String brokerList = "dennis-1:9092";
    private static final String topic = "heima";
    private static final String groupId = "group.demo";

    public static void main(String[] args) {
        Properties properties = new Properties();

        //设置Key反序列化器
        properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        //设置值反序列化器
        properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        //设置集群地址
        properties.put("bootstrap.servers", brokerList);

        //设置GroupId
        properties.put("group.id", groupId);

        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);

        consumer.subscribe(Collections.singleton(topic));

        while (true){
            // 接收消息
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
            records.forEach(System.out::println);
        }

    }
}

image-20200527090911542

接受到了发布的消息,订阅成功。

一个困扰了我很久的坑

楼主最开始在调试的时候,一直在报一个错误:

[Kafka]Error while fetching metadata with correlation id 4192 : {testXX=LEADER_NOT_AVAILABLE}

消息的发布和订阅找不到leader结点。后来才发现其实是宿主机IP设置的不对,我最开始将其设置为了kafka镜像内部的

image-20200527091137917

即这里的172.18.0.2.其实宿主机应该指的是你虚拟机的IP地址,而且应该是静态IP(我用的是virtualbox,有关静态IP的设置可以参考我的另一篇博文:虚拟机静态ip配置

当advertised.listeners进行IP转发的时候,将获取到的本地IP又通过zookeeper转发了回去,这样肯定访问不到

因此应该将advertised.listeners改为虚拟机的IP,端口用我们映射到虚拟机的端口号,这样就解决了这个bug。

至于集群的搭建可以参考这篇文章,其实我的很多东西也是看的这两篇:

  1. zookeeper搭建:https://zhuanlan.zhihu.com/p/110677319
  2. kafka集群:https://zhuanlan.zhihu.com/p/110905106
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章