一、Haproxy简介
HAproxy 是一款高性能的TCP和HTTP负载均衡器。其功能是用来提供基于cookie的持久性,基于内容的交换,过载保护的高级流量管制,自动故障切换,以正则表达式为基础的标题控制运行时间,基于Web的报表,高级日志记录以帮助排除故障的应用或网络,以及其他一些功能。HAProxy运行在当前的硬件上,事件驱动的状态机达到每秒20000点击和超过亿单元以太网,甚至支持数以万计的同步连接。
HAProxy是法国人Willy Tarreau个人开发的一个开源软件,目标是应对客户端10000以上的同时连接,为后端应用服务器、数据库服务器提供高性能的负载均衡服务。在底层数据结构方面,旧版本HAProxy曾经使用过红黑树,用于任务调度、负载均衡等方面。但是Willy Tarreau认为,在事件响应非常频繁的情况下,任务插入、删除的频率非常高,这时候使用红黑树存在性能瓶颈,尤其不能接受红黑树删除节点的时间复杂度为O(log n)。因此,他发明了一种新的数据结构,叫做弹性二叉树(elastic binary tree),简称ebtree。
目前新版本的HAProxy已使用ebtree,而除了HAProxy之外,还没有其它著名的开源软件使用ebtree。可以这么说,HAProxy最有特色的地方就是ebtree,ebtree名符其实是HAProxy的独门武器。
二、Haproxy的特性
HAProxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤其适用于高负载且需要持久连接或7层处理机制的web站点。
客户端侧的长连接(client-side keep-alive)
TCP加速(TCP speedups)
响应池(response buffering)
基于源的粘性(source-based stickiness)
更好的统计数据接口(a much better stats interfaces)
更详细的健康状态检测机制(more verbose health checks)
基于流量的健康评估机制(traffic-based health)
基于ACL的持久性(ACL-based persistence)
ACL:编写内容交换规则;
负载均衡算法(load-balancing algorithms):更多的算法支持;
分层设计(layered design):分别实现套接字、TCP、HTTP处理以提供更好的健壮性、更快的处理机制及便捷的演进能力;
快速、公平调度器(fast and fair scheduler):为某些任务指定优先级可实现理好的QoS;
会话速率限制(session rate limiting):适用于托管环境;
三、Haproxy的性能
HAProxy借助于OS上几种常见的技术来实现性能的最大化。
单进程、事件驱动模型显著降低了上下文切换的开销及内存占用。
O(1)事件检查器(event checker)允许其在高并发连接中对任何连接的任何事件实现即时探测。
在任何可用的情况下,单缓冲(single buffering)机制能以不复制任何数据的方式完成读写操作,这会节约大量的CPU时钟周期及内存带宽;
借助于Linux 2.6 (>= 2.6.27.19)上的splice()系统调用,HAProxy可以实现零复制转发(Zero-copy forwarding),在Linux 3.5及以上的OS中还可以实现零复制启动(zero-starting);
MRU内存分配器在固定大小的内存池中可实现即时内存分配,这能够显著减少创建一个会话的时长;
树型存储:侧重于使用作者多年前开发的弹性二叉树,实现了以O(log(N))的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列;
优化的HTTP首部分析:优化的首部分析功能避免了在HTTP首部分析过程中重读任何内存区域;
精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等;
所有的这些细微之处的优化实现了在中等规模负载之上依然有着相当低的CPU负载,甚至于在非常高的负载场景中,5%的用户空间占用率和95%的系统空间占用率也是非常普遍的现象,这意味着HAProxy进程消耗比系统空间消耗低20倍以上。因此,对OS进行性能调优是非常重要的。即使用户空间的占用率提高一倍,其CPU占用率也仅为10%,这也解释了为何7层处理对性能影响有限这一现象。由此,在高端系统上HAProxy的7层性能可轻易超过硬件负载均衡设备。
在生产环境中,在7层处理上使用HAProxy作为昂贵的高端硬件负载均衡设备故障故障时的紧急解决方案也时长可见。硬件负载均衡设备在“报文”级别处理请求,这在支持跨报文请求(request across multiple packets)有着较高的难度,并且它们不缓冲任何数据,因此有着较长的响应时间。对应地,软件负载均衡设备使用TCP缓冲,可建立极长的请求,且有着较大的响应时间
四、Haproxy基本实现
haproxy的安装,这里演示的为centos 7,通过yum光盘镜像安装
[root@localhost ~]# yum install haproxy [root@localhost ~]# rpm -ql haproxy /etc/haproxy/haproxy.cfg #主配置文件 /etc/logrotate.d/haproxy #日志回滚 /usr/lib/systemd/system/haproxy.service #服务管理单元 /usr/sbin/haproxy #haproxy主程序
这里先实现一个最基本的基于轮询负载负载均衡,先简单简单配置两个httpd服务器
[root@wlw1 ~]# echo ‘My web1 192.168.0.45‘ > /var/www/html/index.html [root@wlw2 ~]# echo ‘My web2 192.168.0.66‘ > /var/www/html/index.html
haproxy服务器配置如下,
vim /etc/haproxy/haproxy.cfg frontend main *:80 default_backend webserver backend webserver balance roundrobin server web.ip45 192.168.0.45:80 check server web.ip66 192.168.0.66:80 check
实验结果,可以看到实现了轮询效果
[root@localhost ~]# curl http://192.168.0.56 My web1 192.168.0.45 [root@localhost ~]# curl http://192.168.0.56 My web2 192.168.0.66 [root@localhost ~]# curl http://192.168.0.56 My web1 192.168.0.45 [root@localhost ~]# curl http://192.168.0.56 My web2 192.168.0.66
五、Haproxy常见全局global配置选项及其用法
①、log:通过logserver记录日志,定义全局的syslog服务器,最多可以定义两个
vim /etc/haproxy/haproxy.cfg global log 127.0.0.1 local2 [root@localhost ~]# vim /etc/rsyslog.conf $ModLoad imudp #开启syslog监听服务 $UDPServerRun 514 local2.* /var/log/haproxy.log
配置好全局日志后通过查看访问日志查询是否成功生效
[root@localhost ~]# tail /var/log/haproxy.log Oct 24 06:25:51 localhost haproxy[1626]: 192.168.0.56:39072 [24/Oct/2015:06:25:51.817] main webserver/web.ip45 4/0/4/8/16 200 289 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Oct 24 06:25:52 localhost haproxy[1626]: 192.168.0.56:39075 [24/Oct/2015:06:25:52.687] main webserver/web.ip66 0/0/1/8/9 200 289 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1" #上面信息,192.168.0.56发送的请求,由main前端响应,这里对应我们配置文件中frontend配置的名字,发送给webserver/web.ip45后端服务器的web.ip45web服务器处理。
②、log-send-hostname <string>:在syslog信息的首部添加当前主机名,可以为“string”指定的名称,也可以缺省使用当前主机名;
③、nbproc <number>:指定启动的haproxy进程的个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
④、ulimit-n <number>:设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计算,因此不推荐修改此选项;
⑤、maxconn <number>:设定每个haproxy进程所接受的最大并发连接数,“ulimit -n”自动计算的结果正是参照此参数设定的;
⑥、spread-checks <0..50, in percent>:在haproxy后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能会带来意外问题;此选项用于将其检查的时间间隔长度上增加或减小一定的随机时长;
六、Haproxy常见全局global配置选项及其用法
①、balance:定义负载均衡算法,可用于“defaults”、“listen”和“backend”。
支持以下算法(动态:权重可动态调整,修改权重后无需重启服务。静态:调整权重不会实时生效,需要重启服务)
roundrobin: 基于权重轮询,动态算法,每个后端主机最多支持4128个连接;
static-rr:基于权重轮询,静态算法,每个后端主机支持的数量无上限;
leastconn:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重;
source:将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议;其默认为静态,不过也可以使用hash-type修改此特性;
uri:对URI的左半部分(“问题”标记之前的部分)或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代理以提高缓存的命中率;需要注意的是,此算法仅应用于HTTP后端服务器场景;其默认为静态算法,不过也可以使用hash-type修改此特性;
URL Syntax: <scheme>://<host>:<port>/<path>;<params>?<query>#<frag>
http://www.wlw.com/test/go;type=s
vim /etc/haproxy/haproxy.cfg frontend main *:80 default_backend webserver backend webserver balance uri hash-type consistent server web.ip45 192.168.0.45:80 check server web.ip66 192.168.0.66:80 check
为了测试出结果。我们为web1和web2各提供五个页面供测试
[root@wlw1 ~]# for i in {1..5};do echo "Page $i from web.ip45" > /var/www/html/page$i.html;done [root@wlw2 ~]# for i in {1..5};do echo "Page $i from web.ip66" > /var/www/html/page$i.html;done
这里我们使用三个客户端来测试结果,可以看到只要是访问同一个uri都是调度到同一台服务器上
[root@localhost ~]# curl http://192.168.0.56/page1.html Page 1 from web.ip66 [root@wlw1 ~]# curl http://192.168.0.56/page1.html Page 1 from web.ip66 [root@wlw2 ~]# curl http://192.168.0.56/page1.html Page 1 from web.ip66 [root@localhost ~]# curl http://192.168.0.56/page4.html Page 4 from web.ip45 [root@wlw1 ~]# curl http://192.168.0.56/page4.html Page 4 from web.ip45 [root@wlw2 ~]# curl http://192.168.0.56/page4.html Page 4 from web.ip45
url_param:通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,那么此值将被执行hash运算并被服务器的总权重相除后派发至某匹配的服务器;此算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度;此算法默认为静态的,不过其也可以使用hash-type修改此特性;
hdr(<name>):对于每个HTTP请求,通过<name>指定的HTTP首部将会被检索;如果相应的首部没有出现或其没有有效值,则使用轮叫算法对相应请求进行调度;其有一个可选选项“use_domain_only”,可在指定检索类似Host类的首部时仅计算域名部分(比如通过www.magedu.com来说,仅计算magedu字符串的hash值)以降低hash算法的运算量;此算法默认为静态的,不过其也可以使用hash-type修改此特性;
②、hash-type <method>
定义用于将hash码映射至后端服务器的方法;其不能用于frontend区段;可用方法有map-based和consistent,在大多数场景下推荐使用默认的map-based方法。
map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。
本文出自 “马尔高” 博客,请务必保留此出处http://kgdbfmwfn.blog.51cto.com/5062471/1705723
原文:http://kgdbfmwfn.blog.51cto.com/5062471/1705723