Kafka学习之旅(六): Kafka生产者通信

一 简介
由官网可以了解到Kafka 所有组件(生产者,消费者,broker)之间的通信协议使用的是TCP,而不是使用的是HTTP 或者其他的通讯协议。那为什么他要去选择TCP而不使用HTTP呢?其实这里面的原因有很多,个人觉得最主要的原因在于 TCP 和 HTTP 之间的区别。
从社区的角度来看,在开发客户端时,人们能够利用 TCP本身提供的一些高级功能,比如多路复用请求以及同时轮询多个连接的能力。
什么是多路复用呢简单的介绍一下就是两个或者多个数据流合并到底层单一的物理连接中TCP 的多路复用请求会在一条物理连接上创建若干个虚拟连接,每
个虚拟连接负责流转各自对应的数据流。其实严格来说,TCP 并不能多路复用,它只是提供可靠的消息交付语义保证,比如自动重传丢失的报文。更严谨地说,作为一个基于报文的协议,TCP 能够被用于多路复用连接场景的前提是,上层的应用协议(比如 HTTP)允许发送多条消息。

二 Kafka是如何打开TCP 通信的
在创建 KafkaProducer 实例时,生产者应用会在后台创建并启动一个名为 Sender 的线程,该 Sender 线程开始运行时首先会创建与 Broker 的连接
下面可以给出一个测试例子来证明一下:

public static void main(String[] args) {
        Map map=new HashMap<String,String>();
        map.put("bootstrap.servers","localhost:9092");
        map.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        map.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        KafkaProducer kafkaProducer=new KafkaProducer(map);
       // ProducerRecord producerRecord=new ProducerRecord("test-topic","id","1");
        //kafkaProducer.send(producerRecord);
        //kafkaProducer.close();
    }

下面给出一段日志:

[12:55:31:581] [DEBUG] - org.apache.kafka.clients.Metadata.update(Metadata.java:290) - Updated cluster metadata version 1 to Cluster(id = null, nodes = [localhost:9092 (id: -1 rack: null)], partitions = [], controller = null)
[12:55:31:885] [DEBUG] - org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:426) - [Producer clientId=producer-1] Kafka producer started

在日志中好像发现了一个问题在没有指定那个指定topic 情况下 生产者好像去连接了kafka 集群。如果不调用 send 方法,这个 Producer 都不知道给哪个主题发消息,它又怎么能知道连接哪个 Broker 呢?难不成它会连接 bootstrap.servers参数指定的所有 Broker 吗?嗯,是的,Java Producer 目前还真是这样设计的。
我在这里稍微解释一下 bootstrap.servers 参数。它是Producer 的核心参数之一,指定了这个 Producer 启动时要连接的 Broker 地址。请注意,这里的“启动时”,代表的是 Producer 启动时会发起与这些 Broker 的连接。因此,如果你为这个参数指定了 1000 个 Broker 连接信息,那么很遗憾,你的 Producer 启动时会首先创建与这 1000个 Broker 的 TCP 连接。在实际使用过程中,我并不建议把集群中所有的 Broker 信息都配置到 bootstrap.servers 中,通常你指定 3~4 台就足以了。因为 Producer 一旦连接到集群中的任一台Broker,就能拿到整个集群的 Broker 信息,故没必要为bootstrap.servers 指定所有的 Broker。
TCP 连接是在创建KafkaProducer 实例时建立的。但!TCP 连接还可能在两个地方被创建:一个是在更新元数据后,另一个是在消息发送时。为什么说是可能?因为这两个地方并非总是创建 TCP 连接。当 Producer 更新了集群的元数据信息之后,如果发现与某些 Broker 当前没有连接,那么它就会创建一个 TCP 连接。同样地,当要发送消息时,Producer 发现尚不存在与目标 Broker 的连接,也会创建一个。

二 Kafka是如何关闭TCP 通信的
关闭的方式由两种一种是主动的关闭,一种是自动断开连接。
第一种比较简单比如用户主动kill 或者调用close 方法。
第二种是 Kafka 帮你关闭,这与 Producer 端参数connections.max.idle.ms 的值有关。默认情况下该参数值是 9 分钟,即如果在 9 分钟内没有任何请求通过某个TCP 连接,那么 Kafka 会主动帮你把该 TCP 连接关闭。用户可以在 Producer 端设置 connections.max.idle.ms=-1禁掉这种机制。一旦被设置成 -1,TCP 连接将成为永久长连接。当然这只是软件层面的“长连接”机制,由于 Kafka创建的这些 Socket 连接都开启了 keepalive,因此keepalive 探活机制还是会遵守的。

下面总结一下本篇

  1. KafkaProducer 实例创建时启动 Sender 线程,从而创建与 bootstrap.servers 中所有 Broker 的 TCP 连接。
  2. KafkaProducer 实例首次更新元数据信息之后,还会再次创建与集群中所有 Broker 的 TCP 连接。
  3. 如果 Producer 端发送消息到某台 Broker 时发现没有与该 Broker 的 TCP 连接,那么也会立即创建连接。
  4. 如果设置 Producer 端 connections.max.idle.ms 参数大于 0,则步骤 1 中创建的 TCP 连接会被自动关闭;如果设置该参数 =-1,那么步骤 1 中创建的TCP 连接将无法被关闭,从而成为“僵尸”连接。
发布了213 篇原创文章 · 获赞 35 · 访问量 85万+

猜你喜欢

转载自blog.csdn.net/u012957549/article/details/97611292
今日推荐