介绍

Haproxy是开源的、高性能的基于TCP(四层),HTTP(七层)应用的负载均衡软件。

四层负载:

当负载均衡机器接收到来自客户端的请求时,会根据负载算法在后台web服务器中选择一台,并将报文中的目标IP转换为后台服务器IP,然后将请求转发给后台服务器,常见的负载均衡有LVS、F5等。

七层负载均衡:

七层负载均衡:也称为七层交换机,位于ISO最高层,即应用层。支持多种协议由HTTP、FTP、SMTP等。七层负载均衡器可以根据报文内容,再配合算法来选择后端服务器,因此也称为“内容交换器”,可以根据访问的URL、域名、浏览器类别等决定负载,这些是四层负载均衡无法做到的,常见的七层负载有,Haproxy、nginx等。
在七层负载均衡模式下,负载均衡与客户端及后端服务器分别建立一次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方式实现会话保持(可实现mysql或redis等的分布式服务)
SSL:     HAProxy可以解析HTTPS协议,并能够将请求解密为HTTP后向后端传输
HTTP请求重写与重定向
监控与统计:HAProxy提供了基于Web的统计信息页面,展现健康状态和流量数据。基于此功能,使用者可以开发监控程序来监控HAProxy的状态

HAProxy的关键特性

性能

采用单线程、事件驱动、非阻塞模型,减少上下文切换的消耗,能在1ms内处理数百个请求。并且每个会话只占用数KB的内存。
大量精细的性能优化,如O(1)复杂度的事件检查器、延迟更新技术、Single-buffereing、Zero-copy forwarding等等,这些技术使得HAProxy在中等负载下只占用极低的CPU资源。
HAProxy大量利用操作系统本身的功能特性,使得其在处理请求时能发挥极高的性能,通常情况下,HAProxy自身只占用15%的处理时间,剩余的85%都是在系统内核层完成的。
HAProxy作者在8年前(2009)年使用1.4版本进行了一次测试,单个HAProxy进程的处理能力突破了10万请求/秒,并轻松占满了10Gbps的网络带宽。

稳定性

作为建议以单进程模式运行的程序,HAProxy对稳定性的要求是十分严苛的。按照作者的说法,HAProxy在13年间从未出现过一个会导致其崩溃的BUG,HAProxy一旦成功启动,除非操作系统或硬件故障,否则就不会崩溃(我觉得可能多少还是有夸大的成分)。
在上文中提到过,HAProxy的大部分工作都是在操作系统内核完成的,所以HAProxy的稳定性主要依赖于操作系统,作者建议使用2.6或3.x的Linux内核,对sysctls参数进行精细的优化,并且确保主机有足够的内存。这样HAProxy就能够持续满负载稳定运行数年之久。

单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的。

安装:

sudo apt-get install haproxy

配置文件:

/etc/haproxy/haproxy.cfg

重启:

sudo service haproxy restart

负载均衡基本配置

###########全局配置#########
global
    log /dev/log    local0 #[日志输出配置,所有日志都记录在本机,通过local0输出]
    log /dev/log    local1 notice #定义haproxy 日志级别[error warringinfo debug]
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy #运行haproxy的用户
    group haproxy #运行haproxy的用户所在的组
    daemon #以后台形式运行harpoxy
    # nbproc 1 #设置进程数量
    maxconn 4096 #默认最大连接数,需考虑ulimit-n限制

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # Default ciphers to use on SSL-enabled listening sockets.
    # For more information, see ciphers(1SSL). This list is from:
    #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
    ssl-default-bind-options no-sslv3

    #pidfile /var/run/haproxy.pid #haproxy 进程PID文件
   #ulimit-n 819200 #ulimit 的数量限制
   #chroot /usr/share/haproxy #chroot运行路径
   #debug #haproxy 调试级别,建议只在开启单进程的时候调试

