Reverse Proxy: http, pop3/imap4

web server

Nginx:

  反省代理 URI, 代理后端某服务器;

  proxy_pass, rewrite

  upstream: 将一组后端计算机定义为集群
    rr

    ip_hash

    least_conn: 最少连接

      lc,wlc

  proxy:

 

/bbs

/php

/images

nginx --> tengine

worker_process:

  CPU: 1

  IO: 1.5

  亲缘性:

65535

web monitor

url: 提高缓存命中率

syslog:

  facility.priority

http://www.magedu.com/admin.php?a=3&b=4

listen web

  bind *:80

 

一、HAProxy简介


HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在时下的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。

HAProxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。

————百度百科


HAProxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤其适用于高负载且需要持久连接或7层处理机制的web站点。

 

HAProxy目前主要有两个版本:

1.4——提供较好的弹性:衍生于1.2版本,并提供了额外的新特性,其中大多数是期待已久的。

  客户端侧的长连接(client-side keep-alive)

  TCP加速(TCP speedups)

  响应池(response buffering)

  RDP协议

  基于源的粘性(source-based stickiness)

  更好的统计数据接口(a much better stats interfaces)

  更详细的健康状态检测机制(more verbose health checks)

  基于流量的健康评估机制(traffic-based health)

  支持HTTP认证

  服务器管理命令行接口(server management from the CLI)

  基于ACL的持久性(ACL-based persistence)

日志分析器

1.3——内容交换和超强负载:衍生于1.2版本,并提供了额外的新特性。

  内容交换(content switching):基于任何请求标准挑选服务器池;

  ACL:编写内容交换规则;

  负载均衡算法(load-balancing algorithms):更多的算法支持;

  内容探测(content inspection):阻止非授权协议;

  透明代理(transparent proxy):在Linux系统上允许使用客户端IP直接连入服务器;

  内核TCP拼接(kernel TCP splicing):无copy方式在客户端和服务端之间转发数据以实现数G级别的数据速率;

  分层设计(layered design):分别实现套接字、TCP、HTTP处理以提供更好的健壮性、更快的处理机制及便捷的演进能力;

  快速、公平调度器(fast and fair scheduler):为某些任务指定优先级可实现理好的QoS;

  会话速率限制(session rate limiting):适用于托管环境;

 

支持的平台及OS:

  x86、x86_64、Alpha、SPARC、MIPS及PARISC平台上的Linux 2.4;

  x86、x86_64、ARM (ixp425)及PPC64平台上的Linux2.6;

  UltraSPARC 2和3上的Sloaris 8/9;

  Opteron和UltraSPARC平台上的Solaris 10;

  x86平台上的FreeBSD 4.1-8;

  i386, amd64, macppc, alpha, sparc64和VAX平台上的OpenBSD 3.1-current;

若要获得最高性能,需要在Linux 2.6或打了epoll补丁的Linux 2.4上运行haproxy 1.2.5以上的版本。haproxy 1.1l默认使用的polling系统为select(),其处理的文件数达数千个时性能便会急剧下降。1.2和1.3版本默认的为poll(),在有些操作系统上可会也会有性能方面的问题,但在Solaris上表现相当不错。HAProxy 1.3在Linux 2.6及打了epoll补丁的Linux 2.4上默认使用epoll,在FreeBSD上使用kqueue,这两种机制在任何负载上都能提供恒定的性能表现。


在较新版本的Linux 2.6(>=2.6.27.19)上,HAProxy还能够使用splice()系统调用在接口间无复制地转发任何数据,这甚至可以达到10Gbps的性能。

基于以上事实,在x86或x86_64平台上,要获取最好性能的负载均衡器,建议按顺序考虑以下方案。

  Linux 2.6.32及之后版本上运行HAProxy 1.4;

  打了epoll补丁的Linux 2.4上运行HAProxy 1.4;

  FreeBSD上运行HAProxy 1.4;

  Solaris 10上运行HAProxy 1.4;

 

性能

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

2.1 配置文件格式

HAProxy的配置处理3类来主要参数来源:

  ——最优先处理的命令行参数,

  ——“global”配置段,用于设定全局配置参数;

  ——proxy相关配置段,如“defaults”、“listen”、“frontend”和“backend”;

2.2 时间格式

一些包含了值的参数表示时间,如超时时长。这些值一般以毫秒为单位,但也可以使用其它的时间单位后缀。

  us: 微秒(microseconds),即1/1000000秒;

  ms: 毫秒(milliseconds),即1/1000秒;

  s: 秒(seconds);

  m: 分钟(minutes);

  h:小时(hours);

  d: 天(days);

 

2.3 例子

下面的例子配置了一个监听在所有接口的80端口上HTTP proxy服务,它转发所有的请求至后端监听在127.0.0.1:8000上的"server"。

global

    daemon(以进程方式运行)

    maxconn 25600(最大连接数)

  defaults
    mode http(代理http)

    timeout connect 5000ms(建立连接超时时间)

    timeout client 50000ms(客户端断开连接超时时间)

    timeout server 50000ms(服务器端断开连接超时时间)

  frontend http-in(前端,http-in前端名称)

    bind *:80(监听端口)

    default_backend servers(默认后端服务)

  backend servers(后端)

    server server1 127.0.0.1:8080 maxconn 32(后端服务器,最大并发连接)

 

2.4 全局配置

“global”配置中的参数为进程级别的参数,且通常与其运行的OS相关。

* 进程管理及安全相关的参数

  - chroot <jail dir>:修改haproxy的工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限;

  - daemon:让haproxy以守护进程的方式工作于后台,其等同于“-D”选项的功能,当然,也可以在命令行中以“-db”选项将其禁用;

  - gid <number>:以指定的GID运行haproxy,建议使用专用于运行haproxy的GID,以免因权限问题带来风险;

  - group <group name>:同gid,不过指定的组名;

  - log <address> <facility> [max level [min level]]:定义全局的syslog服务器,最多可以定义两个;

  - log-send-hostname [<string>]:在syslog信息的首部添加当前主机名,可以为“string”指定的名称,也可以缺省使用当前主机名;

  - nbproc <number>:指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;

  - pidfile:

  - uid:以指定的UID身份运行haproxy进程;

  - ulimit-n:设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计算,因此不推荐修改此选项;

  - user:同uid,但使用的是用户名;

  - stats:

  - node:定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;

  - description:当前实例的描述信息;

 

* 性能调整相关的参数

  - maxconn <number>:设定每个haproxy进程所接受的最大并发连接数,其等同于命令行选项“-n”;“ulimit -n”自动计算的结果正是参照此参数设定的;

  - maxpipes <number>:haproxy使用pipe完成基于内核的tcp报文重组,此选项则用于设定每进程所允许使用的最大pipe个数;每个pipe会打开两个文件描述符,因此,“ulimit -n”自动计算时会根据需要调大此值;默认为maxconn/4,其通常会显得过大;

  - noepoll:在Linux系统上禁用epoll机制;

  - nokqueue:在BSE系统上禁用kqueue机制;

  - nopoll:禁用poll机制;

  - nosepoll:在Linux禁用启发式epoll机制;

  - nosplice:禁止在Linux套接字上使用内核tcp重组,这会导致更多的recv/send系统调用;不过,在Linux 2.6.25-28系列的内核上,tcp重组功能有bug存在;

  - spread-checks <0..50, in percent>:在haproxy后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能会带来意外问题;此选项用于将其检查的时间间隔长度上增加或减小一定的随机时长;

  - tune.bufsize <number>:设定buffer的大小,同样的内存条件小,较小的值可以让haproxy有能力接受更多的并发连接,较大的值可以让某些应用程序使用较大的cookie信息;默认为16384,其可以在编译时修改,不过强烈建议使用默认值;

  - tune.chksize <number>:设定检查缓冲区的大小,单位为字节;更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更多的系统资源;不建议修改;

  - tune.maxaccept <number>:设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐率,默认在单进程模式下为100,多进程模式下为8,设定为-1可以禁止此限制;一般不建议修改;

  - tune.maxpollevents <number>:设定一次系统调用可以处理的事件最大数,默认值取决于OS;其值小于200时可节约带宽,但会略微增大网络延迟,而大于200时会降低延迟,但会稍稍增加网络带宽的占用量;

  - tune.maxrewrite <number>:设定为首部重写或追加而预留的缓冲空间,建议使用1024左右的大小;在需要使用更大的空间时,haproxy会自动增加其值;

  - tune.rcvbuf.client <number>:

  - tune.rcvbuf.server <number>:设定内核套接字中服务端或客户端接收缓冲的大小,单位为字节;强烈推荐使用默认值;

  - tune.sndbuf.client:

  - tune.sndbuf.server:

* Debug相关的参数

  - debug

  - quiet

 

2.5 代理

代理相关的配置可以如下配置段中。

  - defaults <name>

  - frontend <name>

  - backend <name>

  - listen <name>

  “defaults”段用于为所有其它配置段提供默认参数,这配置默认配置参数可由下一个“defaults”所重新设定。

  “frontend”段用于定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接。

  “backend”段用于定义一系列“后端”服务器,代理将会将对应客户端的请求转发至这些服务器。

  “listen”段通过关联“前端”和“后端”定义了一个完整的代理,通常只对TCP流量有用。

  所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分字母大小写。

 

三、配置文件中的关键字参考

3.1 balance

balance <algorithm> [ <arguments> ]

balance url_param <param> [check_post [<max_wait>]]

定义负载均衡算法,可用于“defaults”、“listen”和“backend”。<algorithm>用于在负载均衡场景中挑选一个server,其仅应用于持久信息不可用的条件下或需要将一个连接重新派发至另一个服务器时。支持的算法有:

  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.magedu.com来说,仅计算magedu字符串的hash值)以降低hash算法的运算量;此算法默认为静态的,不过其也可以使用hash-type修改此特性;

  rdp-cookie

  rdp-cookie(name):

 

3.2 bind

bind [<address>]:<port_range> [, ...]

bind [<address>]:<port_range> [, ...] interface <interface>

此指令仅能用于frontend和listen区段,用于定义一个或几个监听的套接字。

