13 | Java生产者是如何管理TCP连接的?
13 | Java生产者是如何管理TCP连接的?
讲述:胡夕
时长12:14大小9.81M
为何采用 TCP?
Kafka 生产者程序概览
何时创建 TCP 连接?
何时关闭 TCP 连接?
小结
开放讨论
赞 19
提建议
精选留言(83)
- 注定非凡2019-10-31Apache Kafka的所有通信都是基于TCP的,而不是于HTTP或其他协议的 1 为什采用TCP? (1)TCP拥有一些高级功能,如多路复用请求和同时轮询多个连接的能力。 (2)很多编程语言的HTTP库功能相对的比较简陋。 名词解释: 多路复用请求:multiplexing request,是将两个或多个数据合并到底层—物理连接中的过程。TCP的多路复用请求会在一条物理连接上创建若干个虚拟连接,每个虚拟连接负责流转各自对应的数据流。严格讲:TCP并不能多路复用,只是提供可靠的消息交付语义保证,如自动重传丢失的报文。 2 何时创建TCP连接? (1)在创建KafkaProducer实例时, A:生产者应用会在后台创建并启动一个名为Sender的线程,该Sender线程开始运行时,首先会创建与Broker的连接。 B:此时不知道要连接哪个Broker,kafka会通过METADATA请求获取集群的元数据,连接所有的Broker。 (2)还可能在更新元数据后,或在消息发送时 3 何时关闭TCP连接 (1)Producer端关闭TCP连接的方式有两种:用户主动关闭,或kafka自动关闭。 A:用户主动关闭,通过调用producer.close()方关闭,也包括kill -9暴力关闭。 B:Kafka自动关闭,这与Producer端参数connection.max.idles.ms的值有关,默认为9分钟,9分钟内没有任何请求流过,就会被自动关闭。这个参数可以调整。 C:第二种方式中,TCP连接是在Broker端被关闭的,但这个连接请求是客户端发起的,对TCP而言这是被动的关闭,被动关闭会产生大量的CLOSE_WAIT连接。展开
作者回复: 总结得相当强:)
共 6 条评论46 - 旭杰2019-07-23Producer 通过 metadata.max.age.ms定期更新元数据,在连接多个broker的情况下,producer是如何决定向哪个broker发起该请求?
作者回复: 向它认为当前负载最少的节点发送请求,所谓负载最少就是指未完成请求数最少的broker
共 4 条评论25 - 小马2020-01-09老师有个问题请教下: Producer 通过 metadata.max.age.ms 参数定期地去更新元数据信息,默认5分钟更新元数据,如果没建立TCP连接则会创建,而connections.max.idle.ms默认9分钟不使用该连接就会关闭。那岂不是会循环往复地不断地在创建关闭TCP连接了吗?
作者回复: 如果你的producer长时间没有消息需要发送,TCP连接确实会定期关闭再重建的
共 2 条评论20 - Frank2019-07-10最近在使用kafka Connector做数据同步服务,在kafka中创建了许多topic,目前对kafka了解还不够深入,不知道这个对性能有什么影响?topic的数量多大范围比较合适?
作者回复: topic数量只要不是太多,通常没有什么影响。如果单台broker上分区数超过2k,那么可能要关注是否会出现性能问题了。
16 - 你好旅行者2019-07-02老师好,看了今天的文章我有几个问题: 1.Kafka的元数据信息是存储在zookeeper中的,而Producer是通过broker来获取元数据信息的,那么这个过程是否是这样的,Producer向Broker发送一个获取元数据的请求给Broker,之后Broker再向zookeeper请求这个信息返回给Producer? 2.如果Producer在获取完元数据信息之后要和所有的Broker建立连接,那么假设一个Kafka集群中有1000台Broker,对于一个只需要与5台Broker交互的Producer,它连接池中的链接数量是不是从1000->5->1000->5?这样不是显得非常得浪费连接池资源?展开
作者回复: 1. 集群元数据持久化在ZooKeeper中,同时也缓存在每台Broker的内存中,因此不需要请求ZooKeeper 2. 就我个人认为,的确有一些不高效。所以我说这里有优化的空间的。
共 4 条评论15 - 柠檬C2019-07-02应该可以用懒加载的方式,实际发送时再进行TCP连接吧,虽然这样第一次发送时因为握手的原因会稍慢一点共 4 条评论15
- 蓝魔丶2019-08-04老师,如果Broker端被动关闭,会导致client端产生close_wait状态,这个状态持续一段时间之后,client端不是应该发生FIN完成TCP断开的正常四次握手吗?怎么感觉老师讲的这个FIN就不会再发了,导致了僵尸连接的产生?
作者回复: 问题在于客户端有可能一直hold住这个连接导致状态一直是CLOSE_WAIT。事实上,这是非常正确的做法,至少符合TCP协议的设计。当然,如果客户端关闭了连接,就像你说的,OS会发起FIN给远端
共 7 条评论12 - kursk.ye2019-07-02试想一下,在一个有着 1000 台 Broker 的集群中,你的 Producer 可能只会与其中的 3~5 台 Broker 长期通信,但是 Producer 启动后依次创建与这 1000 台 Broker 的 TCP 连接。一段时间之后,大约有 995 个 TCP 连接又被强制关闭。这难道不是一种资源浪费吗?很显然,这里是有改善和优化的空间的。 这段不敢苟同。作为消息服务器中国,连接应该是种必要资源,所以部署时就该充分给予,而且创建连接会消耗CPU,用到时再创建不合适,我甚至觉得Kafka应该有连接池的设计。 另外最后一部分关于TCP关闭第二种情况,客户端到服务端没有关闭,只是服务端到客户端关闭了,tcp是四次断开,可以单方向关闭,另一方向继续保持连接展开
作者回复: 嗯嗯,欢迎不同意见。Kafka对于创建连接没有做任何限制。如果一开始就创建所有TCP连接,之后因为超时的缘故又关闭这些连接,当真正使用时再次创建,那么为什么不把创建时机后延到真正需要的时候呢?实际场景中将TCP连接设置为长连接的情形并不多见,因此我说这种设计是可以改进的。
共 12 条评论11 - 半瓶醋2020-05-13胡夕老师,Kafka集群的元数据信息是保存在哪里的呢,以CDH集群为例,我比较菜:)
作者回复: 最权威的数据保存在ZooKeeper中,Controller会从ZooKeeper中读取并保存在它自己的内存中,然后同步部分元数据给集群所有Broker
共 2 条评论8 - yzh2019-08-20老是您好,咨询两个问题。 1. Producer实例创建和维护的tcp连接在底层是否是多个Producer实例共享的,还是Jvm内,多个Producer实例会各自独立创建和所有broker的tcp连接 2.Producer实例会和所有broker维持连接,这里的所有,是指和topic下各个分区leader副本所在的broker进行连接的,还是所有的broker,即使该broker下的所有topic分区都是flower展开
作者回复: 1. 这些TCP连接只会被Producer实例下的Sender线程使用。多个Producer实例会创建各自的TCP连接 2. 从长期来看,只和需要交互的Broker有连接
8 - 电光火石2019-07-07谢谢老师。有几个问题请教一下: 1. producer连接是每个broker一个连接,跟topic没有关系是吗?(consumer也是这样是吗?) 2. 我们运维在所有的broker之前放了一个F5做负载均衡,但其实应该也没用,他会自动去获取kafka所有的broker,绕过这个F5,不知道我的理解是否正确? 3. 在线上我们有个kafka集群,大概200个topic,数据不是很均衡,有的一天才十几m,有的一天500G,我们是想consumer读取所有的topic,然后后面做分发,但是consumer会卡死在哪,也没有报错,也没有日志输出,不知道老师有没有思路可能是什么原因? 谢谢了!展开
作者回复: 1. 也不能说没有关系。客户端需要和topic下各个分区leader副本所在的broker进行连接的 2. 嗯嗯,目前客户端是直连broker的 3. 光看描述想不出具体的原因。有可能是频繁rebalance、long GC、消息corrupted或干脆就是一个已知的bug
5 - 曾轼麟2019-07-02老师下面就有一个问题,KafkaProducer是建议创建实例后复用,像连接池那样使用,还是建议每次发送构造一个实例?听完这讲后感觉哪个都不合理,每次new会有很大的开销,但是一次new感觉又有僵尸连接,KafkaProducer适合池化吗?还是建议单例?
作者回复: KafkaProducer是线程安全的,复用是没有问题的。只是要监控内存缓冲区的使用情况。毕竟如果多个线程都使用一个KafkaProducer实例,缓冲器被填满的速度会变快。
4 - 开水2019-07-02觉得创建kafkaProducer的时候可以不用去创建sender线程去连接broker。 1. 第一次更新元数据的时候,配置一个并发连接参数,比如说10,按照该连接参数的余数去和配置中broker建立TCP连接。 2. 获取到相应的metadata信息后,再去和相应的broker进行连接,连接建立后关闭掉无用的连接。 3. 按照原有设计,发送数据时再次检查连接。 这样多余连接不会超过10,并且可配置。而且在更新metadata和发送数据时进行了连接的双重监测,不用进行三次监测。展开共 2 条评论4
- 诗泽2019-07-02看来无论在bootstrap.servers中是否写全部broker 的地址接下来producer 还是会跟所有的broker 建立一次连接😂4
- Wenthkim2019-07-23老师,请教一个问题,目前遇到一个文中所提的一个问题,就是broker端被直接kill -9,然后产生不量的close_wait,导致重启broker后,producer和consumer都连不上,刷了大量的日志,把机器磁盘给刷爆了,请问老师这个问题我应该怎么去处理?
作者回复: 为什么连不上了呢?是ulimit打满了吗?如果是可否调大一下?
3 - 吴宇晨2019-07-02老师你好,kafka更新元数据的方法只有每5分钟的轮训吗,如果有监控zk节点之类的,是不是可以把轮询元数据时间调大甚至取消
作者回复: Clients端有个参数metadata.max.age.ms强制刷新元数据,默认的确是5分钟。新版本Clients不会与ZooKeeper交互,所以感觉和ZooKeeper没什么关系。。。
3 - KEEPUP2019-07-02KafkaProducer 实例只是在首次更新元数据信息之后,创建与集群中所有 Broker 的 TCP 连接,还是每次更新之后都要创建?为什么要创建与所有 Broker 的连接呢?共 3 条评论3
- Liam2019-07-02producer是否会有类似于heart beat的机制去探测可能被broker关闭的连接然后建立重连呢?
作者回复: 当需要用到连接而发现连接不可用的时候就会重建连接了
3 - James2020-05-14请问老师, 第一次创建实例,获取metadata数据,比如有1000个Broker,则会创建1000个连接吗 然后跟不存在的主题发送消息,也会获取metadata数据,然后也是创建1000个连接吗 最后,定时更新metadada也是会创建1000个连接吗 然后最大保活时间又删除无用的连接,是吧。展开
作者回复: 目前的设计是不会,它只会与需要访问的主题分区所在的broker建立连接
2 - 张伯毅2019-12-25整个集群 topic 的数量有限制嘛, 最大是多少 ? 单台broker上分区数最好不要超过 2k . 这个是根据经验来的嘛,还是官方有推荐.??
作者回复: 官方给的经验:) 最好还是结合自己实际场景而定
2