【kafka通过nginx对外代理需求配置】

网络介绍

在工作中,有一需求将flink中日志投递到kafka中进行消费,由于两个中间件所处网络复杂,之间无法直接互通,因为借助nginx进行代理kafka,供flink进行投递。具体网络详情如下:
flink(后面称客户端,因为这不局限于flink,也可以是任何业务或中间件)和Nginx1位于资源池1
kafka与Nginx2位于资源池2
客户端与Nginx1 相通,Nginx1与Nginx2相通,Nginx2与kakfa相通。
客户端<->nginx1<->nginx2<->kafka

问题背景

刚开始,完成网络配置后,尝试进行消息投递,结果是投递失败。在排查问题时,发现一个现象:客户端所在机器会与kafka所在机器进行三次握手操作,一直卡在SYN_SEND环节。flink所在机器与kafka所在机器必然不通,之间不可能建立连接进行通信。全网很多方案都没讲清这样配置方案,因此本博客详细讲述下。
为解决上述三次握手一直卡在SYN_SEND阶段的问题,研究了下客户端为何去直接请求kafka所在机器IP。原因为:发现在投递时,客户端会根据kafka config/server.properties 文件中advertised.listeners配置进行二次请求(这个很关键),具体步骤如下:

  1. 客户端请求nginx1, nginx1会将流量发给nginx2, nginx2再给kafka建立连接,并返回advertised.listeners的url
  2. 客户端拿到advertised.listeners的ip,发现请求不通。

advertised.listeners 配置项用于告诉客户端可以如何访问 Kafka。每个条目可以指定不同的协议、主机和端口。

解决方案

  1. 配置两处nginx,nginx需要支持四层stream代理,若不支持可以先找博客解决下
  2. kafka配置
  3. hosts配置,包括客户端和kafka端,如果客户端服务在k8s里,可以修改coredns。非k8s修改 /etc/hosts即可。

首先是两处nginx的配置:

nginx共同处配置

# 配置 nginx.conf
# stream的配置可以不同,大家可以根据自己的配置来,也就是正常的反向代理配置
stream {
    log_format proxy '$time_iso8601|$remote_addr|$protocol|$status|'
                     '$bytes_sent|$bytes_received|$session_time|$upstream_addr|$upstream_bytes_sent|'
                     '$upstream_bytes_received|$upstream_connect_time';
    map $time_iso8601 $logdate {
      '~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
      default          'date-not-found';
    }
    access_log /var/log/nginx/tcp_access_$logdate.log proxy;
    include /etc/nginx/stream.d/*.conf;
}

nginx1

upstream nginx1 {
   server nginx2机器ip:port;
}

server {
   listen 9093;
   proxy_pass nginx1;
}

nginx2

upstream nginx2 {
   server kafka的ip:port
}
server {
   listen 9093; (端口自拟)
   proxy_connect_timeout 5s;
   proxy_timeout 300s;
   access_log /var/log/nginx/tcp_access_$logdate.log proxy;
   proxy_pass nginx2;
}

kafka配置和hosts配置

kafka配置和hosts配置很关键,也是整个博客精华所在。刚刚上面提到的客户端会拿advertised.listeners配置的地址直接请求,如果配置成ip+port必然行不通,因此我们采用域名+port方式请求,当客户端拿到域名+port也会原封不动请求。这里客户端和kafka端域名必须相同。
有人就会质疑,那直接将advertised.listeners配置成客户端所能访问的IP(nginx1 ip + port)不就可以了吗?大家可以试下,我这样kafka启动直接报错。

采用域名方式其实是为了欺骗kakfa和客户端,我们给kafka端配置的域名解析是kafka所能访问的ip+port(可以试试127.0.0.1 + port ,或者nginx2 ip + port 应该都是可以的),而给客户端所配置的域名解析是nginx1 ip + port。这样配置后,可以想象一下:

  1. 客户端请求nginx1, nginx1会将流量发给nginx2, nginx2再给kafka建立连接,并返回advertised.listeners的url
  2. 客户端拿到advertised.listeners的url直接请求,这里的域名直接解析成nginx1的地址,完成通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值