<address>:可选选项,其可以为主机名、IPv4地址、IPv6地址或*;省略此选项、将其指定为*或0.0.0.0时,将监听当前系统的所有IPv4地址;

<port_range>:可以是一个特定的TCP端口,也可是一个端口范围(如5005-5010),代理服务器将通过指定的端口来接收客户端请求;需要注意的是,每组监听的套接字<address:port>在同一个实例上只能使用一次,而且小于1024的端口需要有特定权限的用户才能使用,这可能需要通过uid参数来定义;

<interface>:指定物理接口的名称,仅能在Linux系统上使用;其不能使用接口别名,而仅能使用物理接口名称,而且只有管理有权限指定绑定的物理接口;

 

3.3 mode

mode { tcp|http|health }

设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般说来都是HTTP模式),否则将无法启动实例。

tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;此为默认模式,通常用于SSL、SSH、SMTP等应用;

http:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;

health:实例工作于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前业讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能;


3.4 hash-type

hash-type <method>

定义用于将hash码映射至后端服务器的方法;其不能用于frontend区段;可用方法有map-based和consistent,在大多数场景下推荐使用默认的map-based方法。

 

map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。


3.5 log

log global

log <address> <facility> [<level> [<minlevel>]]

为每个实例启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个log参数,不过,如果使用了“log global”且"global"段已经定了两个log参数时,多余了log参数将被忽略。

global:当前实例的日志系统参数同"global"段中的定义时,将使用此格式;每个实例仅能定义一次“log global”语句,且其没有任何额外参数;
<address>:定义日志发往的位置,其格式之一可以为<IPv4_address:PORT>,其中的port为UDP协议端口,默认为514;格式之二为Unix套接字文件路径,但需要留心chroot应用及用户的读写权限;
<facility>:可以为syslog系统的标准facility之一;

<level>:定义日志级别,即输出信息过滤器,默认为所有信息;指定级别时,所有等于或高于此级别的日志信息将会被发送;

 

3.6 maxconn

maxconn <conns>

设定一个前端的最大并发连接数,因此,其不能用于backend区段。对于大型站点来说,可以尽可能提高此值以便让haproxy管理连接队列,从而避免无法应答用户请求。当然,此最大值不能超出“global”段中的定义。此外,需要留心的是,haproxy会为每个连接维持两个缓冲,每个缓冲的大小为8KB,再加上其它的数据,每个连接将大约占用17KB的RAM空间。这意味着经过适当优化后,有着1GB的可用RAM空间时将能维护40000-50000并发连接。

如果为<conns>指定了一个过大值,极端场景下,其最终占据的空间可能会超出当前主机的可用内存,这可能会带来意想不到的结果;因此,将其设定了一个可接受值方为明智决定。其默认为2000。


3.7 default_backend

default_backend <backend>

在没有匹配的"use_backend"规则时为实例指定使用的默认后端,因此,其不可应用于backend区段。在"frontend"和"backend"之间进行内容交换时,通常使用"use-backend"定义其匹配规则;而没有被规则匹配到的请求将由此参数指定的后端接收。

<backend>:指定使用的后端的名称;

 

使用案例:

use_backend dynamic if url_dyn

use_backend static if url_css url_img extension_img

default_backend dynamic

3.8 server

server <name> <address>[:port] [param*]

为后端声明一个server,因此,不能用于defaults和frontend区段。

<name>:为此服务器指定的内部名称,其将出现在日志及警告信息中;如果设定了"http-send-server-name",它还将被添加至发往此服务器的请求首部中;

<address>:此服务器的的IPv4地址,也支持使用可解析的主机名,只不过在启动时需要解析主机名至相应的IPv4地址;

[:port]:指定将连接请求所发往的此服务器时的目标端口,其为可选项;未设定时,将使用客户端请求时的同一相端口;

[param*]:为此服务器设定的一系参数;其可用的参数非常多,具体请参考官方文档中的说明,下面仅说明几个常用的参数;

 

服务器或默认服务器参数:

backup:设定为备用服务器,仅在负载均衡场景中的其它server均不可用于启用此server;

check:启动对此server执行健康状态检查,其可以借助于额外的其它参数完成更精细的设定,如:

  inter <delay>:设定健康状态检查的时间间隔,单位为毫秒,默认为2000;也可以使用fastinter和downinter来根据服务器端状态优化此时间延迟;

  rise <count>:设定健康状态检查中,某离线的server从离线状态转换至正常状态需要成功检查的次数;

  fall <count>:确认server从正常状态转换为不可用状态需要检查的次数;

cookie <value>:为指定server设定cookie值,此处指定的值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,其目的在于实现持久连接的功能;

maxconn <maxconn>:指定此服务器接受的最大并发连接数;如果发往此服务器的连接数目高于此处指定的值,其将被放置于请求队列,以等待其它连接被释放;

maxqueue <maxqueue>:设定请求队列的最大长度;

observe <mode>:通过观察服务器的通信状况来判定其健康状态,默认为禁用,其支持的类型有“layer4”和“layer7”,“layer7”仅能用于http代理场景;

redir <prefix>:启用重定向功能,将发往此服务器的GET和HEAD请求均以302状态码响应;需要注意的是,在prefix后面不能使用/,且不能使用相对地址,以免造成循环;例如:

  server srv1 172.16.100.6:80 redir http://imageserver.magedu.com check

weight <weight>:权重,默认为1,最大值为256,0表示不参与负载均衡;

检查方法:

option httpchk

option httpchk <uri>

option httpchk <method> <uri>

option httpchk <method> <uri> <version>:不能用于frontend段,例如:

backend https_relay

  mode tcp

  option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www.magedu.com

  server apache1 192.168.1.1:443 check port 80

 

使用案例:

server first 172.16.100.7:1080 cookie first check inter 1000

server second 172.16.100.8:1080 cookie second check inter 1000

[root@Smoke ~]# ulimit -n(显示单进程可以打开的最大文件数目)
1024
提示:在linux上默认限定最一个独立进程最多能开打1024个文件描述符;

3.9 capture request header

capture request header <name> len <length>

捕获并记录指定的请求首部最近一次出现时的第一个值,仅能用于“frontend”和“listen”区段。捕获的首部值使用花括号{}括起来后添加进日志中。如果需要捕获多个首部值,它们将以指定的次序出现在日志文件中,并以竖线“|”作为分隔符。不存在的首部记录为空字符串,最常需要捕获的首部包括在虚拟主机环境中使用的“Host”、上传请求首部中的“Content-length”、快速区别真实用户和网络机器人的“User-agent”,以及代理环境中记录真实请求来源的“X-Forward-For”。

<name>:要捕获的首部的名称,此名称不区分字符大小写,但建议与它们出现在首部中的格式相同,比如大写首字母。需要注意的是,记录在日志中的是首部对应的值,而非首部名称。

<length>:指定记录首部值时所记录的精确长度,超出的部分将会被忽略。

可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录64个字符。为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义。

3.10 capture response header

capture response header <name> len <length>

捕获并记录响应首部,其格式和要点同请求首部。

3.11 stats enable

启用基于程序编译时默认设置的统计报告,不能用于“frontend”区段。只要没有另外的其它设定,它们就会使用如下的配置:

  - stats uri : /haproxy?stats

  - stats realm : "HAProxy Statistics"

  - stats auth : no authentication

  - stats scope : no restriction

尽管“stats enable”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。下面是一个配置案例。

  backend public_www

    server websrv1 172.16.100.11:80

    stats enable

    stats hide-version

    stats scope .

    stats uri /haproxyadmin?stats

    stats realm Haproxy\ Statistics

    stats auth statsadmin:password

    stats auth statsmaster:password

 

3.12 stats hide-version

stats hide-version

启用统计报告并隐藏HAProxy版本报告,不能用于“frontend”区段。默认情况下,统计页面会显示一些有用信息,包括HAProxy的版本号,然而,向所有人公开HAProxy的精确版本号是非常有风险的,因为它能帮助恶意用户快速定位版本的缺陷和漏洞。尽管“stats hide-version”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。具体请参照“stats enable”一节的说明。

3.13 stats realm

stats realm <realm>

启用统计报告并高精认证领域,不能用于“frontend”区段。haproxy在读取realm时会将其视作一个单词,因此,中间的任何空白字符都必须使用反斜线进行转义。此参数仅在与“stats auth”配置使用时有意义。

<realm>:实现HTTP基本认证时显示在浏览器中的领域名称,用于提示用户输入一个用户名和密码。

尽管“stats realm”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。具体请参照“stats enable”一节的说明。

 

3.14 stats scope

stats scope { <name> | "." }

启用统计报告并限定报告的区段,不能用于“frontend”区段。当指定此语句时,统计报告将仅显示其列举出区段的报告信息,所有其它区段的信息将被隐藏。如果需要显示多个区段的统计报告,此语句可以定义多次。需要注意的是,区段名称检测仅仅是以字符串比较的方式进行,它不会真检测指定的区段是否真正存在。

<name>:可以是一个“listen”、“frontend”或“backend”区段的名称,而“.”则表示stats scope语句所定义的当前区段。

尽管“stats scope”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。下面是一个配置案例。

backend private_monitoring

  stats enable

  stats uri /haproxyadmin?stats

  stats refresh 10s

3.15 stats auth

stats auth <user>:<passwd>

启用带认证的统计报告功能并授权一个用户帐号,其不能用于“frontend”区段。

<user>:授权进行访问的用户名;

<passwd>:此用户的访问密码,明文格式;

此语句将基于默认设定启用统计报告功能,并仅允许其定义的用户访问,其也可以定义多次以授权多个用户帐号。可以结合“stats realm”参数在提示用户认证时给出一个领域说明信息。在使用非法用户访问统计功能时,其将会响应一个“401 Forbidden”页面。其认证方式为HTTP Basic认证,密码传输会以明文方式进行,因此,配置文件中也使用明文方式存储以说明其非保密信息故此不能相同于其它关键性帐号的密码。

尽管“stats auth”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。

3.16 stats admin

stats admin { if | unless } <cond>

在指定的条件满足时启用统计报告页面的管理级别功能,它允许通过web接口启用或禁用服务器,不过,基于安全的角度考虑,统计报告页面应该尽可能为只读的。此外,如果启用了HAProxy的多进程模式,启用此管理级别将有可能导致异常行为。