########默认配置############
defaults
        log    global
        mode    http #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK
        option    httplog #日志类别,采用httplog
        option    dontlognull #不记录健康检查日志信息
        timeout connect 5000 #连接超时 ms
        timeout client  500000 #客户端超时
        timeout server  500000 #服务器超时

        ########设置haproxy 错误页面#####
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

        retries 2 #两次连接失败就认为是服务器不可用,也可以通过后面设置
      # option forwardfor #如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip
      # option httpclose #每次请求完毕后主动关闭http通道,haproxy不支持keep-alive,只能模拟这种模式的实现
      # option redispatch #当serverId对应的服务器挂掉后,强制定向到其他健康的服务器,以后将不支持
      # option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接
       # timeout check 2000 #心跳检测超时
      # timeout http-keep-alive10s #默认持久连接超时时间
      # timeout http-request 10s #默认http请求超时时间
      # timeout queue 1m #默认队列超时时间
      # balance roundrobin #设置默认负载均衡方式,轮询方式
      # balance source #设置默认负载均衡方式,类似于nginx的ip_hash
      # balnace leastconn #设置默认负载均衡方式,最小连接数

########web统计页面配置,可通过web页面展示haproxy运行状态########
listen admin_stats  
        bind 0.0.0.0:19892 #监听端口  
        mode http #http的7层模式
        option httplog #采用http日志格式  
        stats refresh 30s #统计页面自动刷新时间  
        stats uri /proxystatus #统计页面url  
        stats realm Haproxy Manager #统计页面密码框上提示文本
        stats auth admin:admin #设置监控页面的用户和密码:admin,可以设置多个用户名
       stats auth Frank:Frank #设置监控页面的用户和密码:Frank  
        stats auth admin:passwdod #统计页面用户名和密码设置  
        #stats hide-version #隐藏统计页面上HAProxy的版本信息

frontend minerproxy
        mode    tcp
        bind 0.0.0.0:8080
        #acl web hdr(host) -i www.abc.com  #acl后面是规则名称,-i为忽略大小写,后面跟的是要访问的域名,如果访问www.abc.com这个域名,就触发web规则,。
       #acl img hdr(host) -i img.abc.com  #如果访问img.abc.com这个域名,就触发img规则。
       #use_backend webserver if web   #如果上面定义的web规则被触发,即访问www.abc.com,就将请求分发到webserver这个作用域。
       #use_backend imgserver if img   #如果上面定义的img规则被触发,即访问img.abc.com,就将请求分发到imgserver这个作用域。
       default_backend minexmrproxy #不满足则响应minexmrproxy的默认页面

backend minexmrproxy
        mode    tcp
        server srv1 47.75.53.25:8080 maxconn 2048

########frontend前端配置##############
frontend xmr_pool_proxy
        mode    tcp
        option tcplog
        bind 0.0.0.0:7777
        default_backend supportxmr

########backend后端配置##############
backend supportxmr
        mode    tcp
        option tcplog #采用tcp日志格式 
        balance roundrobin # 负载均衡算法
        #check inter 1000ms 是检测心跳频率 
       #rise 2是2次正确认为服务器可用,fall 3是3次失败认为服务器不可用,weight代表权重
        server srv1 hk02.supportxmr.com:7777 maxconn 20480 weight 100 check inter 1000ms rise 2 fall 3
        server srv2 sg2.supportxmr.com:7777 maxconn 20480 weight 1 check inter 1000ms rise 2 fall 3
        server srv3 pool.supportxmr.com:7777 maxconn 20480 weight 100 check inter 1000ms rise 2 fall 3

负载均衡算法

roundrobin

表示简单的轮询,每个服务器根据权重轮流使用,在服务器的处理时间平均分配的情况下这是最流畅和公平的算法。该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。

static-rr

表示根据权重,建议关注;每个服务器根据权重轮流使用,类似roundrobin,但它是静态的,意味着运行时修改权限是无效的。另外,它对服务器的数量没有限制。

leastconn

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

source

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

uri

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

url_param

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

hdr(name)

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

rdp-cookie(name)

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

其实这些算法各有各的用法,我们平时应用得比较多的应该是roundrobin、source和lestconn。

ACL规则定义

ACL策略定义

1. #如果请求的域名满足正则表达式返回true -i是忽略大小写
acl denali_policy hdr_reg(host) -i ^(www.inbank.com|image.inbank.com)$

2、#如果请求域名满足www.inbank.com 返回 true -i是忽略大小写
acl tm_policy hdr_dom(host) -i www.inbank.com

3、#在请求url中包含sip_apiname=,则此控制策略返回true,否则为false
acl invalid_req url_sub -i sip_apiname=#定义一个名为invalid_req的策略

