> 技术文档 > Haproxy七层代理

Haproxy七层代理


一、负载均衡

1.什么是负载均衡 

        负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均 衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了 公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展。

2、四层负载均衡

        先通过ip+port决定负载均衡的去向。 再对流量请求进行NAT处理,转发至后台服务器。 然后记录tcp、udp流量分别是由哪台服务器处理,后续该请求连接的流量都通过该服务器处理

支持四层的软件

        lvs:重量级四层负载均衡器。

        Nginx:轻量级四层负载均衡器,可缓存。(nginx四层是通过upstream模块)

        Haproxy:模拟四层转发。

3、七层负载均衡

        七层负载均衡是通过虚拟url或主机ip进行流量识别,根据应用层信息进行解析,决定是否需要进行负载均衡。 如果需要,代理后台服务器会与客户端建立连接,如nginx可代理前后端,与前端客户端tcp连接,与后端服务器建立 tcp连接

支持7层代理的软件:

         Nginx:基于http协议(nginx七层是通过proxy_pass)

        Haproxy:七层代理,会话保持、标记、路径转移等。

4、两种负载均衡的区别

        1、分层位置不同:四层负载均衡在传输层及以下,七层负载均衡在应用层及以下

        2、性能不同:四层负载均衡架构无需解析报文消息内容,在网络吞吐量与处理能力上较高:七层可支持解析应用 层报文消息内容,识别URL、Cookie、HTTP header等信息。

        3、原理不同:四层负载均衡是基于ip+port;七层是基于虚拟的URL或主机IP等。

        4、功能类比:四层负载均衡类似于路由器;七层类似于代理服务器。

        5、安全性差异:四层负载均衡无法识别DDoS攻击;七层可防御SYN Cookie/Flood攻击

二、haproxy

1、实验环境

haproxy:172.25.254.111

RS1:172.25.254.11

RS2:172.25.254.21

在haproxy的主机中安装并启动haproxy,在realserver中安装Nginx,模拟web服务,关闭火墙

#haproxy中[root@haproxy ~]# dnf install haproxy -y[root@haproxy ~]# systemctl start haproxy#realserver中[root@RS1 ~]# dnf install nginx -y[root@RS1 ~]# echo 172.25.254.11 > /usr/share/nginx/html/index.html[root@RS1 ~]# systemctl disable --now firewalld[root@RS1 ~]# systemctl enable --now nginx

2、.global配置多进程和线程

打开haproxy的主配置文件(/etc/haproxy/haproxy.cnf)

多进程(红色)与多线程(白色)不能同时启用

3、haproxy的负载均衡简单示例

#进入主配置文件进行编辑[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg#---------------------------------------------------------------------#custom web cluster#---------------------------------------------------------------------frontend webcluster bind *:80 mode http balance roundrobin use_backend webserverbackend webserver server web1 172.25.254.11:80 server web2 172.25.254.21:80#保存退出后重启服务[root@haproxy ~]# systemctl restart haproxy.service

测试

server配置:

#针对一个server配置check  #对指定real进行健康状态检查,如果不加此设置,默认不开启检查,只有check后面没有其它配置也可以启用检查功能 #默认对相应的后端服务器IP和端口,利用TCP连接进行周期性健康性检查,注意必须指定端口才能实现健康性检查addr  #可指定的健康状态监测IP,可以是专门的数据网段,减少业务网络的流量port  #指定的健康状态监测端口inter  #健康状态检查间隔时间,默认2000 msfall  #后端服务器从线上转为线下的检查的连续失效次数,默认为3rise  #后端服务器从下线恢复上线的检查的连续有效次数,默认为2weight  #默认为1,最大值为256,0(状态为蓝色)表示不参与负载均衡,但仍接受持久连接backup #将后端服务器标记为备份状态,只在所有非备份主机down机时提供服务,类似Sorry Serverdisabled #将后端服务器标记为不可用状态,即维护状态,除了持久模式 #将不再接受连接,状态为深黄色,优雅下线,不再接受新用户的请求redirect prefix http://www.baidu.com/ #将请求临时(302)重定向至其它URL,只适用于http模式maxconn  #当前后端server的最大并发连接数

三、haproxy的算法

1、静态算法

        静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度 等,且无法实时修改权重(只能为0和1,不支持其它值),只能靠重启HAProxy生效。