目前来说,POST请求方法被限制于仅能使用缓冲区减去保留部分之外的空间,因此,服务器列表不能过长,否则,此请求将无法正常工作。因此,建议一次仅调整少数几个服务器。下面是两个案例,第一个限制了仅能在本机打开报告页面时启用管理级别功能,第二个定义了仅允许通过认证的用户使用管理级别功能。

 

backend stats_localhost

  stats enable

  stats admin if LOCALHOST

backend stats_auth

  stats enable

  stats auth haproxyadmin:password

  stats admin if TRUE

 

3.17 option httplog

option httplog [ clf ]

启用记录HTTP请求、会话状态和计时器的功能。

clf:使用CLF格式来代替HAProxy默认的HTTP格式,通常在使用仅支持CLF格式的特定日志分析器时才需要使用此格式。

默认情况下,日志输入格式非常简陋,因为其仅包括源地址、目标地址和实例名称,而“option httplog”参数将会使得日志格式变得丰富许多,其通常包括但不限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、“frontend”、“backend”及服务器名称,当然也包括源地址和端口号等。

3.18 option logasap

  no option logasap

option logasap

no option logasap

启用或禁用提前将HTTP请求记入日志,不能用于“backend”区段。

默认情况下,HTTP请求是在请求结束时进行记录以便能将其整体传输时长和字节数记入日志,由此,传较大的对象时,其记入日志的时长可能会略有延迟。“option logasap”参数能够在服务器发送complete首部时即时记录日志,只不过,此时将不记录整体传输时长和字节数。此情形下,捕获“Content-Length”响应首部来记录传输的字节数是一个较好选择。下面是一个例子。

  listen http_proxy 0.0.0.0:80

    mode http

    option httplog

    option logasap

    log 172.16.100.9 local2

 

3.19 option forwardfor

option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

允许在发往服务器的请求首部中插入“X-Forwarded-For”首部。

<network>:可选参数,当指定时,源地址为匹配至此网络中的请求都禁用此功能。

<name>:可选参数,可使用一个自定义的首部,如“X-Client”来替代“X-Forwarded-For”。有些独特的web服务器的确需要用于一个独特的首部。

if-none:仅在此首部不存在时才将其添加至请求报文问道中。

HAProxy工作于反向代理模式,其发往服务器的请求中的客户端IP均为HAProxy主机的地址而非真正客户端的地址,这会使得服务器端的日志信息记录不了真正的请求来源,“X-Forwarded-For”首部则可用于解决此问题。HAProxy可以向每个发往服务器的请求上添加此首部,并以客户端IP为其value。

需要注意的是,HAProxy工作于隧道模式,其仅检查每一个连接的第一个请求,因此,仅第一个请求报文被附加此首部。如果想为每一个请求都附加此首部,请确保同时使用了“option httpclose”、“option forceclose”和“option http-server-close”几个option。

下面是一个例子。

frontend www

  mode http

  option forwardfor except 127.0.0.1

 

3.20 errorfile

errorfile <code> <file>

在用户请求不存在的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。

<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;

<file>:指定用于响应的页面文件;

例如:

errorfile 400 /etc/haproxy/errorpages/400badreq.http

errorfile 403 /etc/haproxy/errorpages/403forbid.http

errorfile 503 /etc/haproxy/errorpages/503sorry.http

 

3.21 errorloc 和 errorloc302

errorloc <code> <url>

errorloc302 <code> <url>


请求错误时,返回一个HTTP重定向至某URL的信息;可用于所有配置段中。

<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;

<url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;

需要留意的是,这两个关键字都会返回302状态吗,这将使得客户端使用同样的HTTP方法获取指定的URL,对于非GET法的场景(如POST)来说会产生问题,因为返回客户的URL是不允许使用GET以外的其它方法的。如果的确有这种问题,可以使用errorloc303来返回303状态码给客户端。

3.22 errorloc303

errorloc303 <code> <url>

请求错误时,返回一个HTTP重定向至某URL的信息给客户端;可用于所有配置段中。

<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有400、403、408、500、502、503和504;

<url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;

例如:

backend webserver

server 172.16.100.6 172.16.100.6:80 check maxconn 3000 cookie srv01

server 172.16.100.7 172.16.100.7:80 check maxconn 3000 cookie srv02

errorloc 403 /etc/haproxy/errorpages/sorry.htm

errorloc 503 /etc/haproxy/errorpages/sorry.htm

 

一个配置示例:

#---------------------------------------------------------------------

# 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          http

  log              global

  option            httplog

  option         dontlognull

  option http-server-close

  option forwardfor       except 127.0.0.0/8

  option         redispatch

  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          30000

 

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 http-in

  bind *:80

  mode http

  log global

  option httpclose

  option logasap

  option dontlognull

  capture request header Host len 20

  capture request header Referer len 60

  default_backend servers

 

frontend healthcheck

  bind :1099

  mode http

  option httpclose

  option forwardfor

  default_backend servers

backend servers

  balance roundrobin

    server websrv1 192.168.10.11:80 check maxconn 2000

    server websrv2 192.168.10.12:80 check maxconn 2000

 

负载均衡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

  balance leastconn

  server dbsrv1 192.168.10.11:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300

  server dbsrv2 192.168.10.12:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300

 

rehel 6.4 RPM

 

环境:启用三台linux虚拟机,一台作为haproxy服务器,两台作为后端http服务器;

后端http-HA1服务器:

[root@node1 ~]# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0C:29:CC:FA:AE  
          inet addr:192.168.10.11  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fecc:faae/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:246742 errors:0 dropped:0 overruns:0 frame:0
          TX packets:323117 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:200611400 (191.3 MiB)  TX bytes:386386932 (368.4 MiB)
          Interrupt:67 Base address:0x2000
