haproxy简介
HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在时下的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
HAProxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。
haproxy部署
首先通过科学上网的方式下载haproxy 下载地址:www.haproxy.org/#down
安装部署haproxy-1.8.13
[root@linux-node1 tools]# tar xf haproxy-1.8.13.tar.gz
[root@linux-node1 tools]# cd haproxy-1.8.13
[root@linux-node1 haproxy-1.8.13]# make TARGET=linux26 PREFIX=/usr/local/haproxy-1.8.13
[root@linux-node1 haproxy-1.8.13]# make install PREFIX=/usr/local/haproxy-1.8.13
[root@linux-node1 haproxy-1.8.13]# ln -s /usr/local/haproxy-1.8.13 /usr/local/haproxy
#拷贝haproxy启动脚本到/etc/init.d/目录,并授予可执行权限
[root@linux-node1 haproxy-1.8.13]# cp examples/haproxy.init /etc/init.d/haproxy
[root@linux-node1 haproxy-1.8.13]# chmod +x /etc/init.d/haproxy
根据haproxy的启动脚本,创建haproxy的配置文件所在的目录,修改启动脚本对应的haproxy的二进制文件位置
#修改haproxy启动脚本对应的二进制文件位置
[root@linux-node1 ~]# vim /etc/init.d/haproxy
#!/bin/sh
#
# chkconfig: - 85 15
# description: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited
\
# for high availability environments.
# processname: haproxy
# config: /etc/haproxy/haproxy.cfg
# pidfile: /var/run/haproxy.pid
BIN=/usr/local/haproxy/sbin/$BASENAME
#根据上面haproxy启动脚本的说明,创建haproxy配置文件的目录
[root@linux-node1 ~]# mkdir /etc/haproxy/
#根据上面haproxy启动脚本的说明,创建haproxy进程需要的用户
[root@linux-node1 ~]# useradd -r haproxy -s /sbin/nologin
通过rsyslog系统日志配置文件来配置haproxy日志文件
[root@linux-node1 ~]# vim /etc/rsyslog.conf
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
local3.* /var/log/haproxy.log
#重启rsyslog使配置haproxy日志文件生效
[root@linux-node1 ~]# /etc/init.d/rsyslog restart
创建haproxy配置文件haproxy.cfg
[root@linux-node1 ~]# vim /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local3 info
chroot /usr/local/haproxy
#下面的进程ID一定要和haproxy启动脚本定义的一致
pidfile /var/run/haproxy.pid
#配置haproxy的sock文件,权限是600,等级是admin权限,超时2分钟
stats socket /usr/local/haproxy/haproxy.sock mode 660 level admin
stats timeout 2m
user haproxy
group haproxy
daemon
nbproc 1
maxconn 30000
defaults
log global
mode http
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
timeout http-request 10s
timeout http-keep-alive 10s
timeout connect 5000
timeout client 50000
timeout server 50000
timeout check 10000
maxconn 30000
#定义haproxy状态监控页面
listen haproxy_status
bind 192.168.80.171:8888
stats enable
stats refresh 100s
stats hide-version
stats uri /haproxy-status
stats realm "HAProxy/ static"
stats auth admin:admin123
stats admin if TRUE
#安全起见,还可以定义允许的网段,拒绝其他网段访问
#acl allow_ips src 192.168.80.0/24
#tcp-request content accept if allow_ips
#tcp-request content reject
frontend webs
bind 192.168.80.171:80
use_backend srvs_backend
backend srvs_backend
mode http
balance roundrobin
option forwardfor header X-FORWARDED-FOR
server web-node1 192.168.80.172:80 check inter 2000 rise 2 fall 3 weight 1
server web-node2 192.168.80.173:80 check inter 2000 rise 2 fall 3 weight 1
上述haproxy.cfg配置文件部分参数说明
#global段中的参数为进程级别的参数,且通常与其运行的OS相关。
#与代理相关的配置参数可以在这些段中配置:“defaults”、“listen”、“frontend”和“backend”
- chroot <jail dir>:修改haproxy的工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限;
- daemon:让haproxy以守护进程的方式工作于后台,其等同于“-D”选项的功能,当然,也可以在命令行中以“-db”选项将其禁用;
- nbproc <number>:指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
- node:定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
- mode:设置haproxy实例默认运行模式,有tcp、http、health三个值
- option httplog:启用记录HTTP请求、会话状态和计时器的功能。默认情况下,日志输入格式非常简陋,因为其仅包括源地址、目标地址和实例名称,而“option httplog”参数将会使得日志格式变得丰富许多,其通常包括但不限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、“frontend”、“backend”及服务器名称,当然也包括源地址和端口号等。
- retries:设置后端服务器的失败重试次数
- option dontlognull:不记录空连接的日志
- timeout http request:断开客户端连接的超时时长
- timeout queue 在队列中等待的时长
- timeout connect 设定在haproxy转发至后端upstream server时等待的超时时长
- timeout client client的一次非活动状态的超时时长
- timeout server 等待服务器端的非活动的超时时长
- timeout http-keep-alive 保持连接的超时时长
- timeout check:检查请求连接的超时时长
- option redispatch:如果后端有服务器宕机,强制切换到正常服务器
- option httpchk:用于指定对http协议的server的检测方法
- hash-type:map-based:使用/权重取模;consistent:一致性hash
- cookie:cookie <name> [rewite(重写)|insert(插入)|prefix] ,insert 一般使用nocache
- option http-server-close:在使用长连接时,一定要使用这个参数,这是为了避免客户端超时没有关闭长连接,此功能可以使服务器端关闭长连接
- option httpclose:每次请求完毕后,关闭http通道。如果使用这个参数,那么就不可用长连接参数
- balance:表示haproxy要使用的调度算法,有如下算法:
roundrobin:轮询,基于权重轮询,动态权重调整,每个后端主机最多支持4128个连接
static-rr:静态权重轮询,不支持动态调整权重,若调整需要重启,每个后端主机支持的数量没有上线
leastconn:最少连接数,动态算法,新的连接请求被派发至具有最少连接数据的后端服务器。
在有着较长时间会话的场景中推荐使用,如ldap、sql等,不适应较短时间会话场景,如http等
source:静态算法,将请求的源地址进行hash,除模取余的算法,除以服务器个数
可以使同一个客户端ip的请求始终被派发至某特定的服务器(缺点就是如果其中某个服务器 宕机了或者增加了,那么除模取余将会改变,会话信息就不复存在)
如果需要将静态改为动态,可以使用hash-type进行修改
uri:对uri的左半部分或对整个uri进行hash,除模取余的算法,除以服务器个数(总权重),可以使用hash-type进行修改到底是静态算法还是动态算法
url_param:根据url中的指定的参数的值进行调度,然后进行hash,可以实现类似会话绑定
hdr(name):header,请求报文首部进行调度,如报文的user-agent浏览器进行调度
把指定的header的值进行hash调度,可以使用hash-type进行修改到底是静态算法还是动态算法设置如:hdr(User-Agent
配置好haproxy的配置文件后,根据haproxy的启动脚本的要求就可以启动haproxy了
[root@linux-node1 ~]# /etc/init.d/haproxy start
#配置开启自启动
[root@linux-node1 ~]# chkconfig --level 35 haproxy on
配置好后端的web服务(略),通过http://192.168.80.171:8888/haproxy-status地址展示haproxy的监控界面如下:
配置当后端服务器出现问题的时候客户端显示的错误页面
[root@linux-node1 haproxy-1.8.13]# cp -r examples/errorfiles/ /usr/local/haproxy/
[root@linux-node1 haproxy]# vim /etc/haproxy/haproxy.cfg
backend srvs_backend
balance roundrobin
option forwardfor header X-FORWARDED-FOR
errorfile 400 /usr/local/haproxy/errorfiles/400.http
errorfile 403 /usr/local/haproxy/errorfiles/403.http
errorfile 503 /usr/local/haproxy/errorfiles/503.http
server web-node1 192.168.80.172:80 check
server web-node2 192.168.80.173:80 check
根据客户端访问的域名不同haproxy反向代理到不同的上游服务器,需要用到acl(类似于nginx反向代理的location)
acl方法,HAProxy定义了很多ACL方法,经常使用的有:hdr_reg(host),hdr_dom(host),hdr_beg(host),url_sub,url_dir,path_beg,path_end
#haproxy.cfg配置文件部分配置如下
frontend webs
bind 192.168.80.171:80
acl www hdr_beg(host) -i www.goser.com
acl bbs hdr_beg(host) -i bbs.goser.com
use_backend www_srvs if www
use_backend bbs_srvs if bbs
default_backend default_srvs
#其他acl控制不符的时候,走默认的后端服务器,比如客户端使用ip访问或其他地址访问等
backend default_srvs
balance roundrobin
option forwardfor header X-FORWARDED-FOR
server web-node1 192.168.80.172:80 check
server web-node2 192.168.80.173:80 check
backend bbs_srvs
balance roundrobin
option forwardfor header X-FORWARDED-FOR
server web-node1 192.168.80.172:80 check
backend www_srvs
balance roundrobin
option forwardfor header X-FORWARDED-FOR
server web-node2 192.168.80.173:80 check
基于cookie会话保持:由于现实上网的方式多为nat转换,多个局域网私有ip对应一个公网ip,如果使用source算法来绑定到上游某台服务器的话,那么这个服务器压力要很大。所以使用cookie的方式让每个客户端访问时haproxy都会根据cookie转发到后端某台服务器
frontend webs
bind 192.168.80.171:80
use_backend srvs_backend
backend srvs_backend
balance roundrobin
cookie node1 insert indirect nocache
cookie node2 insert indirect nocache
option forwardfor header X-FORWARDED-FOR
server web-node1 192.168.80.172:80 check cookie node1
server web-node2 192.168.80.173:80 check cookie node2
设置一致性hash:hash-type consistent 要和balance soure或balance uri配置使用
backend srvs_backend
balance uri
hash-type consistent
option forwardfor header X-FORWARDED-FOR
server web-node1 192.168.80.172:80 check
server web-node2 192.168.80.173:80 check
haproxy负载均衡MySQL服务的配置示例
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
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
maxconn 4000
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
option httplog
option dontlognull
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 600
listen stats
mode http
bind 0.0.0.0:1080
stats enable
stats hide-version
stats uri /haproxyadmin?stats
stats realm Haproxy\ Statistics
stats auth admin:admin
stats admin if TRUE
frontend mysql
bind *:3306
mode tcp
log global
default_backend mysqlservers
backend mysqlservers
#这里使用最小连接数算法,将客户端请求放到连接数最小的mysql服务上
balance leastconn
server dbsrv1 192.168.80.180:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
server dbsrv2 192.168.80.190:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
动静分离案例
#部分配置代码如下:
frontend web_static
bind 0.0.0.0: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
default_backend dynamic
backend static
balance roundrobin
server web-node1 192.168.80.172 check
server web-node2 192.168.80.173 check
backend dynamic
balance roundrobin
server tomcat-noide1 192.168.80.180 check
server tomcat-node2 192.168.80.181 check
通过acl来控制客户端访问的重定向redirect
acl clear dst_port 80
acl secure dst_port 8080
acl login_page url_beg /login
acl logout url_beg /logout
acl uid_given url_reg /login?userid=[^&]+
acl cookie_set hdr_sub(cookie) SEEN=1
redirect prefix https://goser.com set-cookie SEEN=1 if !cookie_set
redirect prefix https://goser.com if login_page !secure
redirect prefix http://goser.com drop-query if login_page !uid_given
redirect location http://www.goser.com/ if !login_page secure
redirect location / clear-cookie USERID= if logout
通过acl来实现访问控制
http-request :7层过滤,主要对web站点访问的控制
tcp-request content 4层过滤,主要对非web站点的访问控制,比如mysql的访问控制
通过socat命令操作haproxy-api来动态管理上游服务的上下线
#安装socat工具
[root@linux-node1 ~]# yum install socat -y
#查看haproxy-api通过socat命令支持的操作
[root@linux-node1 ~]# echo "help" | socat stdio /usr/local/haproxy/haproxy.sock
#查看haproxy的状态信息
[root@linux-node1 ~]# echo "show info" | socat stdio /usr/local/haproxy/haproxy.sock
#查看haproxy的上游服务的状态
[root@linux-node1 ~]# echo "show servers state" | socat stdio /usr/local/haproxy/haproxy.sock
1
# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port
4 srvs_backend 1 web-node1 192.168.80.172 2 0 1 1 4390 6 3 4 6 0 0 0 - 80
4 srvs_backend 2 web-node2 192.168.80.173 2 0 1 1 4539 6 3 4 6 0 0 0 - 80
#让某台上游服务停止web服务
[root@linux-node1 ~]# echo "disable server srvs_backend/web-node1" | socat stdio /usr/local/haproxy/haproxy.sock
#让某台上游服务启动web服务
[root@linux-node1 ~]# echo "enable server srvs_backend/web-node1" | socat stdio /usr/local/haproxy/haproxy.sock
对haproxy大并发连接性能调优
[root@linux-node1 ~]# vim /etc/sysctl.conf
#调整客户端和服务端连接需要的随机端口范围
net.ipv4.ip_local_port_range = 30000 60000
#允许将TIME-WAIT sockets重新用于新的TCP连接
net.ipv4.tcp_tw_reuse = 1
#开启TCP连接中TIME-WAIT sockets的快速回收
net.ipv4.tcp_tw_recycle = 1
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间(可改为30,一般来说FIN-WAIT-2的连接也极少)
net.ipv4.tcp_fin_timeout = 30
#使配置生效
[root@linux-node1 ~]# sysctl -p