1、static-rr:基于权重的轮询调度

        不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)

        不支持端服务器慢启动

        其后端主机数量没有限制,相当于LVS中的 wrr

例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg#---------------------------------------------------------------------#custom web cluster#---------------------------------------------------------------------listen webcluster bind *:80 mode http balance static-rr server web1 172.25.254.11:80 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试

2、first

        根据服务器在列表中的位置,自上而下进行调度

        其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务

        其会忽略服务器的权重设置

        不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg#---------------------------------------------------------------------#custom web cluster#---------------------------------------------------------------------listen webcluster bind *:80 mode http #balance static-rr balance first server web1 172.25.254.11:80 maxconn 1 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.servic

测试

 2、动态算法

        动态算法:基于后端服务器状态进行调度适当调整,新请求将优先调度至当前负载较低的服务器,权重可以在haproxy运行时动态调整无需重启

1、roundrobin

        基于权重的轮询动态调度算法,

        支持权重的运行时调整,不同于lvs中的rr轮训模式,

        HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数)

        其每个后端backend中最多支持4095个real server

        支持对real server权重动态调整

        roundrobin为默认调度算法,此算法使用广

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance roundrobin server web1 172.25.254.11:80 maxconn 1 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试:

2、leastconn

        leastconn加权的最少连接的动态

        支持权重的运行时调整和慢启动,即:根据当前连接最少的后端服务器而非权重进行优先调度(新客户 端连接)

        比较适合长连接的场景使用,比如:MySQL等场景。

例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance leastconn server web1 172.25.254.11:80 maxconn 1 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试:

3、其他算法

        其它算法即可作为静态算法,又可以通过选项成为动态算法

1、source

        源地址hash,基于用户源地址hash并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一 个后端web服务器。此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服 务器,默认为静态方式,但是可以通过hash-type支持的选项更改这个算法一般是在不插入Cookie的TCP 模式下使用,也可给拒绝会话cookie的客户提供最好的会话粘性,适用于session会话保持但不支持 cookie和缓存的场景源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法 和一致性hash

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance source server web1 172.25.254.11:80 maxconn 1 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试:

2、map-based

       map-based:取模法,对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此请 求转发至对应的后端服务器。此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度

        所谓取模运算,就是计算两个数相除之后的余数,10%7=3, 7%4=3

        map-based算法:基于权重取模,hash(source_ip)%所有后端服务器相加的总权重

        缺点:当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变

3、一致性hash

        一致性哈希:当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动hash(o) mod n 该hash算法是动态的,支持使用 socat等工具进行在线权重调整,支持慢启动

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance source hash-type consistent server web1 172.25.254.11:80 maxconn 1 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试结果同source

4、uri

        基于对用户请求的URI的左半部分或整个uri做hash,再将hash结果对总权重进行取模后 根据最终结果将请求转发到后端指定服务器

        适用于后端是缓存服务器场景 默认是静态算法,也可以通过hash-type指定map-based和consistent,来定义使用取模法还是一致性 hash

示例:

#在haproxy中:[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance uri hash-type consistent server web1 172.25.254.11:80 maxconn 1 weight 2 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 weight 1 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service#在realserver中模拟web服务[root@RS1 ~]# echo RS1 172.25.254.11 index1 > /usr/share/nginx/html/index1.html[root@RS1 ~]# echo RS1 172.25.254.11 index2 > /usr/share/nginx/html/index2.html[root@RS1 ~]# echo RS1 172.25.254.11 index3 > /usr/share/nginx/html/index3.html

测试:

5、url_param

        url_param对用户请求的url中的 params 部分中的一个参数key对应的value值作hash计算,并由服务器 总权重相除以后派发至某挑出的服务器,后端搜索同一个数据会被调度到同一个服务器,多用与电商 通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server 如果无没key,将按roundrobin算法

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance url_param name hash-type consistent server web1 172.25.254.11:80 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试:name改变,访问也会改变

5、hdr

        针对用户每个http头部(header)请求中的指定信息做hash, 此处由 name 指定的http首部将会被取出并做hash计算, 然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度。

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance hd(User-Agent) hash-type consistent server web1 172.25.254.11:80 check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

测试:User-Agent 改变,访问的web也会改变

四、高级功能及配置

1、基于cookie的会话保持

        cookie value:为当前server指定cookie值,实现基于cookie的会话黏性,相对于基于 source 地址hash 调度算法对客户端的粒度更精准,但同时也加大了haproxy负载,目前此模式使用较少, 已经被session 共享服务器代替

        注意:不支持 tcp mode,使用 http mode