[root@node1 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.10.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         192.168.10.7    0.0.0.0         UG    0      0        0 eth0

后端http-HA2服务器:

[root@node2 ~]# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0C:29:B8:44:39  
          inet addr:192.168.10.12  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:feb8:4439/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:286 errors:0 dropped:0 overruns:0 frame:0
          TX packets:68 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:26280 (25.6 KiB)  TX bytes:9623 (9.3 KiB)
          Interrupt:67 Base address:0x2000 
[root@node2 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.10.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         192.168.10.7    0.0.0.0         UG    0      0        0 eth0

haproxy:

[root@slave ~]# ifconfig 
eth0      Link encap:Ethernet  HWaddr 00:0C:29:80:E1:12  
          inet addr:172.16.100.107  Bcast:172.16.100.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe80:e112/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:313 errors:0 dropped:0 overruns:0 frame:0
          TX packets:161 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:30803 (30.0 KiB)  TX bytes:18167 (17.7 KiB)
          Interrupt:19 Base address:0x2000 

eth1      Link encap:Ethernet  HWaddr 00:0C:29:80:E1:1C  
          inet addr:192.168.10.7  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe80:e11c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:69 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:6264 (6.1 KiB)  TX bytes:790 (790.0 b)
          Interrupt:16 Base address:0x2080 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:9 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:792 (792.0 b)  TX bytes:792 (792.0 b)
[root@slave ~]# ping 192.168.10.11 -c 1
PING 192.168.10.11 (192.168.10.11) 56(84) bytes of data.
64 bytes from 192.168.10.11: icmp_seq=1 ttl=64 time=1.90 ms

--- 192.168.10.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 1.901/1.901/1.901/0.000 ms
[root@slave ~]# ping 192.168.10.12 -c 1
PING 192.168.10.12 (192.168.10.12) 56(84) bytes of data.
64 bytes from 192.168.10.12: icmp_seq=1 ttl=64 time=2.76 ms

--- 192.168.10.12 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 2.768/2.768/2.768/0.000 ms
[root@slave ~]# curl -I http://192.168.10.11(访问192.168.10.11页面,-I显示http头部信息)
HTTP/1.1 200 OK
Date: Sun, 19 Jun 2016 15:11:11 GMT
Server: Apache/2.2.3 (Red Hat)
Last-Modified: Sun, 19 Jun 2016 08:16:41 GMT
ETag: "bef10-1b-35204c40"
Accept-Ranges: bytes
Content-Length: 27
Connection: close
Content-Type: text/html; charset=UTF-8
[root@slave ~]# curl -I http://192.168.10.12(访问192.168.10.12页面,-I显示http头部信息)
HTTP/1.1 200 OK
Date: Sun, 19 Jun 2016 10:03:26 GMT
Server: Apache/2.2.3 (Red Hat)
Last-Modified: Sun, 19 Jun 2016 03:10:41 GMT
ETag: "2e3b41-1b-eec8ee40"
Accept-Ranges: bytes
Content-Length: 27
Connection: close
Content-Type: text/html; charset=UTF-8
[root@slave ~]# yum -y install haproxy(通过yum源安装haproxy软件)
[root@slave media]# rpm -ql haproxy(查看安装haproxy安装生成那些文件)
/etc/haproxy(主配置文件)
/etc/haproxy/haproxy.cfg
/etc/logrotate.d/haproxy
/etc/rc.d/init.d/haproxy(服务脚本)
/usr/bin/halog
/usr/sbin/haproxy
/usr/share/doc/haproxy-1.4.22
/usr/share/doc/haproxy-1.4.22/CHANGELOG
/usr/share/doc/haproxy-1.4.22/LICENSE
/usr/share/doc/haproxy-1.4.22/README
/usr/share/doc/haproxy-1.4.22/acl-content-sw.cfg
/usr/share/doc/haproxy-1.4.22/acl.fig
/usr/share/doc/haproxy-1.4.22/architecture.txt
/usr/share/doc/haproxy-1.4.22/configuration.txt
/usr/share/doc/haproxy-1.4.22/content-sw-sample.cfg
/usr/share/doc/haproxy-1.4.22/cttproxy-src.cfg
/usr/share/doc/haproxy-1.4.22/design-thoughts
/usr/share/doc/haproxy-1.4.22/design-thoughts/backends-v0.txt
/usr/share/doc/haproxy-1.4.22/design-thoughts/backends.txt
/usr/share/doc/haproxy-1.4.22/design-thoughts/be-fe-changes.txt
/usr/share/doc/haproxy-1.4.22/design-thoughts/buffers.fig
/usr/share/doc/haproxy-1.4.22/design-thoughts/config-language.txt
/usr/share/doc/haproxy-1.4.22/design-thoughts/cttproxy-changes.txt
/usr/share/doc/haproxy-1.4.22/design-thoughts/how-it-works.txt
/usr/share/doc/haproxy-1.4.22/design-thoughts/http_load_time.url
/usr/share/doc/haproxy-1.4.22/design-thoughts/sess_par_sec.txt
/usr/share/doc/haproxy-1.4.22/gpl.txt
/usr/share/doc/haproxy-1.4.22/haproxy-en.txt
/usr/share/doc/haproxy-1.4.22/haproxy-fr.txt
/usr/share/doc/haproxy-1.4.22/haproxy.1
/usr/share/doc/haproxy-1.4.22/haproxy.cfg
/usr/share/doc/haproxy-1.4.22/internals
/usr/share/doc/haproxy-1.4.22/internals/connect-status.txt
/usr/share/doc/haproxy-1.4.22/internals/connection-header.txt
/usr/share/doc/haproxy-1.4.22/internals/connection-scale.txt
/usr/share/doc/haproxy-1.4.22/internals/header-parser-speed.txt
/usr/share/doc/haproxy-1.4.22/internals/header-tree.txt
/usr/share/doc/haproxy-1.4.22/internals/http-cookies.txt
/usr/share/doc/haproxy-1.4.22/internals/http-docs.txt
/usr/share/doc/haproxy-1.4.22/internals/http-parsing.txt
/usr/share/doc/haproxy-1.4.22/internals/naming.txt
/usr/share/doc/haproxy-1.4.22/internals/repartition-be-fe-fi.txt
/usr/share/doc/haproxy-1.4.22/internals/stats-v2.txt
/usr/share/doc/haproxy-1.4.22/internals/stream-sock-states.fig
/usr/share/doc/haproxy-1.4.22/internals/todo.cttproxy
/usr/share/doc/haproxy-1.4.22/lgpl.txt
/usr/share/doc/haproxy-1.4.22/queuing.fig
/usr/share/doc/haproxy-1.4.22/tarpit.cfg
/usr/share/doc/haproxy-1.4.22/url-switching.cfg
/usr/share/haproxy
/usr/share/haproxy/400.http
/usr/share/haproxy/403.http
/usr/share/haproxy/408.http
/usr/share/haproxy/500.http
/usr/share/haproxy/502.http
/usr/share/haproxy/503.http
/usr/share/haproxy/504.http
/usr/share/haproxy/README
/usr/share/man/man1/haproxy.1.gz
/var/lib/haproxy
[root@slave media]# man haproxy(查看haproxy帮助)

       HAProxy - fast and reliable http reverse proxy and load balancer

       haproxy  -f  <configuration file>(配置文件)  [-n maxconn](最大连接数)  [-N maxconn]  [-d]  [-D]  [-q]  [-V]  [-c] [-p <pidfile>] [-s]
 [-l] [-dk] [-ds] [-de] [-dp] [-db]
       [-m <megs>] [{-sf|-st} pidlist...]

       -f <configuration file>
              Specify configuration file path.

       -n <maxconn>
              Set the high limit for the total number of simultaneous connections.

       -N <maxconn>
              Set the high limit for the per-listener number of simultaneous connections.

       -d     Start  in  foregreound  with  debugging mode enabled.  When the proxy runs in this mode, it dumps every connections, disconne
ctions, times-
              tamps, and HTTP headers to stdout. This should NEVER be used in an init script since it will prevent the system from starting
 up.(在前台运行)

       -D     Start in daemon mode.(在后端运行,用于守护进程)

       -q     Disable messages on output.(静默模式)

       -V     Displays messages on output even when -q or 'quiet' are specified. Some information about pollers and 
 config  file  are  displayed  during
              startup.(详细模式)

       -c     Only checks config file and exits with code 0 if no error was found, or exits with code 1 if a syntax 
error was found.(检查配置文件语法)

       -p <pidfile>
              Ask the process to write down each of its children's pids to this file in daemon mode.(指定pid文件)

[root@slave media]# cd /etc/haproxy/(切换到/etc/haproxy目录)
[root@slave haproxy]# ls(查看当前目录文件及子目录)
haproxy.cfg
[root@slave haproxy]# cp haproxy.cfg haproxy.cfg.bak(复制haproxy.cfg为haproxy.cfg.bak)
[root@slave haproxy]# vim haproxy.cfg(编辑haproxy.cfg)

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

[root@slave haproxy]# yum list all | grep syslog(列出yum源软件包,只显示syslog相关)            
rsyslog.i686                        5.8.10-6.el6                @anaconda-RedHatEnterpriseLinux-201301301449.i386/6.4
rsyslog-gnutls.i686                 5.8.10-6.el6                Packages        
rsyslog-gssapi.i686                 5.8.10-6.el6                Packages        
rsyslog-mysql.i686                  5.8.10-6.el6                Packages        
rsyslog-pgsql.i686                  5.8.10-6.el6                Packages        
rsyslog-relp.i686                   5.8.10-6.el6                Packages        
sblim-cmpi-syslog.i686              0.8.0-1.el6                 Packages        
[root@slave haproxy]# rpm -ql rsyslog(查看rsyslog安装生成那些文件)
/etc/logrotate.d/syslog
/etc/pki/rsyslog
/etc/rc.d/init.d/rsyslog(脚本)
/etc/rsyslog.conf(配置文件)
/etc/rsyslog.d
/etc/sysconfig/rsyslog
/lib/rsyslog
/lib/rsyslog/imfile.so
/lib/rsyslog/imklog.so
/lib/rsyslog/immark.so
/lib/rsyslog/impstats.so
/lib/rsyslog/imptcp.so
/lib/rsyslog/imtcp.so
/lib/rsyslog/imudp.so
/lib/rsyslog/imuxsock.so
/lib/rsyslog/lmnet.so
/lib/rsyslog/lmnetstrms.so
/lib/rsyslog/lmnsd_ptcp.so
/lib/rsyslog/lmregexp.so
/lib/rsyslog/lmstrmsrv.so
/lib/rsyslog/lmtcpclt.so
/lib/rsyslog/lmtcpsrv.so
/lib/rsyslog/lmzlibw.so
/lib/rsyslog/ommail.so
/lib/rsyslog/omprog.so
/lib/rsyslog/omruleset.so
/lib/rsyslog/omtesting.so
/lib/rsyslog/omuxsock.so
/lib/rsyslog/pmlastmsg.so
/sbin/rsyslogd
/usr/share/doc/rsyslog-5.8.10
/usr/share/doc/rsyslog-5.8.10/AUTHORS
/usr/share/doc/rsyslog-5.8.10/COPYING
/usr/share/doc/rsyslog-5.8.10/COPYING.ASL20
/usr/share/doc/rsyslog-5.8.10/COPYING.LESSER
/usr/share/doc/rsyslog-5.8.10/ChangeLog
/usr/share/doc/rsyslog-5.8.10/NEWS
/usr/share/doc/rsyslog-5.8.10/README
/usr/share/doc/rsyslog-5.8.10/bugs.html
/usr/share/doc/rsyslog-5.8.10/build_from_repo.html
/usr/share/doc/rsyslog-5.8.10/contributors.html
/usr/share/doc/rsyslog-5.8.10/debug.html
/usr/share/doc/rsyslog-5.8.10/dev_queue.html
/usr/share/doc/rsyslog-5.8.10/droppriv.html
/usr/share/doc/rsyslog-5.8.10/expression.html
/usr/share/doc/rsyslog-5.8.10/features.html
/usr/share/doc/rsyslog-5.8.10/generic_design.html
/usr/share/doc/rsyslog-5.8.10/gssapi.html
/usr/share/doc/rsyslog-5.8.10/history.html
/usr/share/doc/rsyslog-5.8.10/how2help.html
/usr/share/doc/rsyslog-5.8.10/im3195.html
/usr/share/doc/rsyslog-5.8.10/imfile.html
/usr/share/doc/rsyslog-5.8.10/imgssapi.html
/usr/share/doc/rsyslog-5.8.10/imklog.html
/usr/share/doc/rsyslog-5.8.10/impstats.html
/usr/share/doc/rsyslog-5.8.10/imptcp.html
/usr/share/doc/rsyslog-5.8.10/imrelp.html
/usr/share/doc/rsyslog-5.8.10/imsolaris.html
/usr/share/doc/rsyslog-5.8.10/imtcp.html
/usr/share/doc/rsyslog-5.8.10/imuxsock.html
/usr/share/doc/rsyslog-5.8.10/index.html
/usr/share/doc/rsyslog-5.8.10/install.html
/usr/share/doc/rsyslog-5.8.10/ipv6.html
/usr/share/doc/rsyslog-5.8.10/licensing.html
/usr/share/doc/rsyslog-5.8.10/log_rotation_fix_size.html
/usr/share/doc/rsyslog-5.8.10/manual.html
/usr/share/doc/rsyslog-5.8.10/mmsnmptrapd.html
/usr/share/doc/rsyslog-5.8.10/modules.html
/usr/share/doc/rsyslog-5.8.10/multi_ruleset.html
/usr/share/doc/rsyslog-5.8.10/netstream.html
/usr/share/doc/rsyslog-5.8.10/ns_gtls.html
/usr/share/doc/rsyslog-5.8.10/ns_ptcp.html
/usr/share/doc/rsyslog-5.8.10/omlibdbi.html
/usr/share/doc/rsyslog-5.8.10/ommail.html
/usr/share/doc/rsyslog-5.8.10/ommysql.html
/usr/share/doc/rsyslog-5.8.10/omoracle.html
/usr/share/doc/rsyslog-5.8.10/omrelp.html
/usr/share/doc/rsyslog-5.8.10/omruleset.html
/usr/share/doc/rsyslog-5.8.10/omsnmp.html
/usr/share/doc/rsyslog-5.8.10/omstdout.html
/usr/share/doc/rsyslog-5.8.10/omudpspoof.html
/usr/share/doc/rsyslog-5.8.10/omuxsock.html
/usr/share/doc/rsyslog-5.8.10/pmlastmsg.html
/usr/share/doc/rsyslog-5.8.10/property_replacer.html
/usr/share/doc/rsyslog-5.8.10/queues.html
/usr/share/doc/rsyslog-5.8.10/queues_analogy.html
/usr/share/doc/rsyslog-5.8.10/rainerscript.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_actionexeconlywhenpreviousissuspended.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_actionresumeinterval.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_allowedsender.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_controlcharacterescapeprefix.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_debugprintcfsyslinehandlerlist.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_debugprintmodulelist.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_debugprinttemplatelist.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_dircreatemode.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_dirgroup.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_dirowner.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_dropmsgswithmaliciousdnsptrrecords.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_droptrailinglfonreception.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_dynafilecachesize.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_escape8bitcharsonreceive.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_escapecontrolcharactersonreceive.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_failonchownfailure.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_filecreatemode.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_filegroup.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_fileowner.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_generateconfiggraph.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_gssforwardservicename.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_gsslistenservicename.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_gssmode.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_includeconfig.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_mainmsgqueuesize.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_markmessageperiod.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_moddir.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_modload.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_repeatedmsgreduction.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_resetconfigvariables.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_rulesetcreatemainqueue.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_rulesetparser.html
/usr/share/doc/rsyslog-5.8.10/rsconf1_umask.html
/usr/share/doc/rsyslog-5.8.10/rscript_abnf.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_actions.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_examples.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_filter.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_global.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_modules.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_nomatch.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_output.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_conf_templates.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_high_database_rate.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_mysql.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_ng_comparison.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_packages.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_pgsql.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_php_syslog_ng.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_recording_pri.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_reliable_forwarding.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_secure_tls.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_stunnel.html
/usr/share/doc/rsyslog-5.8.10/rsyslog_tls.html
/usr/share/doc/rsyslog-5.8.10/syslog_parsing.html
/usr/share/doc/rsyslog-5.8.10/syslog_protocol.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_ca.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_client.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_errmsgs.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_machine.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_scenario.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_server.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_summary.html
/usr/share/doc/rsyslog-5.8.10/tls_cert_udp_relay.html
/usr/share/doc/rsyslog-5.8.10/troubleshoot.html
/usr/share/doc/rsyslog-5.8.10/v3compatibility.html
/usr/share/doc/rsyslog-5.8.10/v4compatibility.html
/usr/share/doc/rsyslog-5.8.10/v5compatibility.html
/usr/share/doc/rsyslog-5.8.10/version_naming.html
/usr/share/man/man5/rsyslog.conf.5.gz
/usr/share/man/man8/rsyslogd.8.gz
/var/lib/rsyslog
[root@slave haproxy]# vim /etc/sysconfig/rsyslog(编辑rsyslog文件)   

# Options for rsyslogd
# Syslogd options are deprecated since rsyslog v3.
# If you want to use them, switch to compatibility mode 2 by "-c 2"
# See rsyslogd(8) for more details
SYSLOGD_OPTIONS="-c 5 -r"

[root@slave haproxy]# vim /etc/rsyslog.conf(编辑rsyslog.conf)

local2.*                                                /var/log/haproxy.lpg

[root@slave haproxy]# service rsyslog restart(重启rsyslog服务)
关闭系统日志记录器:                                       [确定]
启动系统日志记录器:-r option only supported in compatibility modes 0 to 2 - ignored
                                                           [确定]
[root@slave haproxy]# vim /etc/rsyslog.conf(编辑rsyslog.conf配置文件)
[root@slave haproxy]# vim /etc/sysconfig/rsyslog(编辑rsyslog文件)

SYSLOGD_OPTIONS="-c 2 -r"

[root@slave haproxy]# service rsyslog restart(重启rsyslog服务)
关闭系统日志记录器:                                       [确定]
启动系统日志记录器:                                       [确定]
[root@slave haproxy]# vim /etc/sysconfig/rsyslog(编辑rsyslog文件)

# Options for rsyslogd
# Syslogd options are deprecated since rsyslog v3.
# If you want to use them, switch to compatibility mode 2 by "-c 2"
# See rsyslogd(8) for more details
SYSLOGD_OPTIONS="-c 2 -r"
[root@slave haproxy]# vim haproxy.cfg(编辑haproxy.cfg配置文件)

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

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull(不记录空信息)
    option http-server-close(启用http服务端关闭)
    option forwardfor       except 127.0.0.0/8(来自这个地址都不添加到x-forwarded-for首部)
    option                  redispatch(重新分发)
    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                 3000

listen stats(状态)
    mode http
    bind *:1080(监听端口)
    stats enable(状态启用)
    stats hide-version
    stats uri     /haproxyadmin?stats
    stats realm   Haproxy\ Statistics
    stats auth    admin:admin
    stats admin if TRUE

frontend web
    bind *:80(监听端口)
    log global(日志如何记录)
    option httpclose
    option logasap(提前记录日志)
    option dontlognull(不记录空日志信息)
    capture request  header Host len 20(如果是host还要抓取host的信息的前20个字节保留下来)
    capture request  header Referer len 60(抓取请求首部的referer的前60字节保留下来)
    default_backend servers

backend servers
    balance roundrobin(调度算法)
    server web1 192.168.10.11:80 check maxconn 4000(check健康状况检查,maxconn最大连接数)
    server web2 192.168.10.12:80 check maxconn 3000

:.,$d

[root@slave haproxy]# haproxy -c
HA-Proxy version 1.4.22 2012/08/09
Copyright 2000-2012 Willy Tarreau <w@1wt.eu>

Usage : haproxy [-f <cfgfile>]* [ -vdVD ] [ -n <maxconn> ] [ -N <maxpconn> ]
        [ -p <pidfile> ] [ -m <max megs> ]
        -v displays version ; -vv shows known build options.
        -d enters debug mode ; -db only disables background mode.
        -V enters verbose mode (disables quiet mode)
        -D goes daemon
        -q quiet mode : don't display messages
        -c check mode : only check config files and exit(检查模式)
        -n sets the maximum total # of connections (2000)
        -m limits the usable amount of memory (in MB)
        -N sets the default, per-proxy maximum # of connections (2000)
        -p writes pids of all children to this file
        -de disables epoll() usage even when available
        -ds disables speculative epoll() usage even when available
        -dp disables poll() usage even when available
        -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.
[root@slave haproxy]# service haproxy start(启动haproxy服务)
正在启动 haproxy:                                         [确定]
[root@slave haproxy]# netstat -tnlp(查看系统服务,-t代表tcp,-n以数字显示,-l监听端口,-p显示服务名称)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      2144/haproxy        
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1139/sshd           
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      1106/cupsd          
tcp        0      0 0.0.0.0:1080                0.0.0.0:*                   LISTEN      2144/haproxy        
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1672/master         
tcp        0      0 127.0.0.1:6010              0.0.0.0:*                   LISTEN      2107/sshd           
tcp        0      0 :::3306                     :::*                        LISTEN      1565/mysqld         
tcp        0      0 :::22                       :::*                        LISTEN      1139/sshd           
tcp        0      0 ::1:631                     :::*                        LISTEN      1106/cupsd          
tcp        0      0 ::1:25                      :::*                        LISTEN      1672/master         
tcp        0      0 ::1:6010                    :::*                        LISTEN      2107/sshd  
提示:80和1080端口都监听了;
[root@slave haproxy]# ps aux(查看所有终端进程) 
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   2900  1432 ?        Ss   07:04   0:01 /sbin/init
root         2  0.0  0.0      0     0 ?        S    07:04   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    07:04   0:00 [migration/0]
root         4  0.0  0.0      0     0 ?        S    07:04   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S    07:04   0:00 [migration/0]
root         6  0.0  0.0      0     0 ?        S    07:04   0:00 [watchdog/0]
root         7  0.0  0.0      0     0 ?        S    07:04   0:00 [events/0]
root         8  0.0  0.0      0     0 ?        S    07:04   0:00 [cgroup]
root         9  0.0  0.0      0     0 ?        S    07:04   0:00 [khelper]
root        10  0.0  0.0      0     0 ?        S    07:04   0:00 [netns]
root        11  0.0  0.0      0     0 ?        S    07:04   0:00 [async/mgr]
root        12  0.0  0.0      0     0 ?        S    07:04   0:00 [pm]
root        13  0.0  0.0      0     0 ?        S    07:04   0:00 [sync_supers]
root        14  0.0  0.0      0     0 ?        S    07:04   0:00 [bdi-default]
root        15  0.0  0.0      0     0 ?        S    07:04   0:00 [kintegrityd/0]
root        16  0.0  0.0      0     0 ?        S    07:04   0:00 [kblockd/0]
root        17  0.0  0.0      0     0 ?        S    07:04   0:00 [kacpid]
root        18  0.0  0.0      0     0 ?        S    07:04   0:00 [kacpi_notify]
root        19  0.0  0.0      0     0 ?        S    07:04   0:00 [kacpi_hotplug]
root        20  0.0  0.0      0     0 ?        S    07:04   0:00 [ata/0]
root        21  0.0  0.0      0     0 ?        S    07:04   0:00 [ata_aux]
root        22  0.0  0.0      0     0 ?        S    07:04   0:00 [ksuspend_usbd]
root        23  0.0  0.0      0     0 ?        S    07:04   0:00 [khubd]
root        24  0.0  0.0      0     0 ?        S    07:04   0:00 [kseriod]
root        25  0.0  0.0      0     0 ?        S    07:04   0:00 [md/0]
root        26  0.0  0.0      0     0 ?        S    07:04   0:00 [md_misc/0]
root        27  0.0  0.0      0     0 ?        S    07:04   0:00 [khungtaskd]
root        28  0.0  0.0      0     0 ?        S    07:04   0:00 [kswapd0]
root        29  0.0  0.0      0     0 ?        SN   07:04   0:00 [ksmd]
root        30  0.0  0.0      0     0 ?        S    07:04   0:00 [aio/0]
root        31  0.0  0.0      0     0 ?        S    07:04   0:00 [crypto/0]
root        36  0.0  0.0      0     0 ?        S    07:04   0:00 [kthrotld/0]
root        37  0.0  0.0      0     0 ?        S    07:04   0:00 [pciehpd]
root        39  0.0  0.0      0     0 ?        S    07:04   0:00 [kpsmoused]
root        40  0.0  0.0      0     0 ?        S    07:04   0:00 [usbhid_resumer]
root       200  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_0]
root       202  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_1]
root       209  0.0  0.0      0     0 ?        S    07:04   0:00 [mpt_poll_0]
root       210  0.0  0.0      0     0 ?        S    07:04   0:00 [mpt/0]
root       211  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_2]
root       230  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_3]
root       231  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_4]
root       232  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_5]
root       233  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_6]
root       234  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_7]
root       235  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_8]
root       236  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_9]
root       237  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_10]
root       238  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_11]
root       239  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_12]
root       240  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_13]
root       241  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_14]
root       242  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_15]
root       243  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_16]
root       244  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_17]
root       245  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_18]
root       246  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_19]
root       247  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_20]
root       248  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_21]
root       249  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_22]
root       250  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_23]
root       251  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_24]
root       252  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_25]
root       253  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_26]
root       254  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_27]
root       255  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_28]
root       256  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_29]
root       257  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_30]
root       258  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_31]
root       259  0.0  0.0      0     0 ?        S    07:04   0:00 [scsi_eh_32]
root       372  0.0  0.0      0     0 ?        S    07:04   0:01 [kjournald]
root       451  0.0  0.0   2700   996 ?        S<s  07:04   0:00 /sbin/udevd -d
root       644  0.0  0.0      0     0 ?        S    07:04   0:00 [vmmemctl]
root       670  0.0  0.0      0     0 ?        S    07:04   0:00 [flush-8:0]
root       712  0.0  0.0      0     0 ?        S    07:04   0:00 [bluetooth]
root       786  0.0  0.0      0     0 ?        S    07:04   0:00 [kstriped]
root       815  0.0  0.0      0     0 ?        S    07:04   0:00 [kjournald]
root       853  0.0  0.0      0     0 ?        S    07:04   0:00 [kauditd]
root      1056  0.0  0.0  12932   820 ?        S<sl 07:05   0:00 auditd
dbus      1094  0.0  0.0  13244  1100 ?        Ssl  07:05   0:00 dbus-daemon --system
root      1106  0.0  0.1  13968  2772 ?        Ss   07:05   0:00 cupsd -C /etc/cups/cupsd.conf
root      1139  0.0  0.0   8576  1024 ?        Ss   07:05   0:00 /usr/sbin/sshd
root      1156  0.0  0.0   6268  1452 ?        S    07:05   0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/mydata/data --pid-file=
/mydata/data/s
mysql     1565  0.1  4.4 428716 86072 ?        Sl   07:05   0:05 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/mydata/da
ta --plugin-di
root      1672  0.0  0.1  12524  2516 ?        Ss   07:05   0:00 /usr/libexec/postfix/master
postfix   1680  0.0  0.1  12600  2476 ?        S    07:05   0:00 pickup -l -t fifo -u
postfix   1681  0.0  0.1  12668  2512 ?        S    07:05   0:00 qmgr -l -t fifo -u
root      1682  0.0  0.0   7972  1272 ?        Ss   07:05   0:00 crond
root      1693  0.0  0.0   2920   464 ?        Ss   07:05   0:00 /usr/sbin/atd
root      1706  0.0  0.0   6156   668 ?        Ss   07:05   0:00 /usr/bin/rhsmcertd
root      1720  0.0  0.0   3904  1880 ?        Ss   07:05   0:00 login -- root     
root      1722  0.0  0.0   2008   504 tty2     Ss+  07:05   0:00 /sbin/mingetty /dev/tty2
root      1724  0.0  0.0   2008   508 tty3     Ss+  07:05   0:00 /sbin/mingetty /dev/tty3
root      1726  0.0  0.0   2008   512 tty4     Ss+  07:05   0:00 /sbin/mingetty /dev/tty4
root      1731  0.0  0.0   2008   512 tty5     Ss+  07:05   0:00 /sbin/mingetty /dev/tty5
root      1732  0.0  0.0   3372  1852 ?        S<   07:05   0:00 /sbin/udevd -d
root      1733  0.0  0.0   3372  1792 ?        S<   07:05   0:00 /sbin/udevd -d
root      1735  0.0  0.0   2008   504 tty6     Ss+  07:05   0:00 /sbin/mingetty /dev/tty6
root      1740  0.0  0.1  21944  2920 ?        Sl   07:05   0:00 /usr/sbin/console-kit-daemon --no-daemon
root      1807  0.0  0.0   7988  1756 tty1     Ss+  07:05   0:00 -bash
root      2096  0.0  0.0  46256  1472 ?        Sl   08:01   0:00 /sbin/rsyslogd -i /var/run/syslogd.pid -c 2 -r
root      2107  0.0  0.1  11652  3332 ?        Rs   08:31   0:00 sshd: root@pts/0 
root      2111  0.0  0.0   6844  1740 pts/0    Ss   08:31   0:00 -bash
haproxy   2144  0.0  0.0   3820   988 ?        Ss   08:35   0:00 /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
(haproxy启动命令)
root      2147  0.0  0.0   6544  1060 pts/0    R+   08:36   0:00 ps aux

测试:通过Windows的ie浏览器访问172.16.100.107;

刷新后变为后端http-HA2主机页面;

测试:通过Windows的ie浏览器访问http://172.16.100.107:1080/haproxyadmin?stats;

输入用户名admin,密码admin;

后端http-HA2服务器:

[root@node2 ~]# service httpd stop(停止httpd服务)
停止 httpd:                                               [确定]

刷新http://172.16.100.107:1080/haproxyadmin?stats页面;

后端http-HA2服务器:

[root@node2 ~]# service httpd start(启动httpd服务)
启动 httpd:[Sun Jun 19 20:02:25 2016] [warn] module dav_module is already loaded, skipping
                                                           [确定]

haproxy:

[root@slave haproxy]# vim haproxy.cfg(编辑haproxy.cfg配置文件)

反向代理:缓存

HTTP/1.1

  HTTP/1.1 <-- HTTP/1.0

    cache

web object:

browser: 缓存机制

  本地:

Expire: 绝对时间计时法,2013-05-21 14:55:31

max-age: 相对时间计时法,Cache-Control: max-age=600

index.html: 14:55;59

14:55:59, 0000011:

 

Etag: a9873db

If-None-match

条件判断:

私有缓存:浏览器自己的缓存;

公共缓存:缓存服务器缓存;

CDN: Content Delivery Network 内容分发网络;

Bind, view

  Bind-dlz + MySQL

    pgsql, Oracle, db4

Squid: varnish

Httpd: nginx

Nginx + varnish

Nginx + Squid

Varnish Architecture

vcl_recv

  vcl_pass

  vcl_hash

    vcl_hist

      vcl_deliver

    vcl_miss

        vcl_pass

      vcl_fetch

        vcl_deliver

 

一、关于Varnish

1、varnish系统架构

varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)。

Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔几秒钟探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Management将会重启此Child进程。

Child进程包含多种类型的线程,常见的如:

Acceptor线程:接收新的连接请求并响应;

Worker线程:child进程会为每个会话启动一个worker线程,因此,在高并发的场景中可能会出现数百个worker线程甚至更多;

Expiry线程:从缓存中清理过期内容;

Varnish依赖“工作区(workspace)”以降低线程在申请或修改内存时出现竞争的可能性。在varnish内部有多种不同的工作区,其中最关键的当属用于管理会话数据的session工作区。

2、varnish日志

为了与系统的其它部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此,如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个worker线程都使用了日志数据缓存。

共享内存日志大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish提供了多个不同的工具如varnishlog、varnishncsa或varnishstat等来分析共享内存日志中的信息并能够以指定的方式进行显示。

 

3、VCL

Varnish Configuration Language (VCL)是varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等。使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认的定义。

VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成。

4、varnish的后端存储

varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:

(1)file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果条件允许);

(2)malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;

(3)persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;

varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此,file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以,其仅适用于有着巨大缓存空间的场景。

选择使用合适的存储方式有助于提升系统性,从经验的角度来看,建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之,file存储将有着更好的性能的表现。然而,需要注意的是,varnishd实际上使用的空间比使用-s选项指定的缓存空间更大,一般说来,其需要为每个缓存对象多使用差不多1K左右的存储空间,这意味着,对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外,为了保存数据结构等,varnish自身也会占去不小的内存空间。

为varnishd指定使用的缓存类型时,-s选项可接受的参数格式如下:

  malloc[,size] 或

    file[,path[,size[,granularity]]] 或

  persistent,path,size {experimental}

file中的granularity用于设定缓存空间分配单位,默认单位是字节,所有其它的大小都会被圆整。

二、安装varnish

 

三、HTTP协议与varnish

1、缓存相关的HTTP首部

HTTP协议提供了多个首部用以实现页面缓存及缓存失效的相关功能,这其中最常用的有:

(1)Expires:用于指定某web对象的过期日期/时间,通常为GMT格式;一般不应该将此设定的未来过长的时间,一年的长度对大多场景来说足矣;其常用于为纯静态内容如JavaScripts样式表或图片指定缓存周期;

(2)Cache-Control:用于定义所有的缓存机制都必须遵循的缓存指示,这些指示是一些特定的指令,包括public、private、no-cache(表示可以存储,但在重新验正其有效性之前不能用于响应客户端请求)、no-store、max-age、s-maxage以及must-revalidate等;Cache-Control中设定的时间会覆盖Expires中指定的时间;

(3)Etag:响应首部,用于在响应报文中为某web资源定义版本标识符;

(4)Last-Mofified:响应首部,用于回应客户端关于Last-Modified-Since或If-None-Match首部的请求,以通知客户端其请求的web对象最近的修改时间;

(5)If-Modified-Since:条件式请求首部,如果在此首部指定的时间后其请求的web内容发生了更改,则服务器响应更改后的内容,否则,则响应304(not modified);

(6)If-None-Match:条件式请求首部;web服务器为某web内容定义了Etag首部,客户端请求时能获取并保存这个首部的值(即标签);而后在后续的请求中会通过If-None-Match首部附加其认可的标签列表并让服务器端检验其原始内容是否有可以与此列表中的某标签匹配的标签;如果有,则响应304,否则,则返回原始内容;

(7)Vary:响应首部,原始服务器根据请求来源的不同响应的可能会有所不同的首部,最常用的是Vary: Accept-Encoding,用于通知缓存机制其内容看起来可能不同于用户请求时Accept-Encoding-header首部标识的编码格式;

(8)Age:缓存服务器可以发送的一个额外的响应首部,用于指定响应的有效期限;浏览器通常根据此首部决定内容的缓存时长;如果响应报文首部还使用了max-age指令,那么缓存的有效时长为“max-age减去Age”的结果;

 

四、Varnish状态引擎(state engine)

VCL用于让管理员定义缓存策略,而定义好的策略将由varnish的management进程分析、转换成C代码、编译成二进制程序并连接至child进程。varnish内部有几个所谓的状态(state),在这些状态上可以附加通过VCL定义的策略以完成相应的缓存处理机制,因此VCL也经常被称作“域专用”语言或状态引擎,“域专用”指的是有些数据仅出现于特定的状态中。

1、VCL状态引擎

在VCL状态引擎中,状态之间具有相关性,但彼此间互相隔离,每个引擎使用return(x)来退出当前状态并指示varnish进入下一个状态。

varnish开始处理一个请求时,首先需要分析HTTP请求本身,比如从首部获取请求方法、验正其是否为一个合法的HTT请求等。当这些基本分析结束后就需要做出第一个决策,即varnish是否从缓存中查找请求的资源。这个决定的实现则需要由VCL来完成,简单来说,要由vcl_recv方法来完成。如果管理员没有自定义vcl_recv函数,varnish将会执行默认的vcl_recv函数。然而,即便管理员自定义了vcl_recv,但如果没有为自定义的vcl_recv函数指定其终止操作(terminating),其仍将执行默认的vcl_recv函数。事实上,varnish官方强烈建议让varnish执行默认的vcl_recv以便处理自定义vcl_recv函数中的可能出现的漏洞。

 

2、VCL语法

VCL的设计参考了C和Perl语言,因此,对有着C或Perl编程经验者来说,其非常易于理解。其基本语法说明如下:

(1)//、#或/* comment */用于注释

(2)sub $name 定义函数

(3)不支持循环,有内置变量

(4)使用终止语句,没有返回值

(5)域专用

(6)操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)

VCL的函数不接受参数并且没有返回值,因此,其并非真正意义上的函数,这也限定了VCL内部的数据传递只能隐藏在HTTP首部内部进行。VCL的return语句用于将控制权从VCL状态引擎返回给Varnish,而非默认函数,这就是为什么VCL只有终止语句而没有返回值的原因。同时,对于每个“域”来说,可以定义一个或多个终止语句,以告诉Varnish下一步采取何种操作,如查询缓存或不查询缓存等。

 

3、VCL的内置函数

VCL提供了几个函数来实现字符串的修改,添加bans,重启VCL状态引擎以及将控制权转回Varnish等。

regsub(str,regex,sub)

regsuball(str,regex,sub):这两个用于基于正则表达式搜索指定的字符串并将其替换为指定的字符串;但regsuball()可以将str中能够被regex匹配到的字符串统统替换为sub,regsub()只替换一次;

ban(expression):

ban_url(regex):Bans所有其URL能够由regex匹配的缓存对象;

purge:从缓存中挑选出某对象以及其相关变种一并删除,这可以通过HTTP协议的PURGE方法完成;

hash_data(str):

return():当某VCL域运行结束时将控制权返回给Varnish,并指示Varnish如何进行后续的动作;其可以返回的指令包括:lookup、pass、pipe、hit_for_pass、fetch、deliver和hash等;但某特定域可能仅能返回某些特定的指令,而非前面列出的全部指令;

return(restart):重新运行整个VCL,即重新从vcl_recv开始进行处理;每一次重启都会增加req.restarts变量中的值,而max_restarts参数则用于限定最大重启次数。

 

4、vcl_recv

vcl_recv是在Varnish完成对请求报文的解码为基本数据结构后第一个要执行的子例程,它通常有四个主要用途:

(1)修改客户端数据以减少缓存对象差异性;比如删除URL中的www.等字符;

(2)基于客户端数据选用缓存策略;比如仅缓存特定的URL请求、不缓存POST请求等;

(3)为某web应用程序执行URL重写规则;

(4)挑选合适的后端Web服务器;

可以使用下面的终止语句,即通过return()向Varnish返回的指示操作:

pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;

pipe:不对客户端进行检查或做出任何操作,而是在客户端与后端服务器之间建立专用“管道”,并直接将数据在二者之间进行传送;此时,keep-alive连接中后续传送的数据也都将通过此管道进行直接传送,并不会出现在任何日志中;

lookup:在缓存中查找用户请求的对象,如果缓存中没有其请求的对象,后续操作很可能会将其请求的对象进行缓存;

error:由Varnish自己合成一个响应报文,一般是响应一个错误类信息、重定向类信息或负载均衡器返回的后端web服务器健康状态检查类信息;

 

vcl_recv也可以通过精巧的策略完成一定意义上的安全功能,以将某些特定的攻击扼杀于摇篮中。同时,它也可以检查出一些拼写类的错误并将其进行修正等。

Varnish默认的vcl_recv专门设计用来实现安全的缓存策略,它主要完成两种功能:

(1)仅处理可以识别的HTTP方法,并且只缓存GET和HEAD方法;

(2)不缓存任何用户特有的数据;

安全起见,一般在自定义的vcl_recv中不要使用return()终止语句,而是再由默认vcl_recv进行处理,并由其做出相应的处理决策。

下面是一个自定义的使用示例:

sub vcl_recv {

  if (req.http.User-Agent ~ "iPad" ||

    req.http.User-Agent ~ "iPhone" ||

    req.http.User-Agent ~ "Android") {

      set req.http.X-Device = "mobile";

  } else {

    set req.http.X-Device = "desktop";

  }

}

 

此例中的VCL创建一个X-Device请求首部,其值可能为mobile或desktop,于是web服务器可以基于此完成不同类型的响应,以提高用户体验。

5、vcl_fetch

如前面所述,相对于vcl_recv是根据客户端的请求作出缓存决策来说,vcl_fetch则是根据服务器端的响应作出缓存决策。在任何VCL状态引擎中返回的pass操作都将由vcl_fetch进行后续处理。vcl_fetch中有许多可用的内置变量,比如最常用的用于定义某对象缓存时长的beresp.ttl变量。通过return()返回给arnish的操作指示有:

(1)deliver:缓存此对象,并将其发送给客户端(经由vcl_deliver);

(2)hit_for_pass:不缓存此对象,但可以导致后续对此对象的请求直接送达到vcl_pass进行处理;

(3)restart:重启整个VCL,并增加重启计数;超出max_restarts限定的最大重启次数后将会返回错误信息;

(4)error code [reason]:返回指定的错误代码给客户端并丢弃此请求;

默认的vcl_fetch放弃了缓存任何使用了Set-Cookie首部的响应。

 

五、修剪缓存对象

1、缓存内容修剪

提高缓存命中率的最有效途径之一是增加缓存对象的生存时间(TTL),但是这也可能会带来副作用,比如缓存的内容在到达为其指定的有效期之间已经失效。因此,手动检验缓存对象的有效性或者刷新缓存是缓存很有可能成为服务器管理员的日常工作之一,相应地,Varnish为完成这类的任务提供了三种途径:HTTP 修剪(HTTP purging)、禁用某类缓存对象(banning)和强制缓存未命令(forced cache misses)。

这里需要特殊说明的是,Varnish 2中的purge()操作在Varnish 3中被替换为了ban()操作,而Varnish 3也使用了purge操作,但为其赋予了新的功能,且只能用于vcl_hit或vcl_miss中替换Varnish 2中常用的set obj.ttl=0s。

 

在具体执行某清理工作时,需要事先确定如下问题:

(1)仅需要检验一个特定的缓存对象,还是多个?

(2)目的是释放内存空间,还是仅替换缓存的内容?

(3)是不是需要很长时间才能完成内容替换?

(4)这类操作是个日常工作,还是仅此一次的特殊需求?

 

2、移除单个缓存对象

purge用于清理缓存中的某特定对象及其变种(variants),因此,在有着明确要修剪的缓存对象时可以使用此种方式。HTTP协议的PURGE方法可以实现purge功能,不过,其仅能用于vcl_hit和vcl_miss中,它会释放内存工作并移除指定缓存对象的所有Vary:-变种,并等待下一个针对此内容的客户端请求到达时刷新此内容。另外,其一般要与return(restart)一起使用。下面是个在VCL中配置的示例。

 

acl purgers {

  "127.0.0.1";

  "192.168.0.0"/24;

}

sub vcl_recv {

  if (req.request == "PURGE") {

    if (!client.ip ~ purgers) {

      error 405 "Method not allowed";
    }

    return (lookup);

  }

}

sub vcl_hit {

  if (req.request == "PURGE") {

    purge;

    error 200 "Purged";

  }

}

sub vcl_miss {

  if (req.request == "PURGE") {

    purge;

    error 404 "Not in cache";

  }

}

sub vcl_pass {

  if (req.request == "PURGE") {

    error 502 "PURGE on a passed object";

  }
}

 

客户端在发起HTTP请求时,只需要为所请求的URL使用PURGE方法即可,其命令使用方式如下:

# curl -I PURGE http://varniship/path/to/someurl

3、强制缓存未命中

在vcl_recv中使用return(pass)能够强制到上游服务器取得请求的内容,但这也会导致无法将其缓存。使用purge会移除旧的缓存对象,但如果上游服务器宕机而无法取得新版本的内容时,此内容将无法再响应给客户端。使用req.has_always_miss=ture,可以让Varnish在缓存中搜寻相应的内容但却总是回应“未命中”,于是vcl_miss将后续地负责启动vcl_fetch从上游服务器取得新内容,并以新内容缓存覆盖旧内容。此时,如果上游服务器宕机或未响应,旧的内容将保持原状,并能够继续服务于那些未使用req.has_always_miss=true的客户端,直到其过期失效或由其它方法移除。

4、Banning

ban()是一种从已缓存对象中过滤(filter)出某此特定的对象并将其移除的缓存内容刷新机制,不过,它并不阻止新的内容进入缓存或响应于请求。在Varnish中,ban的实现是指将一个ban添加至ban列表(ban-list)中,这可以通过命令行接口或VCL实现,它们的使用语法是相同的。ban本身就是一个或多个VCL风格的语句,它会在Varnish从缓存哈希(cache hash)中查找某缓存对象时对搜寻的对象进行比较测试,因此,一个ban语句就是类似匹配所有“以/downloads开头的URL”,或“响应首部中包含nginx的对象”。例如:
ban req.http.host == "magedu.com" && req.url ~ "\.gif$"

定义好的所有ban语句会生成一个ban列表(ban-list),新添加的ban语句会被放置在列表的首部。缓存中的所有对象在响应给客户端之前都会被ban列表检查至少一次,检查完成后将会为每个缓存创建一个指向与其匹配的ban语句的指针。Varnish在从缓存中获取对象时,总是会检查此缓存对象的指针是否指向了ban列表的首部。如果没有指向ban列表的首部,其将对使用所有的新添加的ban语句对此缓存对象进行测试,如果没有任何ban语句能够匹配,则更新ban列表。

对ban这种实现方式持反对意见有有之,持赞成意见者亦有之。反对意见主要有两种,一是ban不会释放内存,缓存对象仅在有客户端访问时被测试一次;二是如果缓存对象曾经被访问到,但却很少被再次访问时ban列表将会变得非常大。赞成的意见则主要集中在ban可以让Varnish在恒定的时间内完成向ban列表添加ban的操作,例如在有着数百万个缓存对象的场景中,添加一个ban也只需要在恒定的时间内即可完成。其实现方法本处不再详细说明。

六、Varnish检测后端主机的健康状态

Varnish可以检测后端主机的健康状态,在判定后端主机失效时能自动将其从可用后端主机列表中移除,而一旦其重新变得可用还可以自动将其设定为可用。为了避免误判,Varnish在探测后端主机的健康状态发生转变时(比如某次探测时某后端主机突然成为不可用状态),通常需要连续执行几次探测均为新状态才将其标记为转换后的状态。

每个后端服务器当前探测的健康状态探测方法通过.probe进行设定,其结果可由req.backend.healthy变量获取,也可通过varnishlog中的Backend_health查看或varnishadm的debug.health查看。

 

backend web1 {

  .host = "www.magedu.com";

  .probe = {

    .url = "/.healthtest.html";

    .interval = 1s;

    .window = 5;

    .threshold = 2;

  }

}

 

.probe中的探测指令常用的有:

(1) .url:探测后端主机健康状态时请求的URL,默认为“/”;

(2) .request: 探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;比如:

.request =

  "GET /.healthtest.html HTTP/1.1"

  "Host: www.magedu.com"

  "Connection: close";

(3) .window:设定在判定后端主机健康状态时基于最近多少次的探测进行,默认是8;

(4) .threshold:在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行;默认是3;

(5) .initial:Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;

(6) .expected_response:期望后端主机响应的状态码,默认为200;

(7) .interval:探测请求的发送周期,默认为5秒;

(8) .timeout:每次探测请求的过期时长,默认为2秒;

 

因此,如上示例中表示每隔1秒对此后端主机www.magedu.com探测一次,请求的URL为http://www.magedu.com/.healthtest.html,在最近5次的探测请求中至少有2次是成功的(响应码为200)就判定此后端主机为正常工作状态。

如果Varnish在某时刻没有任何可用的后端主机,它将尝试使用缓存对象的“宽容副本”(graced copy),当然,此时VCL中的各种规则依然有效。因此,更好的办法是在VCL规则中判断req.backend.healthy变量显示某后端主机不可用时,为此后端主机增大req.grace变量的值以设定适用的宽容期限长度。

七、Varnish使用多台后端主机

Varnish中可以使用director指令将一个或多个近似的后端主机定义为一个逻辑组,并可以指定的调度方式(也叫挑选方法)来轮流将请求发送至这些主机上。不同的director可以使用同一个后端主机,而某director也可以使用“匿名”后端主机(在director中直接进行定义)。每个director都必须有其专用名,且在定义后必须在VCL中进行调用,VCL中任何可以指定后端主机的位置均可以按需将其替换为调用某已定义的director。

 

backend web1 {

  .host = "backweb1.magedu.com";

  .port = "80";

}

 

director webservers random {

  .retries = 5;

  {

    .backend = web1;

    .weight = 2;

  }

  {

  .backend = {

    .host = "backweb2.magedu.com";

    .port = "80";

  }

  .weight = 3;

  }

}

 

如上示例中,web1为显式定义的后端主机,而webservers这个directors还包含了一个“匿名”后端主机(backweb2.magedu.com)。webservers从这两个后端主机中挑选一个主机的方法为random,即以随机方式挑选。

Varnish的director支持的挑选方法中比较简单的有round-robin和random两种。其中,round-robin类型没有任何参数,只需要为其指定各后端主机即可,挑选方式为“轮叫”,并在某后端主机故障时不再将其视作挑选对象;random方法随机从可用后端主机中进行挑选,每一个后端主机都需要一个.weight参数以指定其权重,同时还可以director级别使用.retires参数来设定查找一个健康后端主机时的尝试次数。

Varnish 2.1.0后,random挑选方法又多了两种变化形式client和hash。client类型的director使用client.identity作为挑选因子,这意味着client.identity相同的请求都将被发送至同一个后端主机。client.identity默认为cliet.ip,但也可以在VCL中将其修改为所需要的标识符。类似地,hash类型的director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。然而,无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端其机。

八、varnish管理进阶

1、可调参数

Varnish有许多参数,虽然大多数场景中这些参数的默认值都可以工作得很好,然而特定的工作场景中要想有着更好的性能的表现,则需要调整某些参数。可以在管理接口中使用param.show命令查看这些参数,而使用param.set则能修改这些参数的值。然而,在命令行接口中进行的修改不会保存至任何位置,因此,重启varnish后这些设定会消失。此时,可以通过启动脚本使用-p选项在varnishd启动时为其设定参数的值。然而,除非特别需要对其进行修改,保持这些参数为默认值可以有效降低管理复杂度。

 

2、共享内存日志

共享内存日志(shared memory log)通常被简称为shm-log,它用于记录日志相关的数据,大小为80M。varnish以轮转(round-robin)的方式使用其存储空间。一般不需要对shm-log做出更多的设定,但应该避免其产生I/O,这可以使用tmpfs实现,其方法为在/etc/fstab中设定一个挂载至/var/lib/varnish目录(或其它自定义的位置)临时文件系统即可。

3、线程模型(Trheading model)

varnish的child进程由多种不同的线程组成,分别用于完成不同的工作。例如:

  cache-worker线程:每连接一个,用于处理请求;

  cache-main线程:全局只有一个,用于启动cache;

  ban lurker线程:一个,用于清理bans;

  acceptor线程:一个,用于接收新的连接请求;

  epoll/kqueue线程:数量可配置,默认为2,用于管理线程池;

  expire线程:一个,用于移除老化的内容;

  backend poll线程:每个后端服务器一个,用于检测后端服务器的健康状况;

在配置varnish时,一般只需为关注cache-worker线程,而且也只能配置其线程池的数量,而除此之外的其它均非可配置参数。与此同时,线程池的数量也只能在流量较大的场景下才需要增加,而且经验表明其多于2个对提升性能并无益处。

 

4、线程相关的参数(Threading parameters)

varnish为每个连接使用一个线程,因此,其worker线程的最大数决定了varnish的并发响应能力。下面是线程池相关的各参数及其配置:

thread_pool_add_delay     2 [milliseconds]

thread_pool_add_threshold    2 [requests]

thread_pool_fail_delay      200 [milliseconds]

thread_pool_max          500 [threads]

thread_pool_min           5 [threads]

thread_pool_purge_delay       1000 [milliseconds]

thread_pool_stack        65536 [bytes]

thread_pool_timeout         120 [seconds]

thread_pool_workspace      16384 [bytes]

thread_pools           2 [pools]

thread_stats_rate              10 [requests]

其中最关键的当属thread_pool_max和thread_pool_min,它们分别用于定义每个线程池中的最大线程数和最少线程数。因此,在某个时刻,至少有thread_pool_min*thread_pools个worker线程在运行,但至多不能超出thread_pool_max*thread_pools个。根据需要,这两个参数的数量可以进行调整,varnishstat命令的n_wrk_queued可以显示当前varnish的线程数量是否足够,如果队列中始终有不少的线程等待运行,则可以适当调大thread_pool_max参数的值。但一般建议每台varnish服务器上最多运行的worker线程数不要超出5000个。


当某连接请求到达时,varnish选择一个线程池负责处理此请求。而如果此线程池中的线程数量已经达到最大值,新的请求将会被放置于队列中或被直接丢弃。默认线程池的数量为2,这对最繁忙的varnish服务器来说也已经足够。

 

5、

 

九、Varnish的命令行工具

1、varnishadm命令

命令语法:varnishadm [-t timeout] [-S secret_file] [-T address:port] [-n name] [command [...]]

通过命令行的方式连接至varnishd进行管理操作的工具,指定要连接的varnish实例的方法有两种:

-n name —— 连接至名称为“name”的实例;

-T address:port —— 连接至指定套接字上的实例;

其运行模式有两种,当不在命令行中给出要执行的"command"时,其将进入交互式模式;否则,varnishadm将执行指定的"command"并退出。要查看本地启用的缓存,可使用如下命令进行。
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 storage.list

 

[root@node1 ~]# ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 00:0C:29:CC:FA:B8  
          inet addr:172.16.100.6  Bcast:172.16.100.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fecc:fab8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5341 errors:0 dropped:0 overruns:0 frame:0
          TX packets:718 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:459136 (448.3 KiB)  TX bytes:70155 (68.5 KiB)
          Interrupt:83 Base address:0x2080 

测试:通过windows的ie浏览器访问172.16.100.6,打开开发者工具;

ctrl+F5刷新页面,不使用缓存: