c4rt1y

HAProxy之反向代理负载均衡

0x01 介绍(百度百科)

HAProxy是一个使用C语言编写的自由及开放源代码软件[1],其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
HAProxy实现了一种事件驱动, 单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户空间(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。

0x02 haproxy算法介绍

目前haproxy支持的负载均衡算法有如下8种
1、roundrobin
表示简单的轮询,每个服务器根据权重轮流使用,在服务器的处理时间平均分配的情况下这是最流畅和公平的算法。该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。

2、leastconn
连接数最少的服务器优先接收连接。leastconn建议用于长会话服务,例如LDAP、SQL、TSE等,而不适合短会话协议。如HTTP.该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。

3、static-rr
每个服务器根据权重轮流使用,类似roundrobin,但它是静态的,意味着运行时修改权限是无效的。另外,它对服务器的数量没有限制。
该算法一般不用;

4、source
对请求源IP地址进行哈希,用可用服务器的权重总数除以哈希值,根据结果进行分配。只要服务器正常,同一个客户端IP地址总是访问同一个服务器。如果哈希的结果随可用服务器数量而变化,那么客户端会定向到不同的服务器;
该算法一般用于不能插入cookie的Tcp模式。它还可以用于广域网上为拒绝使用会话cookie的客户端提供最有效的粘连;
该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。

5、uri
表示根据请求的URI左端(问号之前)进行哈希,用可用服务器的权重总数除以哈希值,根据结果进行分配。只要服务器正常,同一个URI地址总是访问同一个服务器。一般用于代理缓存和反病毒代理,以最大限度的提高缓存的命中率。该算法只能用于HTTP后端;
该算法一般用于后端是缓存服务器;
该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。

6、url_param
在HTTP GET请求的查询串中查找<param>中指定的URL参数,基本上可以锁定使用特制的URL到特定的负载均衡器节点的要求;
该算法一般用于将同一个用户的信息发送到同一个后端服务器;
该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。

7、hdr(name)
在每个HTTP请求中查找HTTP头<name>,HTTP头<name>将被看作在每个HTTP请求,并针对特定的节点;
如果缺少头或者头没有任何值,则用roundrobin代替;
该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。

8、rdp-cookie(name)
为每个进来的TCP请求查询并哈希RDP cookie<name>;
该机制用于退化的持久模式,可以使同一个用户或者同一个会话ID总是发送给同一台服务器。如果没有cookie,则使用roundrobin算法代替;
该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。 

0x03 实验环境

#3台环境都是centos7
master
	eth0 10.10.10.10
node01
	eth0 10.10.10.20
node02
	eth0 10.10.10.30			

#关闭firewalld
systemctl stop firewalld.service
systemctl disable firewalld.service

#关闭selinux
sed -i 's:SELINUX=enforcing:SELINUX=disabled:g' /etc/selinux/config
setenforce 0

0x04 node01和node02上

#node01环境
yum install httpd -y
systemctl enable httpd
systemctl enable httpd

echo "10.10.10.20" > /var/www/html/index.html

#node02环境
yum install httpd -y
systemctl enable httpd
systemctl enable httpd

echo "10.10.10.30" > /var/www/html/index.html

0x05 master上

#下载haproxy
wget http://www.haproxy.org/download/1.6/src/haproxy-1.6.3.tar.gz
#解压进入目录
tar zxf haproxy-1.6.3.tar.gz && cd haproxy-1.6.3
#安装
make TARGET=LINUX2628 prefix=/usr/local/haporxy
make install
#设置
cp /usr/local/sbin/haproxy /usr/sbin/
cp /root/haproxy-1.7.8/examples/haproxy.init /etc/init.d/haproxy
chmod +x /etc/init.d/haproxy

#添加用户
useradd -r haproxy

#添加目录
mkdir /etc/haproxy/
mkdir /var/lib/haproxy

#修改rsyslog.conf的部分文件
vi /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
local3.*   	/var/log/haproxy.log

#重启rsyslog
systemctl restart rsyslog

#编写haproxy.cfg文件
cat > /etc/haproxy/haproxy.cfg <<EOF
global           
       log 127.0.0.1   local3
       maxconn 4096
       chroot /var/lib/haproxy
       user haproxy
       group haproxy
       daemon
defaults
       log    global
       mode    http
       option  httplog
       option  dontlognull  
       timeout connect     5000
       timeout client      50000
       timeout server     50000
frontend http_front
       bind *:80
       stats uri /haproxy?stats
       default_backend webserver
backend webserver
       option forwardfor header X-REAL-IP
       balance roundrobin
       server  node01 10.10.10.20:80 cookie 1 weight 5 check inter 2000 rise 2 fall 3
       server  node02 10.10.10.30:80 cookie 2 weight 3 check inter 2000 rise 2 fall 3
EOF

#测试语法是否正常
/usr/local/sbin/haproxy -f /etc/haproxy/haproxy.cfg

#启动
/etc/init.d/haproxy start

#访问(使用的算法是roundrobin 轮询算法,所以两次访问的内容不同iP)

10_10_10_10_20 10_10_10_10_30

#控制页面
http://10.10.10.10/haproxy?stats

new-centos

#下面是一份比较详细的haproxy.cfg的说明文档
cat /etc/haproxy/haproxy.cfg
global           #全局设置
       log 127.0.0.1   local3      #日志输出配置,所有日志都记录在本机,通过local3输出
       maxconn 4096                #最大连接数
       chroot /var/lib/haproxy
       user haproxy
       group haproxy
       daemon                #以后台形式运行haproxy
defaults                     #默认设置
       log    global
       mode    http          #所处理的类别,默认采用http模式,可配置成tcp作4层消息转发
       option  httplog       #日志类别,采用httplog
       option  dontlognull  			   #日志中不记录空连接
       timeout  connect    5000            #连接超时时间
       timeout  client     50000           #客户端连接超时时间
       timeout  server     50000           #服务器端连接超时时间
frontend http_front                        #前台
       bind *:80 						#端口
       stats uri /haproxy?stats 		#访问页面
       default_backend webserver        #静态服务器池
backend webserver                       #后台
       option forwardfor header X-REAL-IP 	#获取真实IP
       balance roundrobin		#负载均衡算法
       server  node01 10.10.10.20:80 cookie 1 weight 5 check inter 2000 rise 2 fall 3   #RS健康检测时间间隔2秒,权重5,重试2次,失败3次不可用
       server  node02 10.10.10.30:80 cookie 2 weight 3 check inter 2000 rise 2 fall 3

0x06 haproxy.cfg配置文件讲解

#设置acl
cat /etc/haproxy/haproxy.cfg
global           #全局设置
       log 127.0.0.1   local3      #日志输出配置,所有日志都记录在本机,通过local3输出
       maxconn 4096                #最大连接数
       chroot /var/lib/haproxy
       user haproxy
       group haproxy
       daemon                #以后台形式运行haproxy
defaults                     #默认设置
       log    global
       mode    http          #所处理的类别,默认采用http模式,可配置成tcp作4层消息转发
       option  httplog       #日志类别,采用httplog
       option  dontlognull  			   #日志中不记录空连接
       timeout  connect    5000            #连接超时时间
       timeout  client     50000           #客户端连接超时时间
       timeout  server     50000           #服务器端连接超时时间
frontend http_front                        #前台
       bind *:80 						#端口

       acl is_static_reg url_reg /*.(css|jpg|png|js|jpeg|gif)$		       #控制后缀如下则访问webserver
       use_backend webserver if is_static_path

       acl is_do_path url_reg /index.html			   #如果后缀名是index.html则访问webserver
       use_backend webserver if is_do_path

       acl is_UA_path hdr_reg(User-Agent) -i andriod	#如果User-Agent是andriod则访问webserver
       use_backend webserver if is_UA_path

       stats uri /haproxy?stats 		#访问页面
       default_backend webserver        #静态服务器池
backend webserver                       #后台
       option forwardfor header X-REAL-IP 	#获取真实IP
       balance roundrobin		#负载均衡算法
       server  node01 10.10.10.20:80 cookie 1 weight 5 check inter 2000 rise 2 fall 3   #RS健康检测时间间隔2秒,权重5,重试2次,失败3次不可用
       server  node02 10.10.10.30:80 cookie 2 weight 3 check inter 2000 rise 2 fall 3


#首先附上另一份配置文件+注释[主要是为了理解内容]
cat /etc/haproxy/haproxy.cfg
global           #全局设置
       log 127.0.0.1   local3      #日志输出配置,所有日志都记录在本机,通过local3输出
       maxconn 4096             	#最大连接数
       chroot /usr/local/haproxy
       user haproxy
       group haproxy
       daemon                   #以后台形式运行haproxy
       nbproc 2                 #启动2个haproxy实例
       pidfile /usr/local/haproxy/haproxy.pid  #将所有进程写入pid文件
defaults             #默认设置
       log    global
       log     127.0.0.1       local3         #日志文件的输出定向
       mode    http         #所处理的类别,默认采用http模式,可配置成tcp作4层消息转发
       option  httplog       #日志类别,采用httplog
       option  dontlognull  #日志中不记录空连接
       option  forwardfor   #如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip
       option  httpclose    #每次请求完毕后主动关闭http通道,haproxy不支持keep-alive,只能模拟这种模式的实现
       retries 3           #3次连接失败就认为服务器不可用,主要通过后面的check检查
       option  redispatch   #当serverid对应的服务器挂掉后,强制定向到其他健康服务器
       maxconn 2000                     #最大连接数
       stats   uri     /haproxy-admin  #haproxy 监控页面的访问地址
       contimeout      5000            #连接超时时间
       clitimeout      50000           #客户端连接超时时间
       srvtimeout      50000           #服务器端连接超时时间
       stats auth  c4rt1y:123456   #设置监控页面的用户和密码:Frank
       stats hide-version         #隐藏统计页面的HAproxy版本信息
frontend www                        #前台
       bind *:80
       default_backend webserver      #静态服务器池
backend webserver                    #后台
       mode http             #不存在继承defaults的mode
       balance leastconn    #负载均衡算法 roundrobin  leastconn
       option  httpchk HEAD /index.htm HTTP/1.0       #健康检查
       server  web1 10.16.0.9:8085 cookie 1 weight 5 check inter 2000 rise 2 fall 3
       server  web2 10.16.0.10:8085 cookie 2 weight 3 check inter 2000 rise 2 fall 3

0x07 haproxy动态维护

#在master上
#对/etc/haproxy/haproxy.cfg中添加
vi /etc/haproxy/haproxy.cfg
global
    stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin #指定socket文件路径,权限,管理级别
   		stats timeout 2m  #指定超时时间
#安装socat yum install -y socat #使用socat连接,查看haproxy帮助信息 echo “help” |socat stdio /var/lib/haproxy/haproxy.sock
clear counters : clear max statistics counters (add ‘all‘ for all counters)
clear table    : remove an entry from a table
help           : this message
prompt         : toggle interactive mode with prompt
quit           : disconnect
show backend   : list backends in the current running config
show info      : report information about the running process   #查看所有信息
show pools     : report information about the memory pools usage  #查看所有poll
show stat      : report counters for each proxy and server  #显示状态
show errors    : report last request and response errors for each proxy  
show sess [id] : report the list of current sessions or dump this session
show table [id]: report table usage stats or dump this table‘s contents
show servers state [id]: dump volatile server information (for backend <id>)
get weight     : report a server‘s current weight #获得权重信息
set weight     : change a server‘s weight #设置权重
set server     : change a server‘s state, weight or address  #改变一个server的转态权重或地址
set table [id] : update or create a table entry‘s data
set timeout    : change a timeout setting
set maxconn    : change a maxconn sett
ing
set rate-limit : change a rate limiting value
disable        : put a server or frontend in maintenance mode #将一个server或者fortend置于维护模式
enable         : re-enable a server or frontend which is in maintenance mode #启用一个维护状态的server或者frontend
shutdown       : kill a session or a frontend (eg:to release listening ports)
show acl [id]  : report avalaible acls or dump an acl‘s contents
get acl        : reports the patterns matching a sample for an ACL  #获取acl
add acl        : add acl entry  #加一个acl
del acl        : delete acl entry  #删一个acl
clear acl <id> : clear the content of this acl 
show map [id]  : report avalaible maps or dump a map‘s contents
get map        : reports the keys and values matching a sample for a map
set map        : modify map entry
add map        : add map entry
del map        : delete map entry
clear map <id> : clear the content of this map
set ssl <stmt> : set statement for ssl
#查看haproxy信息 echo “show info” |socat stdio /var/lib/haproxy/haproxy.sock

0x08 生产环境问题

#更改local的端口范围,调整内核参数(默认32768   60999)
cat /proc/sys/net/ipv4/ip_local_port_range 
#调整timewait的端口复用,设置为1(默认为0,主要是防止tcp_wait)
cat /proc/sys/net/ipv4/tcp_tw_reuse 
#缩短tcp_wait的时间,并不建议修改(默认60)
cat /proc/sys/net/ipv4/tcp_fin_timeout 
#终极方案:增加为多个服务器(多IP)

0x09 资料来源

老男孩十二期
http://cbonte.github.io/haproxy-dconv/1.6/configuration.html#7.4
http://www.mamicode.com/info-detail-1746183.html
GoTop