示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance roundrobin hash-type consistent #  名字 插入新的cookie 不允许中间缓存器缓存cookie 如果客户端已经有cookie,则不会再发送cookie信息 cookie WEBCOOKIE insert nocache  indirect server web1 172.25.254.11:80 cookie servera check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 cookie serverb check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

验证cookie信息

2、haproxy状态页 

1、配置状态页

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode http balance roundrobin hash-type consistent cookie WEBCOOKIE insert nocache indirect server web1 172.25.254.11:80 cookie servera check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 cookie serverb check inter 3s fall 3 rise 5listen haproxystatus mode http bind *:8888 #端口号 stats refresh 1 #自动刷新 stats enable log global stats uri /status stats auth zcx:zcx #账号密码[root@haproxy ~]# systemctl restart haproxy.service

测试:

3、ip透传

 1、四层IP透传

        web服务器中需要记录客户端的真实IP地址,用于做访问统计、安全防护、行为分析、区域排行等场景

       未开启四层代理时,访问haproxy

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfglisten webcluster bind *:80 mode tcp balance roundrobin hash-type consistent cookie WEBCOOKIE insert nocache indirect server web1 172.25.254.11:80 cookie servera send-proxy check inter 3s fall 3 rise 5 server web2 172.25.254.21:80 cookie serverb send-proxy check inter 3s fall 3 rise 5[root@haproxy ~]# systemctl restart haproxy.service

         在此日志中是无法看到真实访问源地址的

开启四层代理:

        nginx 配置:在realserver访问日志中通过变量$proxy_protocol_addr 记录透传过来的客户端IP

能看见访问的ip 

 2、七层ip透传

        在haproxy主配置文件的listen中加入   option forwardfor  即可

4、ACL

        ACL:访问控制列表(ACL,Access Control Lists)是一种基于包过滤的访问控制技术,它可以根据设定的条件对经过服务器传输的数据包进行过滤(条件匹配),即对接收到的报文进行匹配和过滤,基于请求报文头部中的源地址、源端口、目标地址、目标端口、请求方法、URL、文件后缀等信息内 容进行匹配并执行进一步操作,比如允许其通过或丢弃。

1、启动一台client,加入本地解析

acl匹配规范

acl       [flags]     [operator]   []acl     名称     匹配规范       匹配模式     具体操作符   操作对象类型

 acl配置

frontend webserver bind *:80 mode http #use_backend webserver  #访问后端 #acl test hdr_dom(host) -i www.zcx.org #hdr_dom(host)为域名匹配,-i 表示不区分大小写 #acl test path_end -m sub /a #请求的URL中资源的结尾, -m为模糊搜索, sub /a 表示包含a的 acl test hdr_end(host) -i .com .net .cn #域名匹配以 .com .net .cn 结尾的 #acl badagent hdr_sub(User-Agent) -i wget #在hdr中匹配包含User-Agent的字段,禁止使用wget命令 #acl badsrc src 172.25.254.31 #基于原地址访问,acl名字是badsrc,来源于172.25.254.31 acl acceptsrc src 172.25.254.31 use_backend webservera if test #符合test的acl条件时访问servera default_backend webserverb #不符合上面访问的方法时,默认访问serverb #http-request deny if badagent #拒绝badagent的访问 #http-request deny if badsrc #http-request deny if ! acceptsrc #拒绝非acceptsrc的访问 #http-request deny if acceptsrc || test #拒绝acceptsrc或test的访问 http-request deny if acceptsrc test #拒绝来源acceptsrc是test的访问backend webservera balance roundrobin server web1 172.25.254.11:80 check inter 5s fall 3backend webserverb server web2 172.25.254.21:80 check inter 5s fall 3

访问时用client访问haproxy即可

示例:ACL企业应用示例

基于源地址的访问控制

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfgfrontend webserver bind *:80 mode http acl ch_ip src 172.25.254.31 172.168.0.0/24 use_backend webservera if ch_ip default_backend webserverbbackend webservera balance roundrobin server web1 172.25.254.11:80 check inter 5s fall 3backend webserverb server web2 172.25.254.21:80 check inter 5s fall 3[root@haproxy ~]# systemctl restart haproxy.service

测试:在172.25.254.1上为serverb

