四层负载均衡
所谓四层就是OSI模型的传输层, 主要是基于tcp/ip的负载均衡模式,即基于ip和端口的方式实现将请求转发至后端节点。 常用场景 1)实现tcp协议的负载均衡 例:对后端服务MySQL从库、以及Redis等服务的负载。 纯粹基于四层的Web应用无法满足当下的负载均衡需求,中小企业直接会选择基于7层的负载均衡模式(nginx proxy)。 见数据库集群架构 2)四层+七层负载均衡架构 在Web前端的7层负载均衡之前,架设四层负载均衡以实现大规模高并发集群架构访问。 四层负载均衡专注于tcp请求的转发,把更复杂的调度(例如:动静分离、业务分离、根据来源设备调度等)交给7层负载均衡处理。 (见大规模集群架构) 3)如果7层负载业务能够拆分成不同的域名对应的业务,流量拆分,就可以直接用七层。
L4和L7的区别及常用软件。
面试题:L4和L7的区别 Layer4 tcp负载均衡 lvs、nginx、haproxy,nginx从1.9.2才支持四层负载。 四层优缺点: 1)基于tcp/ip,即IP+端口的负载均衡 2)四层更快:特别是lvs负载均衡,在内核空间处理,不用走用户空间。处理速度更快 3)四层适合大型站点,处于网站接入层最前端,结合四层+七层使用 (四层放在最前面专注做数据转发,后面可以用七层来继续处理更复杂的业务。一般是结合使用) 4)目前主要应用在后端tcp业务的负载,例如mysql,redis,k8s集群,数据库集群,应用服务器集群。 七层Layer7优缺点: 1)基于应用层http/https的负载均衡,实现开源软件有nginx、haproxy、F5(硬件) 2)七层功能更多:经内核空间进入用户空间的应用层进行转发。 3)可以实现更复杂的负载均衡控制,比如基于url、session、动静分离等。 4)会占用更多的CPU、内存资源,承载的并发比四层更少。 5)七层适合中小站点Web服务,只使用七层负载均衡
lvs、nginx、haproxy区别
LVS优点: 1.基于四层负载,并通过【转发】请求给后端节点实现负载功能。 5万并发,真正的5万并发。 2.内核级转发,效率极高。 3.四种负载模式NAT,DR,TUN,FULLNAT, 其中DR\TUN模式实现单臂路由及数据包返回用户,不在经过负载均衡器本身。 4.DR模式是其常用负载模式。 5.更完善的高可用支持(keepalived)。 LVS缺点: 1.只支持四层负载转发,不能实现基于URL7层转发能功能。 2.最常用的DR模式不支持端口转换功能。 2.nginx和haproxy优点 1.基于四层负载,并通过【代理】代替用户请求后端节点实现负载功能。 2.负载服务器占用双倍连接,并且数据返回依然会经过负载均衡器(收费站模式)。 3.既可以实现四层负载,还可以实现7层负载。 4.还可以实现web服务及缓存功能(nginx专有,haproxy仅专注于代理) 5.nginx作为Web和7层负载更流行(使用的人更多) nginx和haproxy缺点: 1.效率及并发能力不如LVS,代理模式。 2.nginx四层负载太新(近几年才开发出来。)。 3.haproxy做负载更专业,但没有nginx在web上使用更流行。 企业中到底如何选择? 1.需要四层负载且高并发(3万以上),选LVS,否则就选nginx或haproxy。 2.nginx有web服务及缓存功能及4和7层负载功能,且配置简单(常规选Nginx)。 3.haproxy仅专注于负载均衡,在负载算法和健康检查等好于nginx,但不足以让普通用户选择。
nginx四层负载均衡(tcp/ip,ip:port)
扩展作业:haproxy负载搞定 通过ip:port实现负载均衡 Nginx负载形式,基于【代理】的方式,而非转发的模式。 场景1: 基于四层IP+端口代理 场景2: 四层结合七层(实现4,7层由不同的负载均衡器调度) LVS负载形式,基于【转发】请求方式(内核级别转发) 场景1: 基于四层(NAT\DR\tun\fullnat)转发 场景2: 四层+七层实现大规模高并发集群场景
nginx四层负载均衡实现主要就是stream模块
1)stream模块官方说明: http://nginx.org/en/docs/stream/ngx_stream_core_module.html#stream The ngx_stream_core_module module is available since version 1.9.0. This module is not built by default, it should be enabled with the --with-stream configuration parameter. 2)检查nginx支持--with-stream情况 nginx -V 2>oldboy.log egrep '\-\-with-stream' oldboy.log 3)学员博客: https://www.cnblogs.com/gongjingyun123--/p/11424424.html 4)stream模块语法 Syntax: stream { ... } Default: — Context: main
nginx四层负载均衡实践:
1)环境 lb4-01 10.0.0.15 lb4-02 10.0.0.16 2)安装nginx+keepalived 3)生产场景1:实现MySQL数据库负载均衡 四层代理:10.0.0.15 172.16.1.15 DB节点:172.16.1.7 172.16.1.51 步骤: 1.克隆10.0.0.15 2.检查负载的节点正常172.16.1.7 172.16.1.51 3.配置lb4-01 10.0.0.15 4.测试 [root@lb4-01 ~]# vim /etc/nginx/nginx.conf +12 注意要在http标签外面加上如下几行 stream { include /etc/nginx/stream_conf.d/*.conf; } mkdir /etc/nginx/stream_conf.d/ [root@lb4-01 nginx]# cd /etc/nginx/stream_conf.d/ [root@lb4-01 stream_conf.d]# cat 01_lb4-mysql.conf upstream mysql{ server 172.16.1.51:3306; server 172.16.1.7:3306; #开启mariadb } server { listen 3306; #监听的机器本地不能有3306端口。 proxy_pass mysql; } nginx -t systemctl restart nginx 注意:此场景用于代理各类tcp应用,比如,k8s集群,数据库集群,中间件应用服务器集群。 注意: 1.nginx.conf里不允许多个stream标签。 2.stream标签配置为主配置文件nginx.conf main区段。 3.可以在主配置的stream标签里嵌入include /etc/nginx/stream_conf.d/*.conf; 4.nginx.conf 里的 include /etc/nginx/conf.d/*.conf; 这个要注释掉,不然跟stream 80冲突,要不然stream里的80通过10.0.0.15:80监听 #安装Navicat for MySQL或使用Phpmyadmin进行测试
场景2:实现nginx4层+Nginx多七层代理+多Web节点
大并发: www:10.0.0.15-----10.0.0.5/10.0.0.6----->172.16.1.7/172.16.1.7 不需要高并发:blog:10.0.0.5/10.0.0.6----->172.16.1.7/172.16.1.7 四层代理:10.0.0.15 172.16.1.15 四层代理:10.0.0.16 172.16.1.16 L7层代理:172.16.1.5 172.16.1.5 L7层代理:172.16.1.6 172.16.1.6 Web节点:172.16.1.7 172.16.1.8 ==1)四层负载均衡(lb4-01) 10.0.0.15: 完整配置如下: [root@lb4-01 stream_conf.d]# cat 02_web.conf upstream proxy_7 { server 10.0.0.5:80; server 10.0.0.6:80; } server { listen 80; proxy_pass proxy_7; #注意,不带HTTP。 #proxy_protocol on; #开启proxy_protocol协议 } 注意别忘了: 1.stream里的监听80端口不能和7层的监听80冲突。 因此,注释结尾 #include /etc/nginx/conf.d/*.conf; 2.指定VIP listen 10.0.0.17:80; nginx -t systemctl restart nginx
七层负载均衡(lb01,lb02)
[root@lb01 conf.d]# cat 03_www.etiantian.org.conf upstream www { server 172.16.1.7 weight=1 ; #默认80端口 server 172.16.1.8 weight=1; #默认80端口 } server { listen 80; server_name www.etiantian.org; location / { proxy_pass http://www; proxy_set_header Host $http_host; } } nginx -t systemctl restart nginx [root@lb02 conf.d]# cat 03_www.etiantian.org.conf upstream www { server 172.16.1.7 weight=1 ; #默认80端口 server 172.16.1.8 weight=1; #默认80端口 } server { listen 80; server_name www.etiantian.org; location / { proxy_pass http://www; proxy_set_header Host $http_host; } } nginx -t systemctl restart nginx
部署web01,web02
[root@lb01 conf.d]# curl -H"host:www.etiantian.org" 172.16.1.7 web01 [root@lb01 conf.d]# curl -H"host:www.etiantian.org" 172.16.1.8 web02 [root@web02 conf.d]# cat 02_www.etiantian.org.conf server { listen 80; server_name www.etiantian.org; root /data/www; location / { index index.html; } }
必要测试步骤;测试早前配置的7层代理情况
[root@lb4-01 nginx]# curl -H"host:www.etiantian.org" 10.0.0.5 web01 [root@lb4-01 nginx]# curl -H"host:www.etiantian.org" 10.0.0.5 web02 [root@lb4-01 nginx]# curl -H"host:www.etiantian.org" 10.0.0.6 web01 [root@lb4-01 nginx]# curl -H"host:www.etiantian.org" 10.0.0.6 web02 测试L4(15)---L7(5,6)--->Web(7,8) [root@web02 conf.d]# curl -H"host:www.etiantian.org" 10.0.0.15 web01 [root@web02 conf.d]# curl -H"host:www.etiantian.org" 10.0.0.15 web01 [root@web02 conf.d]# curl -H"host:www.etiantian.org" 10.0.0.15 web02 [root@web02 conf.d]# curl -H"host:www.etiantian.org" 10.0.0.15 web02
场景3:实现nginx4层+Nginx多七层代理+多Web节点【获取真实用户IP地址】
四层负载均衡 http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_protocol 开启proxy_protocol协议 proxy_protocol on; 语法 Syntax: proxy_protocol on | off; Default: proxy_protocol off; Context: stream, server This directive appeared in version 1.9.2. Enables the PROXY protocol for connections to a proxied server. http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
https://www.nixops.me/articles/PROXY_protocol_pass_client_ip.html 使用PROXY protocol获取客户IP 8月 29日, 2017年 获取客户IP是常见的需求,对于大流量的项目都会使用反向代理、负载均衡等,甚至多重代理,导致架构和网络都比较复杂,在这种情况下获取IP就不那么容易了。七层代理可以通过添加头信息来实现,如http协议的X-Forword-For,还比较方便;四层代理基本无法简单的获取到客户端IP地址,像LVS的FULLNAT模式,前端LVS把真实IP写在TCP option里面,后端服务器用内核toa模块获取客户IP;haproxy配合TPROXY也是类似的方式实现,两者都需编译内核非常麻烦,这种情况下就可以考虑使用代理协议 一、代理协议简介 代理协议即 PROXY protocol,是haproxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取客户IP时非常有用。如: 多层NAT网络 TCP代理(四层)或多层tcp代理 https反向代理http(某些情况下由于Keep-alive导致不是每次请求都传递x-forword-for) 代理协议分为v1和v2两个版本,v1人类易读,v2是二进制格式,方便程序处理。Proxy protocol是比较新的协议,但目前已经有很多软件支持,如haproxy、nginx、apache、squid、mysql等等,要使用proxy protocol需要两个角色sender和receiver,sender在与receiver之间建立连接后,会先发送一个带有客户信息的tcp header,因为更改了tcp协议,需receiver也支持proxy protocol,否则不能识别tcp包头,导致无法成功建立连接。
#配置开启proxy_protocol,lb4-01(10.0.0.15) [root@lb4-01 stream_conf.d]# cat 02_web.conf upstream proxy_7 { server 172.16.1.5:80; server 172.16.1.6:80; } server { listen 80; proxy_pass proxy_7; #注意,不带HTTP。 proxy_protocol on; #开启proxy_protocol协议================== } nginx -t systemctl reload nginx #七层负载均衡(lb01,lb02)10.0.0.5/6 upstream www { server 172.16.1.7:80; server 172.16.1.8:80; } server { listen 80 proxy_protocol; #添加proxy_protocol server_name www.etiantian.org; set_real_ip_from 172.16.1.0/24; #添加七层负载前经过的代理IP地址 real_ip_header proxy_protocol; #将proxy_protocol获取的IP赋值给$remote_addr location / { proxy_pass http://www; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_protocol_addr; #将proxy_protocol真实客户端的IP地址赋值给X-Forwarded-For变量携带至后端 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ##不加下面两条,可能会报错nginx: [warn] could not build optimal proxy_headers_hash, you should increase either proxy_headers_hash_max_size: 512 #or proxy_headers_hash_bucket_size: 64; ignoring proxy_headers_hash_bucket_size proxy_headers_hash_max_size 51200; proxy_headers_hash_bucket_size 6400; } } 测试 [root@web01 nginx]$tail -f /var/log/nginx/access.log 172.16.1.5 - - [26/Dec/2022:16:38:25 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "10.0.0.1, 10.0.0.15" 172.16.1.5 - - [26/Dec/2022:16:38:26 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "10.0.0.1, 10.0.0.15" 172.16.1.5 - - [26/Dec/2022:16:38:27 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "10.0.0.1, 10.0.0.15" 最后面显示用户真实和代理ip"10.0.0.1, 10.0.0.15"
Nginx多级代理,获取客户端真实请求ip以及每级代理ip
https://blog.csdn.net/simonchi/article/details/53944308
haproxy + nginx + proxy protocol 获得客户真实IP方法
https://www.cnblogs.com/hh2737/p/8951872.html
测试众多nginx http变量值
[root@web01 conf.d]# cat 02_www.etiantian.org.conf server { listen 80; server_name www.etiantian.org; root /data/www; location / { #index index.html; return 200 "web01,老男孩Linux77最优班级\n remote_addr: $remote_addr\n proxy_add_x_forwarded_for:$proxy_add_x_forwarded_for\n proxy_protocol_addr: $proxy_protocol_addr\n http_x_forwarded_for:$http_x_forwarded_for\n"; } }
从DB01访问:10.0.0.51---10.0.0.15----172.16.1.5----172.16.1.7
[root@db01 ~]# curl -H"host:www.etiantian.org" 10.0.0.15 web01,老男孩Linux77最优班级 remote_addr: 172.16.1.5 proxy_add_x_forwarded_for:10.0.0.51, 172.16.1.5 http_x_forwarded_for:10.0.0.51 更改web01主配置日志测试: log_format access '-$proxy_protocol_addr-,--$remote_addr--,---$http_x_forwarded_for---,----$proxy_add_x_forwarded_for----,$remote_user,$time_local,$host,$request,$status,$http_referer,$HTTP_X_UP_CALLING_LINE_ID,$request_time,$http_user_agent $upstream_addr $upstream_response_time $upstream_cache_status'; access_log /var/log/nginx/access.log access; ---,--172.16.1.5--,---10.0.0.51, 10.0.0.15---,----10.0.0.51, 10.0.0.15, 172.16.1.5---- -$proxy_protocol_addr-,--$remote_addr--,---$http_x_forwarded_for---,----$proxy_add_x_forwarded_for----
日志结果:
[root@web01 conf.d]# tail /var/log/nginx/access.log ---,--172.16.1.5--,---10.0.0.51---,----10.0.0.51, 172.16.1.5----,-,01/Aug/2021:17:17:29 +0800,www.etiantian.org,GET / HTTP/1.0,200,-,-,0.000,curl/7.29.0 - - - ---,--172.16.1.5--,---10.0.0.51---,----10.0.0.51, 172.16.1.5----,-,01/Aug/2021:17:17:31 +0800,www.etiantian.org,GET / HTTP/1.0,200,-,-,0.000,curl/7.29.0 - - - nginx多层代理获取客户端的真实ip总结: 1、要有http_realip_module模块支持 2、在nginx.conf文件中 proxy_pass http://www; #添加下面三行 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 3、在每一层nginx日志中的打印的"$http_x_forwarded_for"就是真实客户端的ip地址。 4、后台服务器获取真实的客户端ip地址: headers中的X-Forwarded-For选项中逗号前第一个ip就是真实客户端ip 日志中获取真实ip: $http_x_forwarded_for 就是获取真实ip的变量 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; 提示: 1、set_real_ip_from 是指接受从哪个信任前代理处获得真实用户ip 2、real_ip_header 是指从接收到报文的哪个http首部去获取前代理传送的用户ip 3、real_ip_recursive 是否递归地排除直至得到用户ip(默认为off) 首先,real_ip_header 指定一个http首部名称,默认是X-Real-Ip,假设用默认值的话,nginx在接收到报文后,会查看http首部X-Real-Ip。 (1)如果有1个IP,它会去核对,发送方的ip是否在set_real_ip_from指定的信任ip列表中。如果是被信任的,它会去认为这个X-Real-Ip中的IP值是前代理告诉自己的,用户的真实IP值,于是,它会将该值赋值给自身的$remote_addr变量;如果不被信任,那么将不作处理,那么$remote_addr还是发送方的ip地址。 (2)如果X-Real-Ip有多个IP值,比如前一方代理是这么设置的:proxy_set_header X-Real-Ip $proxy_add_x_forwarded_for; 得到的是一串IP,那么此时real_ip_recursive的值就至关重要了。nginx将会从ip列表的右到左,去比较set_real_ip_from 的信任列表中的ip。 如果real_ip_recursive为off,那么,当最右边一个IP,发现是信任IP,即认为下一个IP(右边第二个)就是用户的真正IP; 如果real_ip_recursive为on,那么将从右到左依次比较,知道找到一个不是信任IP为止。 然后同样把IP值复制给$remote_addr。
http_proxy_module相关参数
相关重要参数 参数说明 proxy_pass http://server_pools; 通过proxy_pass功能把用户的请求转向到反向代理定义的upstream服务器池 proxy_set_header Host $host; 在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时,可以识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置 proxy_set_header X-Forwarded-For $remote_addr; 在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序、日志等接收记录真实用户的IP,而不是代理服务器IP。 这是反向代理时,节点服务器获取用户真实IP的必要功能配置 [root@web02 conf.d]# tail -f /var/log/nginx/access.log 172.16.1.5 - - [02/Aug/2021:16:45:59 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-" 172.16.1.5 - - [02/Aug/2021:16:46:00 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-" log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; 结果: $remote_addr 172.16.1.5 $http_x_forwarded_for - 3. 经过7层反向代理后的节点服务器记录用户IP企业案例 [root@lb01 conf.d]# cat 03_www.etiantian.org.conf upstream www { server 172.16.1.7 weight=1 ; #默认80端口 server 172.16.1.8 weight=1; #默认80端口 } server { listen 80; server_name www.etiantian.org; location / { proxy_pass http://www; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $remote_addr; <==在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序、日志等接收记录真实用户的IP,而不是代理服务器的IP。 } } [root@lb01 conf.d]# nginx -t [root@lb01 conf.d]# systemctl restart nginx 测试:使用DB01或者浏览器测试 [root@db01 ~]# curl -H"host:www.etiantian.org" 172.16.1.5 web01 [root@db01 ~]# curl -H"host:www.etiantian.org" 172.16.1.5 web02 [root@web02 conf.d]# tail -f /var/log/nginx/access.log 172.16.1.5 - - [02/Aug/2021:16:45:59 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-" 172.16.1.5 - - [02/Aug/2021:16:46:00 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-" 172.16.1.5 - - [02/Aug/2021:16:51:21 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "172.16.1.5" 172.16.1.5 - - [02/Aug/2021:16:51:52 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "172.16.1.51" 172.16.1.5 - - [02/Aug/2021:16:52:23 +0800] "GET /favicon.ico HTTP/1.0" 404 555 "http://www.etiantian.org/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "10.0.0.1" 172.16.1.5 - - [02/Aug/2021:16:52:25 +0800] "GET /favicon.ico HTTP/1.0" 404 555 "http://www.etiantian.org/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "10.0.0.1" 172.16.1.5 - - [02/Aug/2021:16:52:28 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "10.0.0.1" 172.16.1.5 - - [02/Aug/2021:16:52:28 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "10.0.0.1" 看结尾$http_x_forwarded_for列如果出现访问的客户的真实IP就对了 浏览器访问的结果,真实IP是10.0.0.1,如果通过db01访问真实IP就是172.16.1.51 结果: $remote_addr依然是172.16.1.5,上级代理IP $http_x_forwarded_for 10.0.0.1 nginx反向代理的若干参数说明: fastcgi_pass http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html proxy_pass http://nginx.org/en/docs/http/ngx_http_proxy_module.html uwsgi_pass http://nginx.org/en/docs/http/ngx_http_uwsgi_module.html 扩展:搭建nginx cache服务 作为静态web服务的前端缓存。 https://blog.csdn.net/dengjiexian123/article/details/53386586