4、#在请求url中存在timetask作为部分地址路径,则此控制策略返回true,否则返回false
acl timetask_req url_dir -i timetask

5、#当请求的header中Content-length等于0时返回 true
acl missing_cl hdr_cnt(Content-length) eq 0

acl策略匹配相应

1、#当请求中header中Content-length等于0 阻止请求返回403
block if missing_cl

2、#block表示阻止请求,返回403错误,当前表示如果不满足策略invalid_req,或者满足策略timetask_req,则阻止请求。
block if !invalid_req || timetask_req

3、#当满足denali_policy的策略时使用denali_server的backend
use_backend denali_server if denali_policy

4、#当满足tm_policy的策略时使用tm_server的backend
use_backend tm_server if tm_policy

5、#reqisetbe关键字定义,根据定义的关键字选择backend
reqisetbe ^Host:\ img dynamic
reqisetbe ^[^\ ]*\ /(img|css)/ dynamic
reqisetbe ^[^\ ]*\ /admin/stats stats

6、#以上都不满足的时候使用默认mms_server的backend
default_backend mms_server

ACL 基本定义语法

·acl 名称 acl标准 [标志位][操作]

·acl 区分大小写

通常参数都是 -i

值的类型

e.g 1024:65535

比较操作

eg ge gt le lt

字符串

常用参数 -i

常用的匹配标准:

dst 目标地址

dst_port 目标端口

src 源地址

src_prot 源端口

acl goodguys src ip/24 如果是goodguys则允许访问

tcp-request content accept if goodguys 如果是goodguys则允许发起连接请求

tcp-request content reject 没有if语句 则拒绝所有(reject)

定义ACL实例

我们期望用户访问的时候如果来源地址是10.0.10.1则拒绝访问


frontend web_server

  bind*:80

  default_backendwebservers

  acl badguy src 10.0.10.1

  block if badguy

如果想访问403页面重定向到其他页面的话,则:

frontend web_server
bind *:80

default_backend webserver

acl badguy src 10.0.10.1
block if badguy
errorloc 403 http://baidu.com/ #定义错误页面重定向

method 访问方法匹配(GET或POST等),实现简单动静分离功能

acl read method GET

acl read method HEAD

acl write method PUT

acl write method POST

use_backend imgserif read

use_backend uploadif write

基于path http路径做访问控制

来自某个ip的主机访问的是1.html 则拒绝访问,其他全部放行,则:

首先定义acl 名称denyfile 根据path来做访问控制,而path一定跟的是具体访问路径

http-reques 来做规则 如果是badguy 并且访问的是denyfile 如果匹配两者则deny掉

frontend web_server
bind *:80
default_backend webserver
acl badguy src 10.0.10.1
acl denyfile path/1.html
http-request deny if badguy denyfile

实现动静分离功能

首先定义两个backend,分别以动态和静态进行分组

backend jingtai
    balance roundrobin
    server web1 10.0.10.82:80 check weight 1maxconn 2000
backend dongtai
    balance roundrobin
    server web2 10.0.10.83:80 check weight 1maxconn 3000

配置frontend

frontend web_server

bind *:80

default_backend webservers

acl badguy src 10.0.10.1

acl denyfile path /1.html

#http-request deny if badguy denyfile



acl static path_end .html

use_backend jingtai if static

default_backend dongtai

实现完全动静分离

acl static path_end -i .html .jpg .png.jpeg .gif .swf .css .xml .txt .pdf

use_backend jingtai if static

default_backend dongtai

正在表达式匹配 path_reg

acl url_static path_reg -i .jpg$ .html$ 等 ^/static ^/images^/stylsheets

基于正则表达式匹配要比基于字符匹配慢很多,所以如果可以写成字符匹配就尽可能使用 path_end path_end 而不要使用path_reg

url

之前我们在用path做匹配的时候发现,path不包含头部信息,而url全部包含

做url匹配要做整个路径匹配,但事实上用的最多的是path 而不是url,以为用户访问文件的时候,可能是这样访问:

http://xxx.com/login.php?name=test&password=xxxx

很显然login.php 才是访问的文件,而根据整个路径结尾进行判断的话则不能判断其类型的,所以更多用到的是path_end ,因为path_end顶多只能匹配到login.php

而不包含后面的内容

url_beg

url开头

url_end

url结尾

有些时候我们用url做匹配的时候可能会使用多条进行组合起来

比如:

如果badguy 访问的是除了denyfile之外的其他文件,则将被拒绝

http-request denyif badguy !denyfile

如果badguy 或其他人 访问的是除了denyfile之外的其他文件,则将被拒绝

http-request denyif badguy OR denyfile

健康状态检查机制

monitor-uri

通过web组件实现监控的,明确指定监控哪个uri而不是内部监控机制(check)

frontend www

bind :80

monitor-uri /haproxy

意思为做状态监测必须去请求这个uri的页面,能请求到并且状态为200则认为正常的

httpchk

做服务器的健康状态监测的时候明确说明http协议,可以指定检查那个uri,还可以指定那种方式检查uri,只启用就明确说明只做uri监测 而后面的监测方法全部省略了

backend https_relay
    mode tcp
    option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www
    server apache1 192.168.1.1:443 check port 80

也就意味着我们做健康检测的时候,是发送自定义信息去check

也就是说httpchk是发送的自定义的方法以及发送的请求报文格式的,只有发送的请求返回值是200,才认为正常否则失败的

http请求格式:

将OPTIONS *HTTP/1.1\r\nHost:\ www 转换成标准格式,如下所示:

OPTIONS * HTTP/1.1

Host: www

定义对mysql进行检测

option mysqlchk user mysqlusername

使用option参数套mysqlchk插件以mysqlusername的名称去连接mysql,只要能连接上,则认为数据库正常,否则不允许连接

对mysql读集群做负载均衡

只是对于读请求可以做负载均衡,如果对于写做负载均衡的时候直接这样调度是不合适的

frontend mysqlservers
bind *:3306
default_backend myservs

backend myservs
balance leastconn
option mysqlchk user root
server myserv1 172.16.100.11:3306 check
server myserv2 172.16.100.12:3306 check

haproxy实现持久连接方式

1 调度算法source

haroxy 将用户IP经过hash计算后 指定到固定的真实服务器上(类似于nginx 的IP hash 指令)

配置指令        balance source

2 cookie 识别  

haproxy 将WEB服务端发送给客户端的cookie中插入(或添加加前缀)haproxy定义的后端的服务器COOKIE ID。

配置指令例举  cookie  SESSION_COOKIE  insert indirect nocache

3 session 识别  

haproxy 将后端服务器产生的session和后端服务器标识存在haproxy中的一张表里。客户端请求时先查询这张表。然后根据session分配后端server。

配置指令:appsession <cookie> len <length> timeout <holdtime>

HAProxy的监控页面

每项资源的监控参数以表格形式呈现给用户,并将监控参划分为七个类别,即 Queue、Session rate、Sessions、Bytes、Denied、Errors、 Warning、server,每组参数类别下又有多个详细参数,其中各个参数的解释如下。

(1)Queue
  cur:表示当前队列的请求数量。
  Max:表是当前队列最大的请求数量。
  Limit:表示队列的限制数量。

(2) Session rate
  Cur:每秒会话连接数量。
  Max:每秒会话数量最大值。囗 Limit:每秒会话数量的限制值。

(3) Sessions
  Total:总共会话数量。
  Cur:当前的会话数量。
  Max:最大会话数量。
  Limit;会话连接限制。
  Lbtot:选中一台服务器所用的总时间。
  Last:最后一次会话时间。

(4) Bytes
  In:网络会话输人字节数总量。
  Out:网络会话输出字节数总量。

(5) Denied
  Req:被拒绝的会话请求数量。
  Resp:拒绝回应的请求数量。

(6) Errors
  Req:错误的请求数量。
  Conn:错误连接数量。
  Resp:错误响应数量。

(7) Warnings
   Retr:重新尝试连接的请求数量。
   Redis:重新发送的请求数量。

(8) Server
  status:后端服务器状态,可以有 UP和 DOWN两种状状态。
  LastChk:持续检查后端服务器的时间。
  Wght:服务器权重。
  Act:活动后端服务器数量。
  Bck:后端备份服务器的数量。
  Down:状态为 Down的后端服务器数量。
  Downtime:服务器总的 Downtime时间。
  Throttle:状态 Backup变为 Active的服务器数量。