在172.25.254.31上为servera

 

匹配浏览器类型

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfgfrontend webserver bind *:80 mode http acl ch_ip src 172.25.254.31 172.168.0.0/24 acl user_agent_black hdr_sub(User-Agent) -i curl wget use_backend webservera if ch_ip default_backend webserverb http-request deny if user_agent_black #curl浏览器和wget命令都不可以访问172.25.254.111backend webservera balance roundrobin server web1 172.25.254.11:80 check inter 5s fall 3 backend webserverb server web2 172.25.254.21:80 check inter 5s fall 3[root@haproxy ~]# systemctl restart haproxy.service

测试:

基于文件后缀实现动静分离:

在realserver中安装php

[root@RS1 ~]# dnf install php -y[root@RS1 ~]# vim /usr/share/nginx/html/index.php[root@RS1 ~]# systemctl restart nginx.service

 编辑haproxy

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfgfrontend webserver bind *:80 mode http acl url_php    path_end -i .php acl url_static path_end -i .jpg .png .css .js .html use_backend webservera if url_php use_backend webserverb if url_static default_backend defaultclusterbackend webservera balance roundrobin server web1 172.25.254.11:80 check inter 5s fall 3 backend webserverb server web2 172.25.254.21:80 check inter 5s fall 3#须有8080端口,且有内容backend defaultcluster server web2 172.25.254.111:8080 check inter 5s fall 3[root@haproxy ~]# systemctl restart haproxy.service

测试:

 5、自定义错误页面

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfgdefaults mode  http log  global option  httplog option  dontlognull option http-server-close option forwardfor except 127.0.0.0/8 option  redispatch retries  3 timeout http-request 10s timeout queue  5s timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check  10s maxconn  3000 errorfile 503 /etc/haproxy/errorpage/503.httpfrontend webserver bind *:80 mode http backend webserver balance roundrobinbackend webservera server web1 172.25.254.11:80 check inter 5s fall 3 server web2 172.25.254.21:80 check inter 5s fall 3[root@haproxy ~]# systemctl restart haproxy.service

创建错误页面,当nginx宕机时出现错误页面

[root@haproxy ~]# mkdir -p /etc/haproxy/errorpage[root@haproxy ~]# vim /etc/haproxy/errorpage/503.httpHTTP/1.0 503 Service UnavailableCache-Control: no-cacheConnection: closeContent-Type: text/html;charset=UTF-8

什么动物生气最安静

大猩猩!!

6、haproxy四层负载

在后端服务器中安装mariadb-server,编辑其主配置文件并授权数据库的所有库和表

[root@RS1 ~]# dnf install mariadb-server -y[root@RS1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf[mysqld]server-id=1[root@RS1 ~]# systemctl start mariadb[root@RS1 ~]# mysql -e \"grant all on *.* to zcx@\'%\' identified by \'zcx\';\"

修改haproxy主配置文件

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfgfrontend webserver bind *:80 mode http backend webserver balance roundrobinbackend webservera server web1 172.25.254.11:80 check inter 5s fall 3 server web2 172.25.254.21:80 check inter 5s fall 3listen sqlcluster bind *:3306 mode tcp balance leastconn server mysql1 172.25.254.11:3306 check server mysql2 172.25.254.21:3306 check[root@haproxy ~]# systemctl restart haproxy.service

测试:

7、HAProxy https 实现

制作证书:

[root@haproxy ~]# mkdir /etc/haproxy/certs/[root@haproxy ~]# openssl req -newkey rsa:2048 \\ -nodes -sha256 –keyout /etc/haproxy/certs/timinglee.org.key \\ -x509 -days 365 -out /etc/haproxy/certs/timinglee.org.crt#查看证书[root@haproxy ~]# ls /etc/haproxy/certs/zcx.org.crt zcx.org.key#将证书放进同一个文件中[root@haproxy certs]# cat zcx.org.crt zcx.org.key > zcx.org.pem

配置haproxy文件

frontend webcluster-80 bind *:80 mode http balance roundrobin redirect scheme https if !{ ssl_fc } use_backend webserverfrontend webcluster-443 bind *:443 ssl crt /etc/haproxy/certs/zcx.pem mode http balance roundrobin use_backend webserverbackend webserver server web1 172.25.254.11:80 check inter 3s fall 3 rise 2 server web2 172.25.254.21:80 check inter 3s fall 3 rise 2

测试: