HAProxy提供高可用性(体现在可以对后端RS的健康检查)、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在时下的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
HAProxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。
HAProxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤其适用于高负载且需要持久连接或7层处理机制的web站点。
HAProxy是基于事件驱动机制的,为默认单一进程响应多个请求的工作模式(而且官方建议也不让改),而Nginx则是生成多个worker进程,每个worker进程响应多个请求;在此模式下HAProxy支持非常大的并发连接数,而多进程或多线程模型受内存限制,系统调度器限制级锁限制,但此模式在多核OS上,程序的扩展性较差
HAProxy的单进程,事件驱动机制显著降低了CPU在上下文切换上的开销及对内存的占用
HAProxy的O(1)事件检查器允许其在高并发的连接中对任何连接的任何事件实现即时探测
HAProxy在任何可用的情况下,其单缓冲(single buffering)机制能以不复制任何数据的方式完成读写操作,类似于内存映射,将数据单缓冲在隔模块之间的实现共享所以不用复制任何数据,这会节约大量的CPU时钟周期及内存带宽;
HAProxy借助于Linux 2.6 (>= 2.6.27.19)上的splice()系统调用,可以实现零复制转发(Zero-copy forwarding)类似于send-file,在Linux 3.5及以上的OS中还可以实现零复制启动(zero-starting);
HAProxyMRU内存分配器在固定大小的内存池中可实现即时内存分配,这能够显著减少创建一个会话的时长;
HAProxy树型存储:侧重于使用作者多年前开发的弹性二叉树,实现了以O(log(N))(仅次于0(1)机制)的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列;
HAProxy优化的HTTP首部分析:优化的首部分析功能避免了在HTTP首部分析过程中重读任何内存区域;
HAProxy精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等;
HAProxy在进行client请求调度时,可以根据请求的URL进行调度,将相同URL的请求转发到同一台后端RS上,这种调度方法在反向代理用户请求到缓存server上非常适用,因为一般的数据缓存就是其根据URL进行的,这可以大大提高缓存的命中率;而Nginx则可以依赖url_hash实现根据URL进行调度,但Nginx本身不支持url_hash,如果需要这种调度算法,则必须安装Nginx的hash软件包。
所谓send-file。就是数据返回给client时本来要经过以下步骤
硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎
但send-file机制为
硬盘—>内核buf->socket相关缓冲区—>协议引擎
可以看到数据不必从内核空间复制带用户空间,而是直接通过端口进行传输,send-file机制提高了数据的传输的性能,纤细请看下面的连接
http://calmness.iteye.com/blog/378463
HAProxy还可以从web界面进行登录连接,进行对后端RS的状态监控
可以从以下三个因素评估负载均衡的性能
1:会话率 单位时间内完成的会话数
2:会话的并发能力 单位时间内持有的会话数
3:数据率 单位时间内实现数据交换的能力
HAProxy的配置处理3类来主要参数来源:
——最优先处理的命令行参数,
——“global”配置段,用于设定全局配置参数;
——proxy相关配置段,如“defaults”、“listen”、“frontend”和“backend”;
HAProxy有许多时间参数,如超时时长。这些值一般以毫秒为单位,但也可以使用其它的时间单位后缀。
us: 微秒(microseconds),即1/1000000秒;
ms: 毫秒(milliseconds),即1/1000秒;
s: 秒(seconds);
m: 分钟(minutes);
h:小时(hours);
d: 天(days);
定义负载均衡算法,可用于“defaults”、“listen”和“backend”
支持的算法有:
roundrobin:基于权重进行轮叫,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,这表示其权重可以在运行时进行调整,不过,在设计上,每个后端服务器仅能最多接受4128个连接;
static-rr:基于权重进行轮叫,与roundrobin类似,但是为静态方法,在运行时调整其服务器权重不会生效;不过,其在后端服务器连接数上没有限制;
leastconn:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重;
source:将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议;其默认为静态,不过也可以使用hash-type修改此特性;
uri:对URI的左半部分(“问题”标记之前的部分)或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代理以提高缓存的命中率;需要注意的是,此算法仅应用于HTTP后端服务器场景;其默认为静态算法,不过也可以使用hash-type修改此特性;
url_param:通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,那么此值将被执行hash运算并被服务器的总权重相除后派发至某匹配的服务器;此算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度;此算法默认为静态的,不过其也可以使用hash-type修改此特性;
hdr(<name>):对于每个HTTP请求,通过<name>指定的HTTP首部将会被检索;如果相应的首部没有出现或其没有有效值,则使用轮叫算法对相应请求进行调度;其有一个可选选项“use_domain_only”,可在指定检索类似Host类的首部时仅计算域名部分(比如通过www.zxl.com来说,仅计算zxl字符串的hash值)以降低hash算法的运算量;此算法默认为静态的,不过其也可以使用hash-type修改此特性;
rdp-cookie 基于cookie的调度算法
hash-type <method>:定义用于将hash码映射至后端服务器的方法;其不能用于frontend区段;可用方法有map-based和consistent,在大多数场景下推荐使用默认的map-based方法。
map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。
实验环境
node1: eth0 192.168.139.2(可访问公网)
eth1 192.168.10.7
node4: 192.168.10.8 网关:192.168.10.7
node5: 192.168.10.9 网关:192.168.10.7
其中在node1上装有HAProxy,用作负载均衡调度器
node4|node5装有httpd,用来作为后端的RS_Server
为了让后端RS不暴露在外网环境下(安全考虑),本次实验采用node4|node5的IP与node1(调度器)的eth0不再一个网段的方法,所以先为node1添加一个网卡,作为node4|nde5的网关
开启node1|node4|node5
[root@node1 ~]# ifconfig -a
eth0 Link encap:Ethernet HWaddr 00:0C:29:1C:13:12
inet addr:192.168.139.2 Bcast:192.168.139.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe1c:1312/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6137 errors:0 dropped:0 overruns:0 frame:0
TX packets:3743 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:403125 (393.6 KiB) TX bytes:239297 (233.6 KiB)
eth1 Link encap:Ethernet HWaddr 00:0C:29:1C:13:1C
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
为新添的网卡eth1配置IP
[root@node1 ~]# ifconfig eth1 192.168.10.7/24 up
[root@node1 ~]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:1C:13:12
inet addr:192.168.139.2 Bcast:192.168.139.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe1c:1312/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6707 errors:0 dropped:0 overruns:0 frame:0
TX packets:4103 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:449123 (438.5 KiB) TX bytes:272859 (266.4 KiB)
eth1 Link encap:Ethernet HWaddr 00:0C:29:1C:13:1C
inet addr:192.168.10.7 Bcast:192.168.10.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe1c:131c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:208 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:13954 (13.6 KiB) TX bytes:328 (328.0 b)
配置node4|node5的网关和IP并启动httpd
[root@node4 ~]# ifconfig eth0 192.168.10.8/24 up
[root@node4 ~]#route add default gw 192.168.139.7
[root@node4 ~]#service httpd start
[root@node5 ~]# ifconfig eth0 192.168.10.8/24 up
[root@node5 ~]# route add default gw 192.168.139.7
[root@node4 ~]#service httpd start
[root@node1 ~]# curl http://192.168.10.8
<h1>node4.zxl.com</h1>
[root@node1 ~]# curl http://192.168.10.9
<h1>node5.zxl.com</h1>
在node1上安装HAProxy
[root@node1 ~]# yum install -y haproxy
[root@node1 ~]# cd /etc/haproxy/
[root@node1 haproxy]# cp haproxy.cfg haproxy.cfg.bak
要启用本机的日志功能local2要做以下配置
[root@node1 haproxy]# vim /etc/sysconfig/rsyslog
SYSLOGD_OPTIONS="-c 2 -r"
[root@node1 haproxy]# vim /etc/rsyslog.conf
local2.* /var/log/haproxy.log
[root@node1 haproxy]# service rsyslog restart
Shutting down system logger: [ OK ]
Starting system logger: [ OK ]
[root@node1 haproxy]# vim haproxy.cfg
global #全局端配置
log 127.0.0.1 local2 #启用本机的日志功能local2
chroot /var/lib/haproxy #chroot限制根目录 /var/lib/haproxy 安全
pidfile /var/run/haproxy.pid #pid文件
maxconn 4000 #设定一个前端的最大并发连接数为4000,因此其不能用于backend区段
user haproxy #以HAProxy用户身份运行
group haproxy #以HAProxy组身份运行
daemon #让haproxy以守护进程的方式工作于后台
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults #为所有其它配置段提供默认参数
mode http #设定实例的运行模式或协议,若调度mysql则为tcp
log global #当前实例的日志系统参数同"global"段中的定义
option httplog #启用记录HTTP请求、会话状态和计时器的功能。
#默认情况下,日志输入格式非常简陋,因为其仅包括源 #地址、目标地址和实例名称,而“option httplog”参 #数将会使得日志格式变得丰富许多,其通常包括但不限 #于HTTP请求、连接计时器、会话状态、连接数、捕获的 #首部及cookie、“frontend”、“backend”及服务器 #名称,当然也包括源地址和端口号等。
option dontlognull #不要记录空日志
option http-server-close
option forwardfor except 127.0.0.0/8 #除了来自本机的请求(本机本身为DR),在发往服务器的请求首部中插入“X-Forwarded-For”首部。通Nginx的X-Real-IP,可以记录真实的client IP
option redispatch
retries 3 #重试次数3
timeout http-request 10s #下面则是一些关于时间的定义,一般默认就行
timeout queue 1m
timeout connect 0s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen stats #“listen”段通过关联“前端”和“后端”定义了一个完整的代理,通常只对 #TCP流量有用。
mode http #值可以为http|tcp|health
bind 0.0.0.0:1080 #定义一个或几个监听的套接字,监听在所有地址的1080端口,进行状态监控
stats enable #启用基于程序编译时默认设置的统计报告(监控),不能用于“frontend”区段
stats hide-version #隐藏HAProxy的版本号(防止有人知道版本号后查到相应的系统漏洞)
stats uri /haproxyadmin?stats #根据这个URI进行监控页面的访问
stats realm Haproxy\ Statistics #认证时的提示信息,\为脱义符后面有空格
stats auth admin:zxl #用户名和密码
stats admin if TRUE #如果认证成功则打开web监控管理界面
frontend http-in #http-in随便给的名称,“frontend”段用于定义一系列监听的套接字,这些套接 #字可接受客户端请求并与之建立连接。
bind *:80 #通过80端口向外提供服务(web)
mode http
log global #启用提前将HTTP请求记入日志,不能用于“backend”区段。
option httpclose
option logasap
option dontlognull #不要记录空日志
capture request header Host len 20 捕获并记录指定的请求首部最近一次出现时的第一个值为HOST(主机)的请求报文的前20个字节并保留下来
capture request header Referer len 60#捕获并记录指定的请求首部最近一次出现时的第一个值为Referer的请求报文的前20个字节并保留下来
default_backend servers #在没有匹配的"use_backend"规则时为实例指定使用的默认后 #端,因此,其不可应用于backend区段。
frontend healthcheck #定义一个健康检查段
bind :1099 #用1099端口进行健康状态检查
mode http
option httpclose #为每一个请求都附加此首部“X-Forwarded-For”
option forwardfor #允许在发往服务器的请求首部中插入“X-Forwarded-For”首部。
default_backend servers
backend servers #“backend”段用于定义一系列“后端”服务器,代理将会将对应客 #户端的请求转发至这些服务器。
balance roundrobin #使用roundrobin调度算法
server websrv1 192.168.10.8:80 check port 80 inter 2 rise 1 fall 2 maxconn 2000
server websrv2 192.168.10.9:80 check port 80 inter 2 rise 1 fall 2 maxconn 2000
#check:启动对此server执行健康状态检查,检查端口80
#inter:设定健康状态检查的时间间隔,单位为毫秒,默认为2000;也可以使用fastinter和 downinter 来根据服务器端状态优化此时间延迟;
#rise:某离线的server从离线状态转换至正常状态需要成功检查的次数;
#fall:确认server从正常状态转换为不可用状态需要检查的次数;
[root@node1 haproxy]# service haproxy start
Starting haproxy: [ OK ]
[root@node1 haproxy]# netstat -tnlp |grep haproxy
tcp 0 0.0.0.0:1099 0.0.0.0:* LISTEN 2007/haproxy
tcp 0 0.0.0.0:80 0.0.0.0:* LISTEN 2007/haproxy
tcp 0 0.0.0.0:1080 0.0.0.0:* LISTEN 2007/haproxy
可以看到启动时执行的是以下命令
[root@node1 haproxy]# ps aux |grep haproxy
haproxy /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
浏览器测试
刷新
登录监控web界面
登入监控界面
负载均衡MySQL服务的配置如下
[root@node1 haproxy]# vim haproxy.cfg
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 #mysql为tcp模式
log global
default_backend mysqlservers
backend mysqlservers
balance leastconn
server dbsrv1 192.168.10.8:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
server dbsrv2 192.168.10.9:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
本次实验完毕!
本文出自 “11097124” 博客,请务必保留此出处http://11107124.blog.51cto.com/11097124/1887016
原文地址:http://11107124.blog.51cto.com/11097124/1887016