HAProxy负载均衡
## HAProxy
- haproxy是属于基于七层代理的负载均衡代理方案,同样支持对四层模拟TCP的负载,功能强大;其中七层应用层是基于Http协议进行代理调度,四层是基于tcp四层协议层进行调度,支持(TLS的https和Mysql调度)
- 提供高可用性、负载均衡以及基于TCP和HTTP应用代理、免费、开源、可靠解决方案。适用于负载大web站点
- 实现了基于事件驱动、单一进程模型,此模型支持数千级别的并发连接
- haproxy不能实现ha高可用,但是可以基于健康检查,来进行监控后端节点的状态。
- haproxy只是httpd协议的反向代理,不提供缓存加速功能。但是反向代理功能强大,额外支持四层负载
- HAProxy 相对其他负载均衡器主要优点:
- HAProxy 是支持虚拟主机,通过 frontend 指令来实现
- 能够补充 Nginx 的一些缺点,比如 Session 的保持,Cookie 引导等工作(请求引导到同一台服务器)
- 支持 url 检测,后端的服务器出问题的检测会有很好的帮助
- 跟 LVS 一样,本身仅仅就只是一款负载均衡软件;单纯从效率上来讲 HAProxy 更会比Nginx 有更出色的负载均衡速度,在并发处理上也是优于 Nginx。
- HAProxy 可以对 Mysql 读进行负载均衡,对后端的 MySQL 节点进行检测和负载均衡,不过在后端的 MySQL slaves 数量超过 10 台时性能不如 LVS,所以更推荐 LVS+Keepalived。
- 能对请求的 url 和 header 中的信息做匹配,有比 lvs 有更好的 7 层实现
注:haproxy基于七层(应用层)负载,实现反向代理,必须监听在与之对应的应用程序端口上。和Nginx代理一样,基于多前端、交叉的方式、调度后端的调度方式
- 安装方式
- yum方式进行安装
- 源代码编译安装
- 相关配置文件
- /etc/haproxy haproxy的相关配置路径
- /etc/haproxy/haproxy.cfg 主配置文件
- /usr/sbin/haproxy 主程序所在文件
HAProxy的安装
-
实验环境
- HAProxy server:Centos7 192.168.10.122 192.168.20.200
- LAMP server1:Centos7 192.168.10.10
- LAMP server2:Centos7 192.168.10.11
- nginx server:Centos7 192.168.10.124
- client:win10 192.168.20.250
-
为haproxy服务器添加网卡并配置ip
-
使用本地yum源进行安装
-
修改配置,实现http服务的负载均衡
global #全局配置 # to have these messages end up in /var/log/haproxy.log you will # need to: # # 1) configure syslog to accept network log events. This is done # by adding the '-r' option to the SYSLOGD_OPTIONS in # /etc/sysconfig/syslog # # 2) configure local2 events to go to the /var/log/haproxy.log # file. A line like the following can be added to # /etc/sysconfig/syslog # # local2.* /var/log/haproxy.log #注释信息提示添加自定义日志的方法 log 127.0.0.1 local2 #定义日志 chroot /var/lib/haproxy #指定根目录 pidfile /var/run/haproxy.pid #pid存放文件 maxconn 4000 #最大连接数 user haproxy #所属用户 group haproxy #所属组 daemon #以守护进程方式运行 # turn on stats unix socket stats socket /var/lib/haproxy/stats #套接字状态信息文件存放位置 #其他常用全局配置 #nbproc <number>:指定启动的haproxy守护进程的个数,不加此选项默认一个 #ulimit -n:设定每个进程能打开的最大文件句柄数(相当于ulimit -n) #spread-check <0..50>:在haproxy后端有很多服务器场景,在精确的时间间隔后统一对众多服务器进行状态检查,会集中消耗大量带宽,这个选项可以在检查的时间间隔长度上增加或减少一定的随机时长 #------------------------------------------------------------------- # common defaults that all the 'listen' and 'backend' sections will # use if not designated in their block #------------------------------------------------------------------- defaults #默认配置 mode http #指定运行模式为应用层http代理,也可以为tcp四层代理、health健康状态监测,与后台服务保持一致 log global #日志配置应用到全局 option httplog # option dontlognull #不记录为空的访问请求 option http-server-close #请求结束主动关闭连接 option forwardfor except 127.0.0.0/8 #除本地访问请求其余请求记录真实访问地址 option redispatch 当绑定cookie的请求对应的真实服务器出现故障,强制将请求重定向至状态正常的RS进行响应 retries 3 #服务连接失败重试次数 timeout http-request 10s #http请求超时时长 timeout queue 1m #请求在队列中的超时时长 timeout connect 10s #连接超时时长 timeout client 1m #客户端超时时长 timeout server 1m #服务端超时时长 timeout http-keep-alive 10s #保持连接超时时长 timeout check 10s #检查超时时长 maxconn 3000 #单个进程最大连接数 #------------------------------------------------------------------- # main frontend which proxys to the backends #------------------------------------------------------------------- frontend main 192.168.20.200:80 #监听地址和端口,*表示所有 # acl url_static path_beg -i /static /images /javascript /stylesheets # acl url_static path_end -i .jpg .gif .png .css .js # use_backend static if url_static #use_backend 条件式后端调用 default_backend webserver #定义名为webserver的前端,与后面backend对应 #bind 绑定监听的ip和端口 #------------------------------------------------------------------- # static backend for serving up images, stylesheets and such #------------------------------------------------------------------- #backend static # balance roundrobin # server static 127.0.0.1:4331 check #------------------------------------------------------------------- # round robin balancing between the various backends #------------------------------------------------------------------- backend webserver #使用定义的前端进行配置 balance roundrobin #指定负载均衡算法roundrobin 轮转 server web1 192.168.10.10:80 check #定义后端真实服务器 RS server web2 192.168.10.10:80 check server web3 192.168.10.100:80 backup #backup为备份服务器 #server常用参数 #check 启用健康状态检查 #inter<delay> 指定检查时间间隔(ms) #fall up切换至down状态需要确认的次数 #rise down切换至up状态需要确认的次数 #backup 指定当前server为备份服务器 #cookie 为server设定cookie的值以实现会话绑定、持久连接 #maxconn:此server接受的并发连接的最大数量 #maxqueue:请求队列的最大长度 #observer:根据流量判断后端server的健康状态 #weight:权重,默认为1,最大值256,0表示不参与负载均衡 #redir <prefix>:启用重定向功能,将发往此服务器的GET和HEAD请求以302状态码响应,需要注意prefix后不能使用/和相对地址,以免造成语法错误和循环 #cookie格式:cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ] #insert命令,表示在将响应报文交给客户端之前,先插入一个属性名为"name"的cookie #使用rewrite模式时,haproxy将重写cookie的值为后端服务器的标识符。 #使用prefix的时候,cookie指令设置的cookie名必须和后端设置的cookie一样 #调度算法: #roundrobin:加权动态轮询,支持权重的运行时调整,支持慢启动;每个后端中最多支持4095个 #static-rr:加权静态轮询,不支持权重的运行时调整及慢启动;后端主机数量无上限 #leastconn:加权最小连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,适用于长连接场景,例如 MySQL、LDAP等,不适合http #first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务 #source:源地址hash(默认为静态算法可使用hash-type指定为动态算法) #hash-type <method> <function> <modifier> #指定hash类型 #method: #map-based:除权取余法,哈希数据结构是静态数组(不支持权重动态调整) #consistent:一致性哈希,动态hash #<function> : 哈希函数 #如sdbm、djb2、wt6 #uri:对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器,将访问同一个URI的请求指定访问到同一台服务器,支持hash-type #url_param:根据url中指定的参数值进行调度,把值做hash计算支持hash-type #hdr(<name>):根据请求报文中的header进行调度,包括(user_agent,referer,hostname)支持hash-type
-
配置两台LAMP服务器
过程参考LAMP环境搭建详细流程 -
修改测试页
-
启动服务
-
测试(使用浏览器访问会因为缓存与长连接导致无法看到轮询效果)
自定义日志
- 修改haproxy主配置文件如下
- 修改日志配置文件
- 重启服务
- 访问后查看指定的日志文件是否进行日志收集
启用状态监控
-
修改haproxy配置文件
listen status #监听配置 bind *:1080 #绑定网卡及端口 stats enable #开启监听 stats hide-version #隐藏版本号 stats uri /haproxyadmin?stats #指定访问监听页面的路径 stats realm Haproxy\ Statistics #定义新的登录账号密码的提示页面 stats auth admin:12345 #账号认证登录,并指定账号密码 stats admin if TRUE #认证成功后拥有管理员权限(开启时要注释stats scope选项) #注:需要stats enable开启状态监控,该参数可以在default/listen/backend中, #开启后下面参数拥有的默认值: #stats uri : /haproxy?stats #stats realm : "HAProxy Statistics" #stats auth : no authentication #stats scope : no restriction
- 重启服务
![image-20191118155123526](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214023736-706153077.png)
- 访问测试
![image-20191118155328409](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214023506-230408893.png)
![image-20191118155352144](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214023141-1238614449.png)
### ACL访问控制配置
- 修改haproxy配置文件如下
![image-20191118162010931](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214022783-1513722340.png)
![image-20191118210120991](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214022550-1603974729.png)
```shell
frontend main 192.168.20.200:80
http-request deny
acl nagios src 192.168.20.250 #acl定义匹配条件,名称为nagios,匹配来自192.168.20.250的请求
acl local_net src 192.168.10.0/24 #local_net匹配规则定义匹配来自192.168.10.0/24网段的请求
http-request deny if nagios #当nagios匹配条件为真则拒绝该请求
http-request allow if local_net #允许local_net中定义的请求
http-request deny #默认拒绝访问
#注:acl访问控制还可以对tcp进行进行控制tcp-request <alllow | deny>
#参数格式:acl <aclname> <criterion> [flag] [operator] <value>
#aclname 匹配规则的名称,区分大小写,只能包括大小写字母、数字,连接线、下划线、点号、冒号
#criterion:测试标准,表示检查那些数据或内容,常用:
#src:ip 源IP
#src_port:integer 源端口
#dst:ip 目标IP
#dst_port:integer 目标端口
#flag:acl标志位,定义控制条件,例如是否区分字符大小写等,可选参数如下:
# -i 忽略字符大小写
# -m 启用特定的匹配方式,一般不用
# -n 禁止DNS反向解析
# -u 不允许aclname重复,默认是可以重名的,当两个acl的名称相同时,运算为或机制。
#operator:判断匹配条件,与<criterion>相比较的操作
# 匹配整数值:eq,ge,gt,le,lt
#value:测试的数据值,访问控制的具体内容或值
# boolean:布尔值
# integer or integer range:整数或整数范围
# IP address/network:网络地址
# string(exact, substring, suffix, prefix, subdir, domain):字符串
# regular expression:正则表达式
#常用的criterion
#be_sess_rate:用于测试指定的backend会话创建的速率(即每秒创建的会话数)
#例如:
#backend dynamic
#mode http
#acl being_scanned be_sess_rate gt 100
#redirect location /error_page/denied.html if being_scanned
#fe_sess_rate:用于测试指定的frontend会话创建的速率(即每秒创建的会话数)
#例如
#frontend mail
#bind *:25
#mode tcp
#maxconn 5000
#acl too_fast fe_sess_rate gt 100
#tcp-request inspect-delay 500ms 延迟500毫秒
#tcp-request content accept if ! too_fast
#tcp-request content accept if WAIT_END
#hdr: 根据请求报文中的header进行调度,包括(user_agent,referer,hostname)
#method:根据请求的方法进行匹配
#path_beg:根据请求URL路径的开头来匹配
#例如:acl url_static path_beg -i /static、/images、/javascript、/stylesheets location
#path_end:根据URL路径请求的结尾
#例如:acl url_static path_beg -i .jpg .gif .png .css .js
```
- 重启服务
![image-20191118164639523](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214022276-1860676059.png)
- 访问测试
![image-20191118191319251](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214022006-540343784.png)
192.168.10.1主机访问时被拒绝
### HAProxy动静分离
- 添加一台nginx服务器作为静态网页处理服务器(参考[Nginx初识](https://www.cnblogs.com/lastyear/p/11838912.html))
- 添加测试页
![image-20191118193332401](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214021738-2145323517.png)
- 修改两台LAMP的测试主页为动态php页面
![image-20191118193527871](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214021478-1305253255.png)
![image-20191118193551022](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214021242-454056582.png)
![image-20191118193618089](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214021019-396974319.png)
![image-20191118193649630](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214020786-1527702028.png)
![image-20191118194012736](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214020572-228707000.png)
![image-20191118200920849](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214020319-1141613897.png)
![image-20191118194227830](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214020063-227301550.png)
![image-20191118200950277](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214019833-2005762753.png)
- 重启服务
![image-20191118193847671](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214019593-392908101.png)
![image-20191118193941758](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214019338-873424875.png)
![image-20191118193950411](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214019100-826050930.png)
- 修改haproxy主配置文件,将nginx服务器添加到负载均衡中
![image-20191118195227413](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214018865-1824842634.png)
![image-20191118195215479](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214018628-456292205.png)
- 重启服务
![image-20191118194956433](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214018361-1541372014.png)
- 访问测试(使用浏览器访问会因为缓存与长连接导致无法看到轮询效果)
![image-20191118201038508](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214018120-34317000.png)
![image-20191118195729058](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214017893-697338292.png)
![image-20191118201026419](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214017648-437218004.png)
- 修改配置,启用动静分离
![image-20191118195923021](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214017410-1352170034.png)
![image-20191118200728164](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214017135-490400372.png)
```shell
frontend main 192.168.20.200:80
acl url_static path_beg -i /img /static /images
#定义匹配规则,匹配以/img、/static、/images开始的请求命名为url_static
acl url_static path_end -i .jpg .gif .png .css .js .html
#匹配.jpg、.gif、.png、.css、.js、.html结尾的请求,命名为url_static
acl url_dynamic path_end -i .php
#匹配以.php结尾的请求命名为url_dynamic
use_backend static if url_static
#若url_static匹配条件为真则由static中的服务器进行响应
use_backend webserver if url_dynamic
#若url_dynamic匹配条件为真则由webserver中的服务器进行响应
default_backend webserver
#默认使用webserver中的后台服务器进行响应
backend static #静态web处理服务器
balance roundrobin
server static1 192.168.10.124:80 check
backend webserver #动态web处理服务器
balance roundrobin
server web1 192.168.10.10:80 check
server web2 192.168.10.11:80 check
server web3 192.168.10.100:80 backup
```
- 重启服务
![image-20191118200537547](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214016842-1224334603.png)
- 测试动静分离
![image-20191118201104217](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214016599-1292268295.png)
### 收集客户真实地址
- 修改haproxy配置文件如下
![image-20191118201358983](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214016309-852207420.png)
![image-20191118201347506](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214016047-1187367364.png)
- 重启服务
![image-20191118201418652](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214015773-1504003277.png)
- 修改LAMP服务器中httpd服务日志格式
![image-20191118201647701](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214015528-1310382246.png)
![image-20191118201908361](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214015272-660046161.png)
另一台LAMP也做相同配置
- 重启服务
![image-20191118202050467](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214014943-2038729262.png)
![image-20191118202059550](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214014709-1204204059.png)
- 修改nginx日志配置(yum安装无需修改)
![image-20191118203622318](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214014474-245549628.png)
![image-20191118203635599](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214014244-1809133197.png)
![image-20191118203701279](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214013995-936359278.png)
![image-20191118203835022](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214013756-46751987.png)
![image-20191118203908073](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118214013513-1819065160.png)
- 重启服务
![image-20191118203934290](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118213954689-549147301.png)
- 访问几次后查看日志文件可以看到真实ip已经被记录
httpd服务的日志真实客户ip地址在最前面
![image-20191118202939955](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118213954409-460571378.png)
nginx服务的日志中真实客户地址在后面
![image-20191118203542118](https://img2018.cnblogs.com/blog/1241092/201911/1241092-20191118213954050-1989365528.png)