HAProxy简介
HAProxy是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,HAProxy是完全免费的、借助HAProxy可以快速并且可靠的提供基于TCP和HTTP应用的代理解决方案。HAProxy稳定性也是非常好,可以与硬件级的F5相媲美,根据官方文档,HAProxy可以跑满10Gbps – New benchmark of HAProxy at 10Gbps using Myricom’s 10GbE NICs(Myri-10G PCI-Express),这个数值作为软件级负载均衡器是相当惊人的。
其配置简单,而且拥有很好的对服务器节点的健康检查功能(相当于keepalived健康检查),当其代理的后端服务器出现故障时,HAProxy会自动的将该故障服务器摘除,当服务器的故障恢复后HAProxy还会自动重新添加回服务器主机。
负载平衡的类型
无负载平衡
没有负载平衡的简单Web应用程序环境可能如下所示
在此示例中,用户直接连接到您的Web服务器,在yourdomain.com上,并且没有负载平衡。如果您的单个Web服务器出现故障,用户将无法再访问您的Web服务器。此外,如果许多用户试图同时访问您的服务器并且无法处理负载,他们可能会遇到缓慢的体验,或者可能根本无法连接。
4层负载平衡
将网络流量负载平衡到多个服务器的最简单方法是使用第4层(传输层)负载平衡。以这种方式进行负载均衡将根据IP范围和端口转发用户流量(即,如果请求进入http://yourdomain.com/anything,则流量将转发到处理yourdomain.com的所有请求的后端。端口80)。
用户访问负载均衡器,负载均衡器将用户的请求转发给后端服务器的Web后端组。无论选择哪个后端服务器,都将直接响应用户的请求。通常,Web后端中的所有服务器应该提供相同的内容-否则用户可能会收到不一致的内容。
所谓的四层就是ISO参考模型中的第四层。四层负载均衡也称为四层交换机,它主要是通过分析IP层及TCP/UDP层的流量实现的基于IP加端口的负载均衡。常见的基于四层的负载均衡器有LVS、F5等。
以常见的TCP应用为例,负载均衡器在接收到第一个来自客户端的SYN请求时,会通过设定的负载均衡算法选择一个最佳的后端服务器,同时将报文中目标IP地址修改为后端服务器IP,然后直接转发给该后端服务器,这样一个负载均衡请求就完成了。从这个过程来看,一个TCP连接是客户端和服务器直接建立的,而负载均衡器只不过完成了一个类似路由器的转发动作。在某些负载均衡策略中,为保证后端服务器返回的报文可以正确传递给负载均衡器,在转发报文的同时可能还会对报文原来的源地址进行修改。
7层负载平衡
7层负载平衡是更复杂的负载均衡网络流量的方法是使用第7层(应用层)负载均衡。使用第7层允许负载均衡器根据用户请求的内容将请求转发到不同的后端服务器。这种负载平衡模式允许您在同一域和端口下运行多个Web应用程序服务器。
示例中,如果用户请求yourdomain.com/blog,则会将其转发到博客后端,后端是一组运行博客应用程序的服务器。其他请求被转发到web-backend,后端可能正在运行另一个应用程序。
七层负载均衡器也称为七层交换机,位于OSI的最高层,即应用层,此时负载均衡器支持多种应用协议,常见的有HTTP、FTP、SMTP等。七层负载均衡器可以根据报文内容,再配合负载均衡算法来选择后端服务器,因此也称为”内容交换器”。比如,对于Web服务器的负载均衡,七层负载均衡器不但可以根据”IP+端口”的方式进行负载分流,还可以根据网站的URL、访问域名、浏览器类别、语言等决定负载均衡的策略。例如,有两台Web服务器分别对应中英文两个网站,两个域名分别是A、B,要实现访问A域名时进入中文网站,访问B域名时进入英文网站,这在四层负载均衡器中几乎是无法实现的,而七层负载均衡可以根据客户端访问域名的不同选择对应的网页进行负载均衡处理。常见的七层负载均衡器有HAproxy、Nginx等。
这里仍以常见的TCP应用为例,由于负载均衡器要获取到报文的内容,因此只能先代替后端服务器和客户端建立连接,接着,才能收到客户端发送过来的报文内容,然后再根据该报文中特定字段加上负载均衡器中设置的负载均衡算法来决定最终选择的内部服务器。纵观整个过程,七层负载均衡器在这种情况下类似于一个代理服务器。
对比四层负载均衡和七层负载均衡运行的整个过程,可以看出,在七层负载均衡模式下,负载均衡器与客户端及后端的服务器会分别建立一次TCP连接,而在四层负载均衡模式下,仅建立一次TCP连接。由此可知,七层负载均衡对负载均衡设备的要求更高,而七层负载均衡的处理能力也必然低于四层模式的负载均衡。
HAProxy的核心功能
- 负载均衡:L4和L7两种模式,支持RR/静态RR/LC/IP Hash/URI Hash/URL_PARAM Hash/HTTP_HEADER Hash等丰富的负载均衡算法
- 健康检查:支持TCP和HTTP两种健康检查模式
- 会话保持:对于未实现会话共享的应用集群,可通过Insert Cookie/Rewrite Cookie/Prefix Cookie,以及上述的多种Hash方式实现会话保持
- SSL:HAProxy可以解析HTTPS协议,并能够将请求解密为HTTP后向后端传输
- HTTP请求重写与重定向
- 监控与统计:HAProxy提供了基于Web的统计信息页面,展现健康状态和流量数据。基于此功能,使用者可以开发监控程序来监控HAProxy的状态
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层性能可轻易超过硬件负载均衡设备。
稳定性
- 作为建议以单进程模式运行的程序,HAProxy对稳定性的要求是十分严苛的。按照作者的说法,HAProxy在13年间从未出现过一个会导致其崩溃的BUG,HAProxy一旦成功启动,除非操作系统或硬件故障,否则就不会崩溃(我觉得可能多少还是有夸大的成分)。
- HAProxy的大部分工作都是在操作系统内核完成的,所以HAProxy的稳定性主要依赖于操作系统,作者建议使用6或3.x的Linux内核,对sysctls参数进行精细的优化,并且确保主机有足够的内存。这样HAProxy就能够持续满负载稳定运行数年之久。
负载均衡算法
负载均衡算法用于检测后端中的哪套服务器被负载均衡机制选定进行请求响应。HAProxy提供多种算法选项。除了负载均衡算法之外,我们还能够为服务器分配一个weight参数来指定该服务器被选定的频率。由于HAProxy提供多种负载均衡算法,下面说明几种常用的算法:
- roundrobin。表示简单的轮询,每个服务器根据权重轮流使用,在服务器的处理时间平均分配的情况下这是最流畅和公平的算法。该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。
- leastconn。连接数最少的服务器优先接收连接。leastconn建议用于长会话服务,例如LDAP、SQL、TSE等,而不适合短会话协议。如该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。
- static-rr。每个服务器根据权重轮流使用,类似roundrobin,但它是静态的,意味着运行时修改权限是无效的。另外,它对服务器的数量没有限制。(该算法一般不用)
- source。对请求源IP地址进行哈希,用可用服务器的权重总数除以哈希值,根据结果进行分配。只要服务器正常,同一个客户端IP地址总是访问同一个服务器。如果哈希的结果随可用服务器数量而变化,那么客户端会定向到不同的服务器。(算法一般用于不能插入cookie的Tcp模式。它还可以用于广域网上为拒绝使用会话cookie的客户端提供最有效的粘连)该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据”hash-type”的变化做调整。
- uri。表示根据请求的URI左端(问号之前)进行哈希,用可用服务器的权重总数除以哈希值,根据结果进行分配。只要服务器正常,同一个URI地址总是访问同一个服务器。一般用于代理缓存和反病毒代理,以最大限度的提高缓存的命中率。该算法只能用于HTTP后端。(该算法一般用于后端是缓存服务器)。该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据”hash-type”的变化做调整。
- url_param。在HTTPGET请求的查询串中查找<param>中指定的URL参数,基本上可以锁定使用特制的URL到特定的负载均衡器节点的要求。(该算法一般用于将同一个用户的信息发送到同一个后端服务器)。该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据”hash-type”的变化做调整。
- hdr(name)。在每个HTTP请求中查找HTTP头<name>,HTTP头<name>将被看作在每个HTTP请求,并针对特定的节点。(如果缺少头或者头没有任何值,则用roundrobin代替)。该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据”hash-type”的变化做调整。
- rdp-cookie(name)。为每个进来的TCP请求查询并哈希RDPcookie<name>。(该机制用于退化的持久模式,可以使同一个用户或者同一个会话ID总是发送给同一台服务器。如果没有cookie,则使用roundrobin算法代替)。该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据”hash-type”的变化做调整。常用的负载均衡算法
HAProxy工作原理
HAProxy提供高可用、负载均衡以及基于TCP(第四层)和HTTP(第七层)的应用的代理,支持虚拟主机,他是免费、快速并且可靠的一种解决方案。HAProxy特别是用于那些负载特别大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在时下的硬件上,完全可以支持数以万计的并发连接,并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。
HAProxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发链接。事件驱动模型因为在有更好的资源和时间管理的用户端(user-space)实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以及使每个CPU时间片(Cycle)做更多的工作。
Haproxy软件引入了frontend,backend的功能,frontend(acl规则匹配)可以根据任意HTTP请求头做规则匹配,然后把请求定向到相关的backend(serverpools等待前端把请求转过来的服务器组)。通过frontend和backend,可以很容易的实现Haproxy的7层负载均衡代理功能。
访问控制列表(ACL)
在负载均衡中,ACL用于测试某些状况,并根据测试结果执行某些操作(例如选定一套服务器或者屏蔽某条请求),如下ACL示例
acl url_blog path_beg /blog
如果用户请求的路径以/blog开头,则匹配这条ACL。举例来说,http://www.cnblogs.com/blog/blog-entry-1请求即符合这一条件。
Backend
所谓的backend是指一组服务器,负责接收各转发请求。Backend在HAProxy配置中的backend部分进行定义。一般来讲,backend的定义主要包括:
- 使用哪种负载均衡算法
- 一套服务器与端口列表
一条backend能够容纳一套或者多套服务器一一总体而言向backend中添加更多服务器将能够将负载扩散至更多的服务器,从而增加潜在负载容量。这种方式也能够提升可靠性,从而应对服务器发生故障的情况。
下面来看一套双backend配置示例,分别为web-backend与blog-backend,其各自包含两套web服务器,且监听端口80:
backend web-backend balance roundrobin server web1 web1.kevin.com:80 check server web2 web2.kevin.com:80 check backend blog-backend balance roundrobin mode http server blog1 blog1.kevin.com:80 check server blog2 blog2.kevin.com:80 check
其中:
- balance roundrobin行指定负载均衡算法,具体细节参考负载均衡算法部分
- mode http则指定所使用的7层代理机制,具体参考负载均衡类型部分
- 结尾处的check选项指定在这些后端服务器上执行运行状态检查
Frontend
一条frontend负责定义请求如何被转发至backend。Frontend在HAProxy配置中的frontend部分。其定义由以下几个部分组成:
- 一组IP地址与一个端口(例如1.1.2:80,*:443,等等)
- ACL
use_backend 规则,其负责根据当前 ACL 条件定义使用哪个 backend,而 default_backend 规则处理一切其它情况
可以将同一 frontend 配置至多种不同网络流量类型!
同一客户端访问服务器,HAProxy 保持会话的三种方案:
- HAProxy 将客户端 IP 进行 Hash 计算并保存,由此确保相同 IP 来访问时被转发到同一台真实服务器上。
- HAProxy 依靠真实服务器发送给客户端的 cookie 信息进行会话保持。
- HAProxy 保存真实服务器的 session 及服务器标识,实现会话保持功能。
HAProxy 的安装与配置
以下内容出自网络,安装的版本较低,但内容不叫全面,还是有非常的参考意义。
HAProxy 的安装
为 HAProxy 创建用户和用户组,此例中用户和用户组都是”ha”。注意,如果想要让 HAProxy 监听 1024 以下的端口,则需要以 root 用户来启动。
# 下载并解压 wget http://www.haproxy.org/download/1.7/src/haproxy-1.7.2.tar.gz tar -xzf haproxy-1.7.2.tar.gz # 编译并安装 make PREFIX=/home/ha/haproxy TARGET=linux2628 make install PREFIX=/home/ha/haproxy
PREFIX 为指定的安装路径,TARGET 则根据当前操作系统内核版本指定:
- linux22 for Linux 2.2
- linux24 for Linux 2.4 and above (default)
- linux24e for Linux 2.4 with support for a working epoll (>0.21)
- linux26 for Linux 2.6 and above
- linux2628 for Linux 2.6.28, 3.x, and above (enables splice and tproxy)
此例中,我们的操作系统内核版本为 3.10.0,所以 TARGET 指定为 linux2628创建 HAProxy 配置文件
mkdir -p /home/ha/haproxy/conf vi /home/ha/haproxy/conf/haproxy.cfg
我们先创建一个最简单配置文件:
global # 全局属性 daemon # 以 daemon 方式在后台运行 maxconn 256 # 最大同时 256 连接 pidfile /home/ha/haproxy/conf/haproxy.pid # 指定保存 HAProxy 进程号的文件 defaults # 默认参数 mode http # http 模式 timeout connect 5000ms # 连接 server 端超时 5s timeout client 50000ms # 客户端响应超时 50s timeout server 50000ms # server 端响应超时 50s frontend http-in # 前端服务 http-in bind *:8080 # 监听 8080 端口 default_backend servers # 请求转发至名为"servers"的后端服务 backend servers # 后端服务 servers server server1 127.0.0.1:8000 maxconn 32 # backend servers 中只有一个后端服务,名字叫 server1,起在本机的 8000 端口,HAProxy 同时最多向这个服务发起 32 个连接
注意:HAProxy 要求系统的 ulimit -n 参数大于 [maxconn*2+18],在设置较大的 maxconn 时,注意检查并修改 ulimit -n 参数将 HAProxy 注册为系统服务
在 /etc/init.d 目录下添加 HAProxy 服务的启停脚本:
vi /etc/init.d/haproxy #!/bin/sh set -e PATH=/sbin:/bin:/usr/sbin:/usr/bin:/home/ha/haproxy/sbin PROGDIR=/home/ha/haproxy PROGNAME=haproxy DAEMON=$PROGDIR/sbin/$PROGNAME CONFIG=$PROGDIR/conf/$PROGNAME.cfg PIDFILE=$PROGDIR/conf/$PROGNAME.pid DESC="HAProxy daemon" SCRIPTNAME=/etc/init.d/$PROGNAME # Gracefully exit if the package has been removed. test -x $DAEMON || exit 0 start() { echo -e "Starting $DESC: $PROGNAME\n" $DAEMON -f $CONFIG echo "." } stop() { echo -e "Stopping $DESC: $PROGNAME\n" haproxy_pid="$(cat $PIDFILE)" kill $haproxy_pid echo "." } restart() { echo -e "Restarting $DESC: $PROGNAME\n" $DAEMON -f $CONFIG -p $PIDFILE -sf $(cat $PIDFILE) echo "." } case "$1" in start) start ;; stop) stop ;; restart) restart ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2 exit 1 ;; esac exit 0
启动、停止和重启
service haproxy start service haproxy stop service haproxy restart
添加日志
HAProxy 不会直接输出文件日志,所以我们要借助 Linux 的 rsyslog 来让 HAProxy 输出日志。
修改 haproxy.cfg,在 global 域和 defaults 域中添加:
global ... log 127.0.0.1 local0 info log 127.0.0.1 local1 warning ... defaults ... log global ...
意思是将 info 级(及以上)的日志推送到 rsyslog 的 local0 接口,将 warn 级(及以上)的日志推送到 rsyslog 的 local1 接口,并且所有 frontend 都默认使用 global 中的日志配置。
注:info 级的日志会打印 HAProxy 处理的每一条请求,会占用很大的磁盘空间,在生产环境中,建议将日志级别调整为 notice为 rsyslog 添加 haproxy 日志的配置
vi /etc/rsyslog.d/haproxy.conf $ModLoad imudp $UDPServerRun 514 $FileCreateMode 0644 # 日志文件的权限 $FileOwner ha # 日志文件的 owner local0.* /var/log/haproxy.log # local0 接口对应的日志输出文件 local1.* /var/log/haproxy_warn.log # local1 接口对应的日志输出文件
修改 rsyslog 的启动参数
vi /etc/sysconfig/rsyslog # Options for rsyslogd # Syslogd options are deprecated since rsyslog v3. # If you want to use them, switch to compatibility mode 2 by "-c2" # See rsyslogd(8) for more details SYSLOGD_OPTIONS="-c2 -r -m0"
重启 rsyslog 和 HAProxy
service rsyslog restart service haproxy restart
此时就应该能在/var/log目录下看到haproxy的日志文件了用logrotate进行日志切分
通过rsyslog输出的日志是不会进行切分的,所以需要依靠Linux提供的logrotate(Linux系统Logrotate服务介绍)来进行切分工作
使用root用户,创建haproxy日志切分配置文件:
mkdir /root/logrotate vi /root/logrotate/haproxy /var/log/haproxy.log /var/log/haproxy_warn.log { #切分的两个文件名 daily #按天切分 rotate 7 #保留7份 create 0644 haha #创建新文件的权限、用户、用户组 compress #压缩旧日志 delaycompress #延迟一天压缩 missingok #忽略文件不存在的错误 dateext #旧日志加上日志后缀 sharedscripts #切分后的重启脚本只运行一次 postrotate #切分后运行脚本重载rsyslog,让rsyslog向新的日志文件中输出日志 /bin/kill -HUP $(/bin/cat /var/run/syslogd.pid 2>/dev/null) &>/dev/null endscript } 并配置在crontab中运行: 00 * * * /usr/sbin/logrotate /root/logrotate/haproxy
HAProxy搭建L7负载均衡器
总体方案
本节中,我们将使用HAProxy搭建一个L7负载均衡器,应用如下功能:负载均衡、会话保持、健康检查、根据URI前缀向不同的后端集群转发、监控页面。架构如下:
架构中共有6个后端服务,划分为3组,每组中2个服务:
- ms1:服务URI前缀为ms1/的请求
- ms2:服务URI前缀为ms2/的请求
- def:服务其他请求
搭建后端服务
部署6个后端服务,可以使用任意的Web服务,如Nginx、Apache HTTPD、Tomcat、Jetty等,具体Web服务的安装过程省略。
此例中,我们在192.168.8.111和192.168.8.112两台主机上分别安装了3个Nginx:
- srv1-192.168.8.111:8080
- srv2-192.168.8.112:8080
- srv1-192.168.8.111:8081
- srv2-192.168.8.112:8081
- srv1-192.168.8.111:8082
- srv2-192.168.8.112:8082
在这6个Nginx服务分别部署健康检查页面healthCheck.html,页面内容任意。确保通过http://ip:port/healthCheck.html可以访问到这个页面
接下来在6个Nginx服务中部署服务页面:
- 在第一组中部署ms1/demo.html
- 在第二组中部署ms2/demo.html
- 在第三组中部署def/demo.html
demo.html的内容,以部署在192.168.8.111:8080上的为例:Hello! This is ms1.srv1!部署在192.168.8.112:8080上的就应该是Hello! This is ms1.srv2!以此类推。
搭建HAProxy
在192.168.8.110主机安装HAProxy,HAProxy的安装和配置步骤如上一章中描述,此处略去。
HAProxy配置文件:
global daemon maxconn 30000 #ulimit -n至少为60018 user ha pidfile /home/ha/haproxy/conf/haproxy.pid log 127.0.0.1 local0 info log 127.0.0.1 local1 warning defaults mode http log global option http-keep-alive #使用keepAlive连接 option forwardfor #记录客户端IP在X-Forwarded-For头域中 option httplog #开启httplog,HAProxy会记录更丰富的请求信息 timeout connect 5000ms timeout client 10000ms timeout server 50000ms timeout http-request 20000ms #从连接创建开始到从客户端读取完整HTTP请求的超时时间,用于避免类DoS攻击 option httpchk GET /healthCheck.html #定义默认的健康检查策略 frontend http-in bind *:9001 maxconn 30000 #定义此端口上的maxconn acl url_ms1 path_beg -i /ms1/ #定义ACL,当uri以/ms1/开头时,ACL[url_ms1]为true acl url_ms2 path_beg -i /ms2/ #同上,url_ms2 use_backend ms1 if url_ms1 #当[url_ms1]为true时,定向到后端服务群ms1中 use_backend ms2 if url_ms2 #当[url_ms2]为true时,定向到后端服务群ms2中 default_backend default_servers #其他情况时,定向到后端服务群default_servers中 backend ms1 #定义后端服务群ms1 balance roundrobin #使用RR负载均衡算法 cookie HA_STICKY_ms1 insert indirect nocache #会话保持策略,insert名为"HA_STICKY_ms1"的cookie #定义后端server[ms1.srv1],请求定向到该server时会在响应中写入cookie值[ms1.srv1] #针对此server的maxconn设置为300 #应用默认健康检查策略,健康检查间隔和超时时间为2000ms,两次成功视为节点UP,三次失败视为节点DOWN server ms1.srv1 192.168.8.111:8080 cookie ms1.srv1 maxconn 300 check inter 2000ms rise 2 fall 3 #同上,inter 2000ms rise 2 fall 3是默认值,可以省略 server ms1.srv2 192.168.8.112:8080 cookie ms1.srv2 maxconn 300 check backend ms2 #定义后端服务群ms2 balance roundrobin cookie HA_STICKY_ms2 insert indirect nocache server ms2.srv1 192.168.8.111:8081 cookie ms2.srv1 maxconn 300 check server ms2.srv2 192.168.8.112:8081 cookie ms2.srv2 maxconn 300 check backend default_servers #定义后端服务群default_servers balance roundrobin cookie HA_STICKY_def insert indirect nocache server def.srv1 192.168.8.111:8082 cookie def.srv1 maxconn 300 check server def.srv2 192.168.8.112:8082 cookie def.srv2 maxconn 300 check listen stats #定义监控页面 bind *:1080 #绑定端口1080 stats refresh 30s #每30秒更新监控数据 stats uri /stats #访问监控页面的uri stats realm HAProxy\ Stats #监控页面的认证提示 stats auth admin:admin #监控页面的用户名和密码
修改完成后,启动HAProxy。
service haproxy start
测试
首先,访问一下监控页面 http://192.168.8.110:1080/stats 并按提示输入用户名密码接下来就能看到监控页面:
监控页面中列出了我们配置的所有frontend和backend服务,以及它们的详细指标。如连接数,队列情况,session rate,流量,后端服务的健康状态等等
接下来,我们一一测试在HAProxy中配置的功能健康检查
从监控页面中就可以直接看出健康检查配置的是否正确,上图中可以看到,backend ms1、ms2、default_servers下属的6个后端服务的Status都是20h28m UP,代表健康状态已持续了20小时28分钟,而LastChk显示L7OK/200 in 1ms则代表在1ms前进行了L7的健康检查(即HTTP请求方式的健康检查),返回码为200。
此时我们将ms1.srv1中的healthCheck.html改名,mv healthCheck.html healthCheck.html.bak,然后再去看监控页面。ms1.srv1的状态变成了2s DOWN,LastChk则是L7STS/404 in 2ms,代表上次健康检查返回了404,再恢复healthCheck.html,很快就能看到ms1.srv1重新恢复到UP状态。
负载均衡和会话保持策略
在分别访问过ms1/demo.html,ms2/demo.html,m3/demo.html后,查看一下浏览器的Cookie。可以看到HAProxy已经回写了三个用于会话保持的cookie,此时反复刷新这三个页面,会发现总是被定向到*.srv1上接下来我们删除HA_STICKY_ms1这条cookie,然后再访问ms1/demo.html,会看到同时也被新写入了一条Cookie。如果发现仍然被定位到ms1.srv1,同时也没有写入新的HA_STICKY_ms1 Cookie,那么可能是浏览器缓存了ms1/demo.html页面,请求并没有到达HAProxy。F5刷新一下应该就可以了。
HAProxy搭建L4负载均衡器
HAProxy作为L4负载均衡器工作时,不会去解析任何与HTTP协议相关的内容,只在传输层对数据包进行处理。也就是说,以L4模式运行的HAProxy,无法实现根据URL向不同后端转发、通过cookie实现会话保持等功能。同时,在L4模式下工作的HAProxy也无法提供监控页面。但作为L4负载均衡器的HAProxy能够提供更高的性能,适合于基于套接字的服务(如数据库、消息队列、RPC、邮件服务、Redis等),或不需要逻辑规则判断,并已实现了会话共享的HTTP服务。
总体方案
本例中,我们使用HAProxy以L4方式来代理两个HTTP服务,不提供会话保持。
global daemon maxconn 30000 #ulimit -n至少为60018 user ha pidfile /home/ha/haproxy/conf/haproxy.pid log 127.0.0.1 local0 info log 127.0.0.1 local1 warning defaults mode tcp log global option tcplog #开启tcplog timeout connect 5000ms timeout client 10000ms timeout server 10000ms #TCP模式下,应将timeout client和timeout server设置为一样的值,以防止出现问题 option httpchk GET /healthCheck.html #定义默认的健康检查策略 frontend http-in bind *:9002 maxconn 30000 #定义此端口上的maxconn default_backend default_servers #请求定向至后端服务群default_servers backend default_servers #定义后端服务群default_servers balance roundrobin server def.srv1 192.168.8.111:8082 maxconn 300 check server def.srv2 192.168.8.112:8082 maxconn 300 check
L4模式下的会话保持
虽然TCP模式下的HAProxy无法通过HTTP Cookie实现会话保持,但可以很方便的实现基于客户端IP的会话保持。只需将balance roundrobin改为balance source.
此外,HAProxy提供了强大的stick-table功能,HAProxy可以从传输层的数据包中采样出大量的属性,并将这些属性作为会话保持的策略写入stick-table中。
HAProxy关键配置详解
HAProxy的配置文件共有5个域
- global:用于配置全局参数
- default:用于配置所有frontend和backend的默认属性
- frontend:用于配置前端服务(即HAProxy自身提供的服务)实例
- backend:用于配置后端服务(即HAProxy后面接的服务)实例组
- listen:frontend+backend的组合配置,可以理解成更简洁的配置方法
global域的关键配置
- daemon:指定HAProxy以后台模式运行,通常情况下都应该使用这一配置
- user [username]:指定HAProxy进程所属的用户
- group [groupname]:指定HAProxy进程所属的用户组
- log [address] [device] [maxlevel] [minlevel]:日志输出配置,如log 127.0.0.1 local0 info warning,即向本机rsyslog或syslog的local0输出info到warning级别的日志。其中[minlevel]可以省略。HAProxy的日志共有8个级别,从高到低为emerg/alert/crit/err/warning/notice/info/debug
- pidfile:指定记录HAProxy进程号的文件绝对路径。主要用于HAProxy进程的停止和重启动作。
- maxconn:HAProxy进程同时处理的连接数,当连接数达到这一数值时,HAProxy将停止接收连接请求
frontend域的关键配置
- acl [name] [criterion] [flags] [operator] [value]:定义一条ACL,ACL是根据数据包的指定属性以指定表达式计算出的true/false值。如”acl url_ms1 path_beg -i /ms1/”定义了名为url_ms1的ACL,该ACL在请求uri以/ms1/开头(忽略大小写)时为true
- bind [ip]:[port]:frontend服务监听的端口
- default_backend [name]:frontend对应的默认backend
- disabled:禁用此frontend
- http-request [operation] [condition]:对所有到达此frontend的HTTP请求应用的策略,例如可以拒绝、要求认证、添加header、替换header、定义ACL等等。
- http-response [operation] [condition]:对所有从此frontend返回的HTTP响应应用的策略,大体同上
- log:同global域的log配置,仅应用于此frontend。如果要沿用global域的log配置,则此处配置为log global
- maxconn:同global域的maxconn,仅应用于此frontend
- mode:此frontend的工作模式,主要有http和tcp两种,对应L7和L4两种负载均衡模式
- option forwardfor:在请求中添加X-Forwarded-For Header,记录客户端ip
- option http-keep-alive:以KeepAlive模式提供服务
- option httpclose:与http-keep-alive对应,关闭KeepAlive模式,如果HAProxy主要提供的是接口类型的服务,可以考虑采用httpclose模式,以节省连接数资源。但如果这样做了,接口的调用端将不能使用HTTP连接池
- option httplog:开启httplog,HAProxy将会以类似Apache HTTP或Nginx的格式来记录请求日志
- option tcplog:开启tcplog,HAProxy将会在日志中记录数据包在传输层的更多属性
- stats uri [uri]:在此frontend上开启监控页面,通过[uri]访问
- stats refresh [time]:监控数据刷新周期
- stats auth [user]:[password]:监控页面的认证用户名密码
- timeout client [time]:指连接创建后,客户端持续不发送数据的超时时间
- timeout http-request [time]:指连接创建后,客户端没能发送完整HTTP请求的超时时间,主要用于防止DoS类攻击,即创建连接后,以非常缓慢的速度发送请求包,导致HAProxy连接被长时间占用
- use_backend [backend] if|unless [acl]:与ACL搭配使用,在满足/不满足ACL时转发至指定的backend
backend域的关键配置
- acl:同frontend域
- balance [algorithm]:在此backend下所有server间的负载均衡算法,常用的有roundrobin和source,完整的算法说明见官方文档html#4.2-balance
- cookie:在backend server间启用基于cookie的会话保持策略,最常用的是insert方式,如cookie HA_STICKY_ms1 insert indirect nocache,指HAProxy将在响应中插入名为HA_STICKY_ms1的cookie,其值为对应的server定义中指定的值,并根据请求中此cookie的值决定转发至哪个server。indirect代表如果请求中已经带有合法的HA_STICK_ms1 cookie,则HAProxy不会在响应中再次插入此cookie,nocache则代表禁止链路上的所有网关和缓存服务器缓存带有Set-Cookie头的响应。
- default-server:用于指定此backend下所有server的默认设置。具体见下面的server配置。
- disabled:禁用此backend
- http-request/http-response:同frontend域
- log:同frontend域
- mode:同frontend域
- option forwardfor:同frontend域
- option http-keep-alive:同frontend域
- option httpclose:同frontend域
- option httpchk [METHOD] [URL] [VERSION]:定义以http方式进行的健康检查策略。如option httpchk GET /healthCheck.html HTTP/1.1
- option httplog:同frontend域
- option tcplog:同frontend域
- server [name] [ip]:[port] [params]:定义backend中的一个后端server,[params]用于指定这个server的参数,常用的包括有:
- check:指定此参数时,HAProxy将会对此server执行健康检查,检查方法在option httpchk中配置。同时还可以在check后指定inter, rise, fall三个参数,分别代表健康检查的周期、连续几次成功认为server UP,连续几次失败认为server DOWN,默认值是inter 2000ms rise 2 fall 3
- cookie [value]:用于配合基于cookie的会话保持,如cookie ms1.srv1代表交由此server处理的请求会在响应中写入值为srv1的cookie(具体的cookie名则在backend域中的cookie设置中指定)
maxconn:指 HAProxy 最多同时向此 server 发起的连接数,当连接数到达 maxconn 后,向此 server 发起的新连接会进入等待队列。默认为 0,即无限
default 域
上文所属的 frontend 和 backend 域关键配置中,除 acl、bind、http-request、http-response、use_backend 外,其余的均可以配置在 default 域中。default 域中配置了的项目,如果在 frontend 或 backend 域中没有配置,将会使用 default 域中的配置。
listen 域
listen 域是 frontend 域和 backend 域的组合,frontend 域和 backend 域中所有的配置都可以配置在 listen 域下。
使用 Keepalived 实现 HAProxy 高可用
尽管 HAProxy 非常稳定,但仍然无法规避操作系统故障、主机硬件故障、网络故障甚至断电带来的风险。所以必须对 HAProxy 实施高可用方案。下文将介绍利用 Keepalived 实现的 HAProxy 热备方案。即两台主机上的两个 HAProxy 实例同时在线,其中权重较高的实例为 MASTER,MASTER 出现问题时,另一台实例自动接管所有流量。
原理
在两台 HAProxy 的主机上分别运行着一个 Keepalived 实例,这两个 Keepalived 争抢同一个虚 IP 地址,两个 HAProxy 也尝试去绑定这同一个虚 IP 地址上的端口。显然,同时只能有一个 Keepalived 抢到这个虚 IP,抢到了这个虚 IP 的 Keepalived 主机上的 HAProxy 便是当前的 MASTER。Keepalived 内部维护一个权重值,权重值最高的 Keepalived 实例能够抢到虚 IP。同时 Keepalived 会定期 check 本主机上的 HAProxy 状态,状态 OK 时权重值增加。
搭建 HAProxy 主备集群
在两台物理机上安装并配置 HAProxy,本例中,将在 192.168.8.110 和 192.168.8.111 两台主机上上安装两套完全一样的 HAProxy,具体步骤省略,请参考“使用 HAProxy 搭建 L7 负载均衡器”一节。
安装 Keepalived
下载,解压,编译,安装:
wget http://www.keepalived.org/software/keepalived-1.2.19.tar.gz tar -xzf keepalived-1.2.19.tar.gz ./configure --prefix=/usr/local/keepalived make make install
注册为系统服务:
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/ cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/ chmod +x /etc/init.d/keepalived
注意:Keepalived 需要使用 root 用户进行安装和配置配置 Keepalived
创建并编辑配置文件
mkdir -p /etc/keepalived/ cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/ vi /etc/keepalived/keepalived.conf
配置文件内容:
global_defs { router_id LVS_DEVEL #虚拟路由名称 } #HAProxy 健康检查配置 vrrp_script chk_haproxy { script "killall -0 haproxy" #使用 killall -0 检查 haproxy 实例是否存在,性能高于 ps 命令 interval 2 #脚本运行周期 weight 2 #每次检查的加权权重值 } #虚拟路由配置 vrrp_instance VI_1 { state MASTER #本机实例状态,MASTER/BACKUP,备机配置文件中请写 BACKUP interface enp0s25 #本机网卡名称,使用 ifconfig 命令查看 virtual_router_id 51 #虚拟路由编号,主备机保持一致 priority 101 #本机初始权重,备机请填写小于主机的值(例如 100) advert_int 1 #争抢虚地址的周期,秒 virtual_ipaddress { 192.168.8.201 #虚地址 IP,主备机保持一致 } track_script { chk_haproxy #对应的健康检查配置 } }
如果主机没有 killall 命令,则需要安装 psmisc 包:
yum install psmisc
分别启动两个 Keepalived
service keepalived start
验证
启动后,先分别在两台主机查看虚 IP 192.168.8.201 由谁持有,执行命令:ip addr sh enp0s25 (将 enp0s25 替换成主机的网卡名)
如果你先启动备机的 Keepalived,那么很有可能虚 IP 会被备机抢到,因为备机的权重配置只比主机低 1,只要执行一次健康检查就能把权重提高到 102,高于主机的 101。此时访问 http://192.168.8.201:9001/ms1/demo.html ,可以看到我们先前部署的网页。此时,检查 /var/log/haproxy.log,能看到此请求落在了抢到了虚 IP 的主机上。接下来,我们停掉当前 MASTER 主机的 HAProxy 实例(或者 Keepalive 实例,效果一样)
service haproxy stop
再次访问 http://192.168.8.201:9001/ms1/demo.html ,并查看备机的 /var/log/haproxy.log,会看到此请求落在了备机上,主备自动切换成功。也可以再次执行 ip addr sh enp0s25 命令,会看到虚 IP 被备机抢去了。在 /var/log/message 中,也能够看到 keepalived 输出的切换日志。
参考链接: