企业服务架构图及负载均衡的要求
场景说明
• 在企业生产环境中,每天会有很多的需求变更,比如增加服务器、新业务上线、url路由修改、域名配置等等,对于前端负载均衡设备来说,容易维护,复杂度低,是首选指标。在企业中,稳定压倒一切,与
其搞得很复杂,经常出问题,不如做的简单和稳定。
• 在企业中,90%以上的故障,来源于需求变更。可能是程序bug,也可能是人为故障,也可能是架构设计问题等等。
• 前端负载均衡设备为重中之重,在软件选型上一定充分考虑,能满足业务的前提下,尽可能降低复杂度,提高易维护性
小型架构图
中型架构图
公有云Web架构
私有云web架构
什么是负载均衡:
•负载均衡(Load Balance,简称LB)是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展。
•https://yq.aliyun.com/articles/1803#阿里云SLB介绍
为什么使用负载均衡:
•Web服务器的动态水平扩展
•对用户无感知
•增加业务并发访问及处理能力
•解决单服务器瓶颈问题
•节约公网IP地址
•降低IT支出成本
•隐藏内部服务器IP
•提高内部服务器安全性
•配置简单
•固定格式的配置文件
•功能丰富
•支持四层和七层,支持动态下线主机
•性能较强
•并发数万甚至数十万
常见有哪些负载均衡:
•软件负载:
•四层:
•LVS(Linux Virtual Server) •HAProxy(High Availability Proxy) •Nginx() •……
•七层:
•HAProxy •Nginx •……
•硬件负载:
•F5 •Netscaler •……
典型应用场景:
•应用场景:
•四层:Redis、Mysql、RabbitMQ、Memcache等
•七层:Nginx、Tomcat、Apache、PHP、图片、动静分离、API等
四层和七层负载均衡的区别
四层:
通过分析IP层及TCP/UDP层的流量实现的基于"IP+端口"的负载均衡。
七层:
可以根据内容,再配合负载均衡算法来选择后端服务器,不但可以根据"ip+端口"方式进行负载分流,还可以根据网站的URL,访问域名,浏览器类别,语言等决定负载均衡的策略。七层负载均衡模式下,负载均衡与客户端及后端的服务器会分别建立一次TCP连接,而在四层负载均衡模式下(DR),仅建立一次TCP连接;七层负载均衡对负载均衡设备的要求更高,处理能力也低于四层负载均衡。
Haproxy介绍
1、简单介绍
•HAProxy: 是法国人Willy Tarreau开发的一个开源软件,是一款应对客户端10000以上的同时连接的高性能的TCP和HTTP负载均衡器。其功能是用来提供基于cookie的持久性,基于内容的交换,过载保护的高级流量管制,自动故障切换,以正则表达式为基础的控制运行时间,基于Web的报表,高级日志记录以帮助排除故障的应用或网络及其他功能。
•LB Cluster:
四层:lvs, nginx(stream),haproxy(mode tcp)
七层:http: nginx(http), haproxy(mode http), httpd...
•官网:
http://www.haproxy.org
https://www.haproxy.com
•文档:https://cbonte.github.io/haproxy-dconv/
2、定义
(1)HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高性能性、负载均衡,以及基于TCP和HTTP的应用程序代理。相较与 Nginx,HAProxy 更专注与反向代理,因此它可以支持更多的选项,更精细的控制,更多的健康状态检测机制和负载均衡算法。
(2)HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
(3)包括 GitHub、Bitbucket、Stack Overflow、Reddit、Tumblr、Twitter在内众多知名网站,及亚马逊网络服务系统都使用了HAProxy
3、HAProxy功能
•HAProxy是TCP / HTTP反向代理服务器,尤其适合于高可用性高并发环境
•可以针对HTTP请求添加cookie,进行路由后端服务器
•可平衡负载至后端服务器,并支持持久连接
•支持基于cookie进行调度
•支持所有主服务器故障切换至备用服务器
•支持专用端口实现监控服务
•支持不影响现有连接情况下停止接受新连接请求
•可以在双向添加,修改或删除HTTP报文首部
•支持基于pattern实现连接请求的访问控制
•通过特定的URI为授权用户提供详细的状态信息
•历史版本更新功能:1.4 1.5 1.6 1.7 1.8 1.9 2.0-dev
•1.8:多线程,HTTP/2缓存……
•1.7:服务器动态配置,多类型证书……
•1.6:DNS解析支持,HTTP连接多路复用……
•1.5:开始支持SSL,IPV6,keepalived……
4、Haproxy的特性
① 可靠性与稳定性都非常出色,可与硬件级设备媲美。
② 支持连接拒绝,可以用于防止DDoS攻击
③ 支持长连接、短连接和日志功能,可根据需要灵活配置
④ 路由HTTP请求到后端服务器,基于cookie作会话绑定;同时支持通过获取指的url来检测后端服务器的状态
⑤ HAProxy还拥有功能强大的ACL支持,可灵活配置路由功能,实现动静分离,在架构设计与实现上带来很大方便
⑥ 可支持四层和七层负载均衡,几乎能为所有服务常见的提供负载均衡功能
⑦ 拥有功能强大的后端服务器的状态监控web页面,可以实时了解设备的运行状态,还可实现设备上下线等简单操作。例:cobbler、samba、httpd
⑧ 支持多种负载均衡调度算法,并且也支持session保持。
5、Haproxy安装方式
(1)Haproxy安装常用两种方式,yum安装和源码包安装
(2)yum 安装:通常是在线安装,好处是安装方式简单,不易出错;常用的安装yum源为epel
(3)源码包安装:是先将 Haproxy 的源码下载下来,在自己的系统里编译生成可执行文件,然后执行,好处是因为是在自己的系统上编译的,更符合自己系统的性能,也就是说在自己的系统上执行 Haproxy服务性能效率更好。
(4)区别:路径和启动方式不同,支持的模块也不同。
yum 安装方式:
[root@centos7~]#yum install haproxy
源码编译HAProxy:
官网下载HAProxy包,并解压包,切换到haproxy包目录下
[root@centos17haproxy-1.8.20]#tar xvf haproxy-1.8.20.tar.gz && cd haproxy-1.8.20
安装相关依赖包
[root@centos17haproxy-1.8.20]#yum install gcc gcc-c++ glibc glibc-devel pcrepcre-devel openssl openssl-devel systemd-devel net-tools vim iotopbczip unzip zlib-devellrzsztree screen lsof tcpdump wget ntpdate
开始编译
[root@centos17haproxy-1.8.20]#make ARCH=x86_64 TARGET=linux2628 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy
指定安装路径
[root@centos17haproxy-1.8.20]#make install PREFIX=/usr/local/haproxy
将可执行程序haproxy复制/usr/sbin/目录下
[root@centos17haproxy-1.8.20]#cp haproxy /usr/sbin/
创建haproxy启动脚本 vim /usr/lib/systemd/system/haproxy.service
[Unit] Description=HAProxy Load Balancer After=syslog.target network.target [Service] ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid ExecReload=/bin/kill -USR2 $MAINPID [Install] WantedBy=multi-user.target
创建启动脚本目录
[root@centos_17haproxy]#mkdir /etc/haproxy
创建haproxy服务启动目录及基本的配置文件
[root@centos_17haproxy]#vim /etc/haproxy/haproxy.cfg global maxconn 100000 chroot /usr/local/haproxy #stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin user haproxy group haproxy daemon nbproc 2 绑定两个cpu就开启下面两个,绑定四个就开启四个 cpu-map 1 0 cpu-map 2 1 #cpu-map 3 2 #cpu-map 4 3 pidfile /run/haproxy.pid log 127.0.0.1 local3 info defaults option http-keep-alive option forwardfor maxconn 100000 mode http timeout connect 300000ms timeout client 300000ms timeout server 300000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys listen web_port bind 0.0.0.0:80 mode http log global server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5
创建一个haproxy用户,并设置为系统不能登录的shell类型
[root@centos_17haproxy]#useradd -s /sbin/nologin haproxy
启动haproxy服务
[root@centos_17haproxy]#systemctl start haproxy
查看haproxy启动的线程数
[root@centos_17haproxy]#ps -ef |grep haproxy 可以看到此时用户名是nobody启动双线程,并都属于一个父进程 root 13270 1 0 21:59 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid haproxy 13272 13270 0 21:59 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid haproxy 13273 13270 0 21:59 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid root 13278 12621 0 21:59 pts/0 00:00:00 grep --color=auto haproxy
HAProxy组成
程序环境:
主程序:/usr/sbin/haproxy 配置文件:/etc/haproxy/haproxy.cfg Unit file:/usr/lib/systemd/system/haproxy.service
配置段:
global:全局配置段
进程及安全配置相关的参数 性能调整相关参数 Debug参数
proxies:代理配置段
defaults:为frontend, backend, listen提供默认配置 frontend:前端,相当于nginx中的server {} backend:后端,相当于nginx中的upstream {} listen:同时拥有前端和后端配置
简单的配置示例:在vim /etc/haproxy/haproxy.cfg配置文件中修改
frontend web bind 192.168.37.17:80 本机haproxy的IP地址 default_backend websrvs backend websrvs balance roundrobin server srv1 172.16.100.6:80 后台服务的IP地址 server srv2 172.16.100.7:80
listen用法:
listen web bind 192.168.37.17:80 server web1 192.168.37.27:80
访问网页:
Haproxy配置-global
•chroot #锁定运行目录 •deamon #以守护进程运行 •#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin #socket文件 •user, group, uid, gid #运行haproxy的用户身份 •nbproc #开启的haproxy进程数,与CPU保持一致 •nbthread #指定每个haproxy进程开启的线程数,默认为每个进程一个线程 •cpu-map 1 0 #绑定haproxy进程至指定CPU •maxconn #每个haproxy进程的最大并发连接数 •maxsslconn #SSL每个haproxy进程ssl最大连接数 •maxconnrate #每个进程每秒最大连接数 •spread-checks #后端server状态check随机提前或延迟百分比时间,建议2-5(20%-50%)之间,成百上千个后端服务器可加此选项。 •pidfile#指定pid文件路径 •log 127.0.0.1 local3 info #定义全局的syslog服务器;最多可以定义两个
自定义haproxy的log日志
1、在rsyslog.conf配置配置文件中开启log日志功能。
[root@centos_17haproxy]#vim /etc/rsyslog.conf
$ModLoad imudp 开启udp模式存放日志 $UDPServerRun 514 开启端口 local3.* /var/log/haproxy.log 存放haproxy日志路径
修改完rsyslog配置文件之后重新启动:systemctl restart rsyslog
2、在haproxyd的global全局配置文件中修改对应的local3
log 127.0.0.1 local3
配置完之后重新启动haproxy服务:systemctl restart haproxy
3、验证结果,此时修改后的配置文件中已经生成单独的log日志文件。
[root@centos_17haproxy]#tail /var/log/haproxy.log Dec 22 00:03:19 localhost haproxy[15460]: Proxy stats started. Dec 22 00:03:19 localhost haproxy[15460]: Proxy web_port started.
HAProxy Proxies配置
•defaults [<name>] #默认配置项,针对以下的frontend、backend和lsiten生效,可以多个name •frontend <name> #前端servername,类似于Nginx的一个虚拟主机server。 •backend <name> #后端服务器组,等于nginx的upstream •listen <name> #将frontend和backend合并在一起配置
注:name字段只能使用”-”、”_”、”.”、和”:”,并且严格区分大小写,例如:Web和web是完全不同的两组服务器。
Proxies配置-defaults
defaults 配置参数:
•option redispatch #当server Id对应的服务器挂掉后,强制定向到其他健康的服务器 •option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接 •option http-keep-alive 60 #开启会话保持 •option forwardfor #开启IP透传 •mode http #默认工作类型 •timeout connect 60s #转发客户端请求到后端server的最长连接时间(TCP之前) •timeout server 600s #转发客户端请求到后端服务端的超时超时时长(TCP之后) •timeout client 600s #与客户端的最长空闲时间 •timeout http-keep-alive 120s #session 会话保持超时时间,范围内会转发到相同的后端服务器 •#timeout check 5s #对后端服务器的检测超时时间
Proxies配置-frontend配置参数
•bind:指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端口,可同时用于listen字段中 •bind [<address>]:<port_range> [, ...] [param*] •mode http/tcp #指定负载协议类型 •use_backend backend_name #调用的后端服务器组名称
bind指令仅能用于frontend和listen区段,用于定义一个或几个监听的套接字。
① <address>:可选选项,其可以为主机名、IPv4地址、IPv6地址或*;省略此选项、将其指定为*或0.0.0.0时,将监听当前系统的所有IPv4地址;
② <port_range>:可以是一个特定的TCP端口,也可是一个端口范围(如5005-5010),代理服务器将通过指定的端口来接收客户端请求;需要注意的是,每组监听的套接字
③ <address:port>在同一个实例上只能使用一次,而且小于1024的端口需要有特定权限的用户才能使用,这可能需要通过uid参数来定义;
④ <interface>:指定物理接口的名称,仅能在Linux系统上使用;其不能使用接口别名,而仅能使用物理接口名称,而且只有管理有权限指定绑定的物理接口;
示例:
•frontend WEB_PORT •bind :80,:8080 •bind 192.168.7.102:10080,192.168.7.102:10043 •use_backend backend_name
Proxies配置-backend配置参数
•mode http/tcp #指定负载协议类型 •option #配置选项 •server #定义后端realserver
注意:option后面加httpchk,smtpchk, mysql-check, pgsql-check,ssl-hello-chk方法,可用于实现更多应用层检测功能。
示例:
•frontend WEB_PORT •bind :80,:8080 •bind 192.168.7.102:10080,192.168.7.102:10043 •use_backend backend_name
后端服务器状态监测及相关配置
•check #对指定real进行健康状态检查,默认不开启 •addr IP #可指定的健康状态监测IP •port num #指定的健康状态监测端口 •inter num #健康状态检查间隔时间,默认2000 ms •fall num #后端服务器失效检查次数,默认为3 •rise num #后端服务器从下线恢复检查次数,默认为2 •weight #默认为1,最大值为256,0表示不参与负载均衡 •backup #将后端服务器标记为备份状态 •disabled #将后端服务器标记为不可用状态 •redirect prefix http://www.magedu.com #将请求临时重定向至其它URL,只适用于http模式 •maxconn <maxconn>:当前后端server的最大并发连接数 •backlog <backlog>:当server的连接数达到上限后的后援队列长度
(mode http|tcp|health)设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般说来都是HTTP模式),否则将无法启动实例。可以放在任何4段中 default frontent backent listen
① tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查,通常用于SSL、SSH、SMTP等应用;
② http:实例运行于HTTP模式,7层,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;centos实际默认模式
③ health:实例工作于health模式,其对入站请求仅响应"OK"信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前来讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能;可以用于测试
示例:
listen web mode http bind 192.168.37.17:80 server web1 192.168.37.27:80 check weight 3 inter 3s fall 3 rise 5 #check后面命令是对haproxy进行状态检测 server web2 192.168.37.37:80 check inter 3s fall 3 rise 5 backup redirect prefix http://www.magedu.com 临时重定向,只适用于http模式
frontend/ backend及Proxies配置-listen配置案例
使用listen替换frontend和backend的配置方式:
#官网业务访问入口====================================== frontend WEB_PORT_80 bind 192.168.37.17:80 mode tcp use_backend web_prot_http_nodes backend web_prot_http_nodes mode http option forwardfor server 192.168.37.27:80 check inter 3000 fall 3 rise 5 server 192.168.37.37:80 check inter 3000 fall 3 rise 5 frontend WEB_PORT_443 bind 192.168.37.17:443 mode tcp use_backend web_prot_http_nodes backend web_prot_http_nodes mode http option forwardfor server 192.168.37.27:443 check inter 3000 fall 3 rise 5 server 192.168.37.37:443 check inter 3000 fall 3 rise 5 #官网业务访问入口===================================== listen WEB_PORT_80 bind 192.168.37.17:80 mode tcp option forwardfor server web1 192.168.37.17:80 check inter 3000 fall 3 rise 5 server web2 192.168.37.27:80 check inter 3000 fall 3 rise 5 listen WEB_PORT_443 bind 192.168.37.17:443 mode tcp option forwardfor server web1 192.168.37.27:443 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:443 check inter 3000 fall 3 rise 5
HAProxy 调度算法
balance:指明对后端服务器的调度算法,配置在listen或backend
静态算法:按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、链接数和相应速度等,且无法实时修改权重,只能重启后生效。
•static-rr:基于权重的轮询调度,不支持权重的运行时调整及后端服务器慢启动,其后端主机数量没有限制
•first:根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置。
first示例:
#官网业务访问入口===================================== listen WEB_PORT_80 bind 192.168.37.17:80 balance first mode tcp option forwardfor server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
测试效果,先只会访问第一台服务器,当达到最大连接数,才会访问到第二台服务器。
动态算法:基于后端服务器状态进行调度适当调整,比如优先调度至当前负载较低的服务器,且权重可以在haproxy运行时动态调整无需重启。
roundrobin:基于权重的轮询动态调度算法,支持权重的运行时调整,不等于lvs 的rr,支持慢启动即新加的服务器会逐渐增加转发数,每个后端backend中最多支持4095个server,此为默认调度算法,server 权重设置weight。
leastconn:加权的最少连接的动态,支持权重的运行时调整和慢启动,即当前后端服务器连接最少的优先调度,比较适合长连接的场景使用,比如MySQL等场景,其并不太适用于较短会话的应用层协议。
roundrobin示例:
listen WEB_PORT_80 bind 192.168.37.17:80 #balance first balance roundrobin 默认是此算法 mode tcp option forwardfor server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
hash 算法
source:源地址hash,基于用户源地址hash并将请求转发到后端服务器,默认为静态即取模方式,但是可以通过hash-type支持的选项更改,后续同一个源地址请求将被转发至同一个后端web服务器,比较适用于session保持/缓存业务等场景,用法不多。
•map-based:取模法,基于服务器权重的hash数组取模,该hash是静态的即不支持在线调整权重,不支持慢启动,其对后端服务器调度均衡,缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因权重发生变化而导致调度结果整体改变,hash(o)mod n(其中n代表是有几个权重)。
1、source:源地址hash,基于用户源地址hash并将请求转发到后端服务器,默认为静态即取模方式,但是可以通过hash-type支持的选项更改,后续同一个源地址请求将被转发至同一个后端web服务器,比较适用于session保持/缓存业务等场景。
2、consistent:一致性哈希,该hash是动态的,支持在线调整权重,支持慢启动,优点在于当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动。
listen web_prot_http_nodes bind 192.168.7.101:80 mode http balance source hash-type consistent log global option forwardfor server 192.168.7.101 192.168.7.101:8080 check inter 3000 fall 3 rise 5 server 192.168.7.102 192.168.7.102:8080 check inter 3000 fall 3 rise 5
3、uri:基于对用户请求的uri做hash并将请求转发到后端指定服务器,适用于后端缓存服务器
对URI 的左半部分或整个uri 做hash 计算,并除以服务器总权重取模
左半部分:/<path>;<params>
整个uri :/<path>;<params>?<query>#<frag>
map-based:取模法 consistent:一致性哈希 http://example.org/absolute/URI/with/absolute/path/to/resource.txt #URI/URL ftp://example.org/resource.txt #URI/URL /relative/URI/with/absolute/path/to/resource.txt #URI
uri: uniform resource identifier,统一资源标识符,是一个用于标识某一互联网资源名称的字符串
示例:
listen WEB_PORT_80 bind 192.168.37.17:80 #balance first #balance source #hash-type consistent balance uri mode http option forwardfor server web1 192.168.37.27:80 check weight 3 inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
测试效果,访问指定的uri路径文件:
[root@centos_17~]#curl http://192.168.37.17/app/test1.html 192.168.37.37 RS1
4、url_param:
对用户请求的url中的<params>部分中的参数name作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server
假设url= http://www.magedu.com/foo/bar/index.php?k1=v1&k2=v2
则:
host = "www.magedu.com"
url_param= "k1=v1&k2=v2"
listen WEB_PORT_80 bind 192.168.37.17:80 # haproxy调度器IP地址 #balance first #balance source #hash-type consistent #balance uri balance url_param name 定义name值 mode http #不支持tcp模式,会切换至tcp的roundrobin负载模式 option forwardfor server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5 # 后端服务器IP地址 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
测试效果,定义的name=的值就会默认访问一个IP地址,不是name=有可能访问另外一个IP地址。
5、hdr(不常用)
hdr(<name>):针对用户每个http头部(header)请求中的指定信息做hash,此处由<name>指定的http首部将会被取出并做hash计算,然后由服务器总权重相除以后派发至某挑出的服务器,假如无有效的值,则会被轮询调度
•hdr( Cookie、User-Agent、host )
6、rdp-cookie对远程桌面的负载,使用cookie保持会话
•rdp-cookie(<name>)
算法总结:
•roundrobin-------->tcp/http 动态 用的比较多,做四层负载,做过session共享用的最多的调度算法,调度轮询,支持权重分配。 •leastconn----------->tcp/http 动态 用的比较多,做四层负载均衡,用于后端服务器上MySQL/PHP/HTTPS •static-rr-------------->tcp/http 静态轮询,等于roundrobin,但是不支持权重。 •first-------------------->tcp/http 静态,很少使用 •source---------------->tcp/http 取决于hash_type是否consistent,后端服务器没有seesion共享,但是还要实现会话保持 •Uri---------------------->http 取决于hash_type是否consistent,缓存场景,CDN缓存服务器,七层。 •url_param---------->http 取决于hash_type是否consistent,缓存场景,七层 •hdr--------------------->http 取决于hash_type是否consistent,基于请求头部指定的信息做调度,七层模式。 •rdp-cookie--------->tcp 取决于hash_type是否consistent,windows远程桌面,很少使用,四层。
什么时候用四层,什么时候用七层?
在haproxy对用户的请求报文,响应报文,不做响应处理,只做转发作用时,就用四层,通常情况,使用四层做负载。
在haproxy匹配头部信息,匹配某个字段,在做头部报文处理,需要用七层,七层做负载均衡,会对头部报文处理,会影响转发性能。
四层与七层的区别:
四层:
•在四层负载设备中,把client发送的报文目标地址(原来是负载均衡设备的IP地址),根据均衡设备设置的选择web服务器的规则选择对应的web服务器IP地址,这样client就可以直接跟此服务器建立TCP连接并发送数据。
七层:
•七层负载均衡服务器起了一个代理服务器的作用,服务器建立一次TCP连接要三次握手,而client要访问webserver要先与七层负载设备进行三次握手后建立TCP连接,把要访问的报文信息发送给七层负载均衡;然后七层负载均衡再根据设置的均衡规则选择特定的webserver,然后通过三次握手与此台webserver建立TCP连接,然后webserver把需要的数据发送给七层负载均衡设备,负载均衡设备再把数据发送给client;所以,七层负载均衡设备起到了代理服务器的作用。
七层IP透传:
(1)分析:后端收到服务的请求是haproxy的,所以日志记录的请求ip也是haproxy的;如我们想要记录真实client 的ip,需加forwardfor 选项;
在由haproxy 发往后端主机的请求报文中添加"X-Forwarded-For" 首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP。
(2)格式
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
[ except <network> ] :请求报请来自此处指定的网络时不予添加此首部,如haproxy 自身所在网络
[ header <name> ] :使用自定义的首部名称,而非默认的"X-Forwarded-For"
[ if-none ] 如果没有首部才添加首部,如果有使用默认值
七层负载:
listen web_prot_http_nodes bind 192.168.7.102:80 # haproxy主机的IP地址 mode http option forwardfor IP地址透传 server web1 blogs.studylinux.net:80 check inter 3000 fall 3 rise 5 # 调度到后端服务器上
确保nginx的日志格式为json格式:以下是nginx的json日志格式
http { log_format access_json '{"@timestamp":"$time_iso8601",' '"host":"$server_addr",' '"clientip":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_time,' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"uri":"$uri",' '"domain":"$host",' '"xff":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"tcp_xff":"$proxy_protocol_addr",' '"http_user_agent":"$http_user_agent",' '"status":"$status"}'; access_log /var/log/nginx/access.log access_json;
查看nginx的访问日志就可以收集到client的IP地址: tail -f /var/log/nginx/access.log
四层负载:
listen web_prot_http_nodes bind 192.168.7.102:80 # haproxy调度器IP地址 mode tcp server web2 blogs.studylinux.net:80 send-proxy check inter 3000 fall 3 rise 5
Nginx配置:需要在nginx配置文件中加入以下两部分内容,并将nginx的日志格式改为json格式。
listen 80 proxy_protocol; # 加入proxy_protocol选项 '"tcp_xff":"$proxy_protocol_addr",' #TCP获取客户端真实IP日志格式,需要添加两个配置选项。
查看nginx的访问日志就可以收集到client的IP地址: tail -f /var/log/nginx/access.log
Cookie 配置(生产中可以基于haproxy均衡调度到后端服务器)
cookie <value>:为指定server设定cookie值,此处指定的值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,其目的在于实现持久连接的功能;
cookie <value>:为当前server指定cookie值,实现基于cookie的会话黏性
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
<name>:cookie名称,用于实现持久连接,可以解决一直同时调度到同一台主机的问题。
rewrite:重写 insert:插入 prefix:前缀 nocache:当client和hapoxy之间有缓存时,不缓存cookie
基于cookie实现的session 保持:
实现原理:首先以轮询的方式第一次给访问用户分配服务器,并给用户发放cookie值,然后用户再次访问时,就会携带cookie值,调度器会区分cookie值,将用户调度到后端服务器,实现cookie的会话黏性。
listen WEB_PORT_80 bind 192.168.37.17:80 balance roundrobin # 以轮询的方式先对用户发放cookie值。 mode http cookie SERVER-COOKIE insert indirect nocache #先定义,下边才能使用,insert报文首部,nocache 不缓存cookie,其中SERVER-COKIE名称可以自定义。 server web1 192.168.37.27:80 cookie web-27 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 cookie web-37 check inter 3000 fall 3 rise 5
用curl命令验证cookie会话保持状态:
[root@mysql2 ~]# curl --cookie "SERVER-COOKIE=web1-27" http://192.168.37.27/index.html 192.168.7.103 [root@mysql2 ~]# curl --cookie "SERVER-COOKIE=web1-37" http://192.168.37.37/index.html
配置HAProxy状态页,监测web页面
•stats enable #基于默认的参数启用stats page •stats hide-version # 隐藏版本 •stats refresh <delay> # 设定自动刷新时间间隔 •stats uri <prefix> #自定义stats page uri,默认值:/haproxy?stats •stats realm <realm> #账户认证时的提示信息,示例:stats realm : HAProxyStatistics •stats auth <user>:<passwd> #认证时的账号和密码,可使用多次,默认:no authentication •stats refresh 5s #定义页面自动刷新间隔时间 •stats admin { if | unless } <cond> #启用stats page中的管理功能
示例:
vim /etc/haproxy/haproxy.cfg
listen stats bind :9527 stats enable stats hide-version stats uri /haproxy-status stats realm HAPorxyStatsPage stats auth haadmin:123456 stats auth admin:123456 stats refresh 30s stats admin if TRUE
打开状态页访问:192.168.37.17:9527/haproxy-status
验证HAProxy状态页
session rate(每秒的连接会话信息): Errors(错误统计信息): cur:每秒的当前会话数量 Req:错误请求量 max:每秒新的最大会话数量 conn:错误链接量 limit:每秒新的会话限制量 Resp:错误响应量 sessions(会话信息): Warnings(警告统计信息): cur:当前会话量 Retr:重新尝试次数 max:最大会话量 Redis:再次发送次数 limit: 限制会话量 Total:总共会话量 Server(real server信息): LBTot:选中一台服务器所用的总时间 Status:后端机的状态,包括UP和DOWN Last:和服务器的持续连接时间 LastChk:持续检查后端服务器的时间 Wght:权重 Bytes(流量统计): Act:活动链接数量 In:网络的字节输入总量 Bck:备份的服务器数量 Out:网络的字节输出总量 Chk:心跳检测时间 Dwn:后端服务器连接后都是DOWN的数量 Denied(拒绝统计信息): Dwntme:总的downtime时间 Req:拒绝请求量 Thrtle:server 状态 Resp:拒绝回复量
状态页信息
pid = 3698 (process #2, nbproc = 2, nbthread = 2) #pid为当前pid号,process为当前进程号,nbproc和nbthread为一共多少进程和每个进程多少个线程 uptime = 0d 0h00m08s #启动了多长时间 system limits: memmax = unlimited; ulimit-n = 131124 #系统资源限制:内存/最大打开文件数/ maxsock = 131124; maxconn = 65536; maxpipes = 0 #最大socket连接数/单进程最大连接数/最大管道数maxpipes current conns = 1; current pipes = 0/0; conn rate = 1/sec #当前连接数/当前管道数/当前连接速率 Running tasks: 1/9; idle = 100 % #运行的任务/当前空闲率 active UP:#在线服务器backup UP:#标记为backup的服务器 active UP, going down:#监测未通过正在进入down过程backup UP, going down:#备份服务器正在进入down过程 active DOWN, going up:#down的服务器正在进入up过程backup DOWN, going up:#备份服务器正在进入up过程 active or backup DOWN:#在线的服务器或者是backup的服务器已经转换成了down状态not checked:#标记为不监测的服务器 active or backup DOWN for maintenance (MAINT) #active或者backup服务器认为下线的 active or backup SOFT STOPPED for maintenance #active或者backup被认为软下线(人为将weight改成0)
修改报文首部
在请求报文尾部添加指定报文:
reqadd<string> [{if | unless} <cond>]#支持条件判断
在响应报文尾部添加指定报文:
rspadd<string> [{if | unless} <cond>] 示例:rspaddX-Via:HAPorxy
从请求报文中删除匹配正则表达式的首部
reqdel<search> [{if | unless} <cond>] reqidel<search> [{if | unless} <cond>] 不分大小写
从响应报文中删除匹配正则表达式的首部
rspdel<search> [{if | unless} <cond>] rspidel<search> [{if | unless} <cond>]
示例:rspidel server.* #从相应报文删除server信息
rspidel X-Powered-By:.* #从响应报文删除X-Powered-By信息
演示:
listen WEB_PORT_80 bind 192.168.37.17:80 mode http rspidel Server:.* 删除后端服务器的版本信息 server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
修改前会显示apache的版本号,不安全。
访问地址:192.168.37.17
修改后,将会删除对应的Server:.*正则表达式后面的所有字符,隐藏后端服务器的版本号,以防私密泄漏,此时访问时,已经无法看到后端服务器的apache版本号。
访问地址:192.168.37.17
HAProxy 日志配置
定义haproxy日志文件路径:
1、在default配置项定义:
log 127.0.0.1 local{1-7} info #基于syslog记录日志到指定设备,级别有(err、warning、info、debug)
2、配置rsyslog:vim /etc/rsyslog.conf
$ModLoad imudp $UDPServerRun 514 local3.* /var/log/haproxy.log
3、配置HAProxy:vim /etc/haproxy/haproxy.cfg,在global字段定义log日志级别
global log 127.0.0.1 local3 ##################################################### listen web_port bind 127.0.0.1:80 mode http log global option tcplog server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5
4、重启rsyslog服务并访问haproxy状态页
自定义记录日志
将特定信息记录在日志中(1.8版本不生效)
capture cookie <name> len <length> #捕获请求和响应报文中的cookie并记录日志 capture request header <name> len <length> #捕获请求报文中指定的首部内容和长度并记录日志 capture response header <name> len <length> #捕获响应报文中指定的内容和长度首部并记录日志
示例:
capture request header Host len 256
capture request header User-Agent len 512
实战演示:
vim /etc/haproxy/haproxy.cfg
#官网业务访问入口===================================== listen WEB_PORT_80 bind 192.168.37.7:80 mode http capture request header Host len 512 capture request header User-Agent len 512 server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
网页版查看访问的host主机的IP地址
经过日志分析,也可以捕获到本机的host的IP地址。
HAProxy 压缩功能
•compression algo #启用http协议中的压缩机制,常用算法有gzip deflate
•compression type #要压缩的类型
实战演示:
vim /etc/haproxy/haproxy.cfg
#官网业务访问入口===================================== listen WEB_PORT_80 bind 192.168.37.7:80 mode http capture request header Host len 512 capture request header User-Agent len 512 compression algo gzip deflate compression type text/plain text/html text/css text/xml text/javascript application/javascript server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5
访问网页,查看此时支持的gzip和deflate格式的压缩:192.168.37.17
Web服务器状态监测
三种状态监测方式:
•基于四层的传输端口做状态监测
server 172.18.200.103 172.18.200.103:80 check port 9000 addr 172.18.200.104 inter 3s fall 3 rise 5 weight 1
•基于指定URI 做状态监测
•基于指定URI的request请求头部内容做状态监测
option httpchk
•option httpchk <uri> •option httpchk <method> <uri> •option httpchk <method> <uri> <version>
示例:
•listen web_prot_http_nodes •bind 192.168.7.102:80 •mode http •log global •option httpchk GET /wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/1.0 #基于指定URL •#option httpchk HEAD /wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/1.0 Host:192.168.7.102 #通过request获取的头部信息进行匹配进行健康检测,节省很多不必要的网络开销,降低磁盘IO。 •server 192.168.7.102 blogs.studylinux.net:80 check inter 3000 fall 3 rise 5 •server 192.168.7.101 192.168.7.101:8080 cookie web1 check inter 3000 fall 3 rise 5
实战演示:
在后端服务器(192.168.37.37)新建一个monitor_page目录,并在目录下创建一个index.html文件。
[root@centos37html]#mkdir /var/www/html/monitor_page [root@centos37html]#echo OK > monitor_page/index.html
vim /etc/haproxy/haproxy.cfg
#官网业务访问入口===================================== listen WEB_PORT_80 bind 192.168.37.17:80 mode tcp 改为tcp类型,也会从http服务进行访问。 rspidel Server:.* #option httpchk GET /monitor_page/index.html HTTP/1.0 option httpchk HEAD /monitor_page/index.html HTTP/1.0 Host:192.168.37.17 生产用,用HEAD模式,可以节省很多不必要的网络开销,降低磁盘IO,声明是从17的IP地址发起的请求。 server web1 192.168.37.27:80 check inter 3000 fall 3 rise 5 server web2 192.168.37.37:80 check inter 3000 fall 3 rise 5
改为HEAD模式(只获取头部信息,并设置为每五秒监控一次),就不会在后端服务器日志中不会再显示文件大小,节省不必要的网络开销,降低磁盘IO。
在网页上进行状态页检查,此时可以看到后端服务器(192.168.37.27)没有monitor_page此目录,就会显示down机现象。
HAProxy中的ACL
1、ACL定义:
访问控制列表,用于实现基于请求报文的首部、响应报文的内容或其它的环境状态信息来做出转发决策,这大大增强了其配置弹性。其配置法则通常分为两步,首先去定义ACL ,即定义一个测试条件,而后在条件得到满足时执行某特定的动作,如阻止请求或转发至某特定的后端。
acl:对接收到的报文进行匹配和过滤,基于请求报文头部中的源地址、源端口、目标地址、目标端口、请求方法、URL、文件后缀等信息内容进行匹配并执行进一步操作。
•acl <aclname> <criterion> [flags] [operator] [<value>] •acl 名称条件条件标记位具体操作符操作对象类型 •acl image_service hdr_dom(host) -i img.magedu.com •ACL名称,可以使用大字母A-Z、小写字母a-z、冒号:、点.、中横线和下划线,并且严格区分大小写,必须Image_site和image_site完全是两个acl。
2、ACL derivatives :
•hdr([<name> [,<occ>]]):完全匹配字符串 •hdr_beg([<name> [,<occ>]]):前缀匹配 •hdr_dir([<name> [,<occ>]]):路径匹配 •hdr_dom([<name> [,<occ>]]):域匹配 •hdr_end([<name> [,<occ>]]):后缀匹配 •hdr_len([<name> [,<occ>]]):长度匹配 •hdr_reg([<name> [,<occ>]]):正则表达式匹配 •hdr_sub([<name> [,<occ>]]):子串匹配
3、<criterion> :匹配条件
(1)dst 目标IP
(2)dst_port 目标PORT
(3)src 源IP
(4)src_port 源PORT
hdr <string>用于测试请求头部首部指定内容
hdr_dom(host) 请求的host名称,如www.magedu.com hdr_beg(host) 请求的host开头,如www. img. video. download. ftp. hdr_end(host) 请求的host结尾,如.com .net .cn path_beg 请求的URL开头,如/static、/images、/img、/css path_end 请求的URL中资源的结尾,如.gif .png .css .js .jpg .jpeg
演示:
frontend web bind 192.168.37.17:80 mode http # acl www_web_page hdr_dom(host) -i www.magedu.net # acl mobile_web_page hdr_dom(host) -i mobile.magedu.net acl ip_range_test src 192.168.37.7 192.168.0.0/24 此源IP地址或者IP段访问时,都跳转至后端服务器的192.168.37.27地址上。 use_backend web2 if ip_range_test default_backend backup_web_host backend web2 server web1 192.168.37.27:80 weight 1 check port 80 inter 3s fall 3 rise 5 #server web1 192.168.37.37:80 weight 1 check port 80 inter 3s fall 3 rise 5
在客户端(192.168.37.7)访问haproxy效果,就会一直访问192.168.37.27地址。
当我们知道客户端的IP地址时,也可以进行拒绝客户端的访问,加上block选项。
查看访问效果,此时客户端被拒绝访问。
4、<flags>-条件标记
-i 不区分大小写 -m 使用指定的pattern匹配方法 -n 不做DNS解析 -u 禁止acl重名,否则多个同名ACL匹配或关系
5、[operator]-操作符:
整数比较:eq、ge、gt、le、lt
字符比较:
-exact match (-m str) :字符串必须完全匹配模式 -substring match (-m sub) :在提取的字符串中查找模式,如果其中任何一个被发现,ACL将匹配 -prefix match (-m beg) :在提取的字符串首部中查找模式,如果其中任何一个被发现,ACL将匹配 -suffix match (-m end) :将模式与提取字符串的尾部进行比较,如果其中任何一个匹配,则ACL进行匹配 -subdirmatch (-m dir) :查看提取出来的用斜线分隔(“/”)的字符串,如果其中任何一个匹配,则ACL进行匹配 -domain match (-m dom) :查找提取的用点(“.”)分隔字符串,如果其中任何一个匹配,则ACL进行匹配
6、<value>的类型:
-Boolean #布尔值false,true -integer or integer range #整数或整数范围,比如用于匹配端口范围,1024~32768 -IP address / network #IP地址或IP范围, 192.168.0.1 ,192.168.0.1/24
-string用法:
exact –精确比较 substring —子串 suffix -后缀比较 prefix -前缀比较 subdir -路径, /wp-includes/js/jquery/jquery.js domain -域名,www.magedu.com -regular expression #正则表达式 -hex block #16进制
实战演示:
frontend web bind 192.168.37.17:80 mode http acl www_web_page hdr_dom(host) -i www.magedu.net 访问www.magedu.net时,跳转至192.168.37.27后端服务器 acl mobile_web_page hdr_dom(host) -i mobile.magedu.net 访问mobile.magedu.net时,跳转至192.168.37.37后端服务器 use_backend pc_web_host if www_web_page use_backend mobile_web_host if mobile_web_page default_backend backup_web_host 访问其他域名时,默认跳转至192.168.37.47后端服务器。 backend pc_web_host server web1 192.168.37.27:80 weight 1 check port 80 inter 3s fall 3 rise 5 #server web1 192.168.37.37:80 weight 1 check port 80 inter 3s fall 3 rise 5 backend mobile_web_host #server web1 192.168.37.27:80 weight 1 check port 80 inter 3s fall 3 rise 5 server web1 192.168.37.37:80 weight 1 check port 80 inter 3s fall 3 rise 5 backend backup_web_host server web1 192.168.37.47:80 weight 1 check port 80 inter 3s fall 3 rise 5
网页访问效果:
7、Acl定义与调用
多个acl作为条件时的逻辑关系:
-与:隐式(默认)使用 -或:使用“or” 或“||”表示 -否定:使用“!“ 表示
示例:
if valid_src valid_port #与关系 if invalid_src || invalid_port #或 if ! invalid_src #非
自定义错误页面
支持200, 400, 403, 408, 500, 502, 503, 504.
errorfile 500 /usr/local/haproxy/html/500.html #自定义错误页面跳转 errorfile 502 /usr/local/haproxy/html/502.html errorfile 503 /usr/local/haproxy/html/503.html
自定义错误跳转,直接跳转到指定的服务器IP地址上,此IP地址需要是公网IP,并让其客户端能够访问,否则无法跳转。
errorloc 503 http://192.168.37.27/error_page/503.html
实战演一:
直接在HAProxy机器上创建自定义的错误页面。
errorfile 500 /usr/local/haproxy/html/500.html errorfile 502 /usr/local/haproxy/html/502.html errorfile 503 /usr/local/haproxy/html/503.html frontend web bind 192.168.37.17:80 mode http acl www_web_page hdr_dom(host) -i www.magedu.net use_backend mobile_web_host if www_web_page default_backend backup_web_host backend mobile_web_host #server web1 192.168.37.27:80 weight 1 check port 80 inter 3s fall 3 rise 5 server web1 192.168.37.37:80 weight 1 check port 80 inter 3s fall 3 rise 5 backend backup_web_host server web1 192.168.37.47:80 weight 1 check port 80 inter 3s fall 3 rise 5
然后创建错误页面目录及文件
[root@centos_17html]#mkdir /usr/local/haproxy/html [root@centos_17html]#cd /usr/local/haproxy/html/ [root@centos_17html]#echo error 503 > 503.html [root@centos_17html]#echo error 502 > 502.html [root@centos_17html]#echo error 500 > 500.html
访问网页:
实战演示二:
自定义错误跳转,直接跳转到指定的服务器URL上,此IP地址需要是公网域名,并让其客户端能够访问,否则无法跳转。
errorloc 503 http://192.168.37.37/error_page/503.html 指定跳转至192.168.37.37的服务器上。
在后端要跳转的服务器上创建一个错误提示:
[root@centos37monitor_page]#mkdir /var/www/html/error_page [root@centos37monitor_page]#echo Custerm error 503 > /var/www/html/error_page/503.html
停止掉要访问的后端服务器:systemctl stop httpd
验证访问效果: