Kafka: Get broker host from ZooKeeper

前端 未结 5 942
伪装坚强ぢ
伪装坚强ぢ 2020-12-02 13:32

For particular reasons I need to use both - ConsumerGroup (a.k.a. high-level consumer) and SimpleConsumer (a.k.a. low-level consumer) to read from

相关标签:
5条回答
  • 2020-12-02 14:02
     public KafkaProducer(String zookeeperAddress, String topic) throws IOException,
            KeeperException, InterruptedException {
    
        this.zookeeperAddress = zookeeperAddress;
        this.topic = topic;
    
        ZooKeeper zk = new ZooKeeper(zookeeperAddress, 10000, null);
        List<String> brokerList = new ArrayList<String>();
    
        List<String> ids = zk.getChildren("/brokers/ids", false);
        for (String id : ids) {
            String brokerInfoString = new String(zk.getData("/brokers/ids/" + id, false, null));
            Broker broker = Broker.createBroker(Integer.valueOf(id), brokerInfoString);
            if (broker != null) {
                brokerList.add(broker.connectionString());
            }
        }
    
        props.put("serializer.class", KAFKA_STRING_ENCODER);
        props.put("metadata.broker.list", String.join(",", brokerList));
        producer = new Producer<String, String>(new ProducerConfig(props));
    }
    
    0 讨论(0)
  • 2020-12-02 14:13

    To do this using the shell:

    zookeeper-shell myzookeeper.example.com:2181
    ls /brokers/ids
      => [2, 1, 0]
    get /brokers/ids/2
    get /brokers/ids/1
    get /brokers/ids/0 
    
    0 讨论(0)
  • 2020-12-02 14:18

    It turns out that Kafka uses ZKStringSerializer to read and write data into znodes. So, to fix the error I only had to add it as a last parameter in ZkClient constructor:

    val zkClient = new ZkClient(zkQuorum, Integer.MAX_VALUE, 10000, ZKStringSerializer)
    

    Using it, I wrote several useful functions for discovering broker ids, their addresses and other stuff:

    import kafka.utils.Json
    import kafka.utils.ZKStringSerializer
    import kafka.utils.ZkUtils
    import org.I0Itec.zkclient.ZkClient
    import org.apache.kafka.common.KafkaException
    
    
    def listBrokers(): List[Int] = {
      zkClient.getChildren("/brokers/ids").toList.map(_.toInt)
    }
    
    def listTopics(): List[String] = {
      zkClient.getChildren("/brokers/topics").toList
    }
    
    def listPartitions(topic: String): List[Int] = {
      val path = "/brokers/topics/" + topic + "/partitions"
      if (zkClient.exists(path)) {
        zkClient.getChildren(path).toList.map(_.toInt)
      } else {
        throw new KafkaException(s"Topic ${topic} doesn't exist")
      }
    }
    
    def getBrokerAddress(brokerId: Int): (String, Int) = {
      val path = s"/brokers/ids/${brokerId}"
      if (zkClient.exists(path)) {
        val brokerInfo = readZkData(path)
        (brokerInfo.get("host").get.asInstanceOf[String], brokerInfo.get("port").get.asInstanceOf[Int])
      } else {
        throw new KafkaException("Broker with ID ${brokerId} doesn't exist")
      }
    }
    
    def getLeaderAddress(topic: String, partitionId: Int): (String, Int) = {
      val path = s"/brokers/topics/${topic}/partitions/${partitionId}/state"
      if (zkClient.exists(path)) {
        val leaderStr = zkClient.readData[String](path)
        val leaderId = Json.parseFull(leaderStr).get.asInstanceOf[Map[String, Any]].get("leader").get.asInstanceOf[Int]
        getBrokerAddress(leaderId)
      } else {
        throw new KafkaException(s"Topic (${topic}) or partition (${partitionId}) doesn't exist")
      }
    }
    
    0 讨论(0)
  • 2020-12-02 14:19

    actually, there is ZkUtils from within Kafka (at least for 0.8.x line), that you can use with one small caveat: you'll need to re-implement ZkStringSerializer that would convert strings as UTF-8 encoded byte arrays. If you'd like to use Java8's streaming APIs, you can iterate over Scala collections throug scala.collection.JavaConversions. This is the thing that helped my case.

    0 讨论(0)
  • 2020-12-02 14:20

    That is the way of what one of my colleagues did to get a list of Kafka brokers. I think it's a correct way when you want to get a broker list dynamically.

    Here is an example code that shows how to get the list.

    public class KafkaBrokerInfoFetcher {
    
        public static void main(String[] args) throws Exception {
            ZooKeeper zk = new ZooKeeper("localhost:2181", 10000, null);
            List<String> ids = zk.getChildren("/brokers/ids", false);
            for (String id : ids) {
                String brokerInfo = new String(zk.getData("/brokers/ids/" + id, false, null));
                System.out.println(id + ": " + brokerInfo);
            }
        }
    }
    

    Running the code onto the cluster consisting of three brokers results in

    1: {"jmx_port":-1,"timestamp":"1428512949385","host":"192.168.0.11","version":1,"port":9093}
    2: {"jmx_port":-1,"timestamp":"1428512955512","host":"192.168.0.11","version":1,"port":9094}
    3: {"jmx_port":-1,"timestamp":"1428512961043","host":"192.168.0.11","version":1,"port":9095}
    
    0 讨论(0)
提交回复
热议问题