We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
接触过CDN的小伙伴可能注意过,CDN的回源地址一般都不止一个,有时候会让源站对这些IP地址进行加白。这么做的目的一般有两个:1. 通过增加IP的方式突破单IP 65535的端口的限制,增加并发连接数;2. 防止后端服务阻断某个IP导致流量回注失败的情况。网上有很多教程教大家怎么用Nginx搭一个CDN,那么问题来了,当我手头只有一个Nginx的时候,能够做到上述的多个回源地址么?
答案是可以的,用Nginx proxy_bind 指令 + split_clients指令。
Nginx的proxy_bind指令可以指定连接upstream时候的本地IP,当配置文件中设置了这个IP后,socket建连进行到bind的阶段,就可以用这个IP进行绑定,upstream侧看到请求就都是从这个IP发过来的。但是proxy_bind只能指定一个IP地址,没办法直接配置数组,那没办法配置多出口了么?上帝关上了门的时候,一定留下了一扇窗。proxy_bind除了支持设置单一IP外,还可以设置变量(也支持透明传输,见参考资料),我们可以在不同的请求中对这个变量赋不同的IP,这样就能达到多出口的目的了。split_clients就可以帮我们完成上述的功能。话不多说,上配置文件:
user www-data; worker_processes auto; pid /run/nginx.pid; events { worker_connections 768; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; upstream backend { server 192.168.0.161:80; } server { listen 80 default_server; server_name _; access_log /var/log/nginx/access.log combined; location / { proxy_pass http://backend; proxy_bind $split_ip; proxy_set_header X-Forwarded-For $remote_addr; } } split_clients "$request_uri$remote_port" $split_ip { 33% 192.168.0.151; 33% 192.168.0.152; * 192.168.0.153; } }
大家可以着重把注意力放到29-40行,妙的地方就在这里,只要请求过来,就会根据请求URI+客户端端口计算hash值,选出一个$split_ip,并且赋给proxy_bind指令,就完成了多出口IP的配置。测试拓扑图大概是这样的:
这样,我在192.168.0.161的Nginx的access.log中看到的客户端IP就是三个了。但是,这样就结束了么?NoNoNo,还需要简单优化一下下:
upstream backend { server 192.168.0.161:80; keepalive 16; } server { listen 80 default_server; server_name _; access_log /var/log/nginx/access.log combined; location / { proxy_pass http://backend; proxy_bind $split_ip; proxy_set_header X-Forwarded-For $remote_addr; proxy_http_version 1.1; proxy_set_header Connection ""; } }
是的!我加上了keepalive相关的配置!按照猜测,应该可以轮询IP,然后访问upstream的时候,既能出现多IP,也能保持长连接。
然后我用wrk试了一下,没问题,能够满足我上面的猜测。wrk的命令如下:
wrk -t8 -c200 -d10s --latency "http://192.168.0.151"
其实,我也用curl试了下,发现访问的频率变低之后,IP始终不会变化。
后来抓包分析了下,应该和并发有关系,如果并发为1的情况,大概率会一直以某个IP进行访问,重新建联后,可能会换成别的IP。当然如果并发上去了,就会出现多个IP同时使用的情况。抓包是在192.168.0.161上进行的,命令如下:
tcpdump -i any host 192.168.0.151 or host 192.168.0.152 or host 192.168.0.153 -w 1.cap
分析抓包的数据,发现这么几个特点:
至此,我们的Nginx改造完成,并且进行了优化,完美地解决了问题!
The text was updated successfully, but these errors were encountered:
No branches or pull requests
接触过CDN的小伙伴可能注意过,CDN的回源地址一般都不止一个,有时候会让源站对这些IP地址进行加白。这么做的目的一般有两个:1. 通过增加IP的方式突破单IP 65535的端口的限制,增加并发连接数;2. 防止后端服务阻断某个IP导致流量回注失败的情况。网上有很多教程教大家怎么用Nginx搭一个CDN,那么问题来了,当我手头只有一个Nginx的时候,能够做到上述的多个回源地址么?
答案是可以的,用Nginx proxy_bind 指令 + split_clients指令。
Nginx的proxy_bind指令可以指定连接upstream时候的本地IP,当配置文件中设置了这个IP后,socket建连进行到bind的阶段,就可以用这个IP进行绑定,upstream侧看到请求就都是从这个IP发过来的。但是proxy_bind只能指定一个IP地址,没办法直接配置数组,那没办法配置多出口了么?上帝关上了门的时候,一定留下了一扇窗。proxy_bind除了支持设置单一IP外,还可以设置变量(也支持透明传输,见参考资料),我们可以在不同的请求中对这个变量赋不同的IP,这样就能达到多出口的目的了。split_clients就可以帮我们完成上述的功能。话不多说,上配置文件:
大家可以着重把注意力放到29-40行,妙的地方就在这里,只要请求过来,就会根据请求URI+客户端端口计算hash值,选出一个$split_ip,并且赋给proxy_bind指令,就完成了多出口IP的配置。测试拓扑图大概是这样的:
这样,我在192.168.0.161的Nginx的access.log中看到的客户端IP就是三个了。但是,这样就结束了么?NoNoNo,还需要简单优化一下下:
是的!我加上了keepalive相关的配置!按照猜测,应该可以轮询IP,然后访问upstream的时候,既能出现多IP,也能保持长连接。
然后我用wrk试了一下,没问题,能够满足我上面的猜测。wrk的命令如下:
wrk -t8 -c200 -d10s --latency "http://192.168.0.151"
其实,我也用curl试了下,发现访问的频率变低之后,IP始终不会变化。
后来抓包分析了下,应该和并发有关系,如果并发为1的情况,大概率会一直以某个IP进行访问,重新建联后,可能会换成别的IP。当然如果并发上去了,就会出现多个IP同时使用的情况。抓包是在192.168.0.161上进行的,命令如下:
分析抓包的数据,发现这么几个特点:
至此,我们的Nginx改造完成,并且进行了优化,完美地解决了问题!
参考资料
The text was updated successfully, but these errors were encountered: