你试过在另一个VPC里启动Kafka客户端,明明两个网络之间路由通了,telnet也能连上,但客户端就是消费不到一条消息,是不是会怀疑网络出了bug?其实不是。

Kafka跨VPC连接失败的根源,是一个寻址问题,而不是网络连通性问题。一旦想通这一点,为什么VPC对等、中转网关、每个broker单独挂负载均衡这些方案都不好使,就很好理解了。

普通服务跨网络访问很简单:在前面放一个负载均衡器,给一个地址,客户端都指向它,就完事了。但Kafka不是这样工作的。客户端建立连接分两步:第一步,引导阶段,客户端先跟任意一个broker通信,问一句“集群里都有谁”;第二步,直接连接阶段,broker应答时会返回元数据,也就是一列broker的信息,每个broker都以自己的advertised.listeners地址命名。客户端随后会向特定的broker发起直连——要么是它要读写分区的leader,要么是最近的副本(如果你开启了KIP-392的follower fetching,Kafka 2.4以上版本都支持)。

第二步是关键。在集群前面放一个共享地址没用,因为客户端必须解析并路由到每个broker对外通告的那个地址,集群怎么给,客户端就必须怎么连。假如某个broker通告的是broker-1.cluster.internal:9092,这个域名只在集群所在VPC内可解析,那么远程客户端会先顺利完成引导连接,然后尝试直连这个地址时立刻失败。像这样:

docker exec kafka-consumer-a kcat -b kafka:9092 -L -m 5
# -> Failed to resolve 'kafka:9092'

两个VPC之间有了网络通路,不代表Kafka可达。客户端坐在自己的位置,还得把每个broker通告的地址解析通、路由通。

那让broker通告一个可路由的地址不就好了吗?确实,broker支持配置多个监听器,一个对内一个对外。但每个监听器意味着每个broker上都要多开一个端口,而且像MSK、Confluent Cloud、Aiven这类托管Kafka服务通常根本不让你改动。更重要的是,监听器方案扩展不到跨账号、跨云的一堆独立网络,而你所面对的正是这种局面。

说起VPC对等,它用来打通两个VPC的确很好用;一旦超过两个,坑就来了:对等是点对点且不可传递的,把网络A、B各自对等到集群VPC,A并不能通过集群跟B通信。每个新客户端网络都需要跟集群VPC建立自己的对等连接,于是集群VPC就被动变成了中心枢纽。十个客户端网络意味着十条对等、十条路由表条目、十轮安全组沟通,而集群VPC压根儿就不是为当枢纽设计的。CIDR也得提前协调好,对等的VPC网段不能重叠,每个团队都得坐下来商量地址空间。再加上托管Kafka服务本身对可建立的对等连接或PrivateLink数量有所限制,一旦触顶就无从扩展。

所以下次再遇到跨VPC连Kafka的怪现象,先别急着查防火墙,也许只是broker嘴里报出的那个地址,客户端压根够不着。