haproxy学习

haproxy:既是http协议的代理,又是tcp层的负载均衡器
  mode:http,tcp(https,mysql)
  客户端请求request于代理服务器,代理服务器封装成另外一个请求报文request真正的后端
  服务器,后端服务器响应代理服务器,代理服务器重新封装响应报文再传输给客户端
 
haproxy:只是http协议的反向代理,不提供缓存功能,但额外支持对tcp层对基于tcp通信的
  应用做LB负载均衡
 
haproxy:
  安装:yum install haproxy -y
  能够多进程模式下工作,默认启动一个进程,该参数为nbproc number
  启动haproxy:/etc/init.d/haproxy start
 
1、配置一个简单实例haproxy:

frontend webserver *:80         前端监听在80端口,前端名称为webserver
  default_backend web

#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
backend web                         后端服务器名称web
  balance roundrobin
  server web1 192.168.223.137:80 check
  server web2 192.168.223.146:80 check

当访问浏览器:http://192.168.223.136/,会根据roundrobin算法调度到后端服务器

配置haproxy日志:

1、将下面四行注释掉

  # Provides UDP syslog reception
  $ModLoad imudp
  $UDPServerRun 514

  # Provides TCP syslog reception
  $ModLoad imtcp
  $InputTCPServerRun 514

2、添加如下一行

local2.*                                                /var/log/haproxy.log

3、重启rsyslog服务:service rsyslog restart

当请求访问haproxy时,日志内容如下:

[root@node1 ~]# tail -f /var/log/haproxy.log
Aug 5 21:55:42 localhost haproxy[66553]: 192.168.223.1:56443 [05/Aug/2017:21:55:41.900] webserver web/web2 168/0/0/0/168 200 297 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Aug 5 21:55:42 localhost haproxy[66553]: 192.168.223.1:56443 [05/Aug/2017:21:55:42.068] webserver web/web1 158/0/0/1/159 200 260 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"

可以看出实际的客户端地址192.168.223.1,以及请求的前端服务器名称,后端服务器的信息

查看后端服务器信息:(后端由一个nginx,一个httpd提供服务)

nginx日志:

[root@wadeson html]# tail -f ../logs/access.log
192.168.223.136 "-" - - [05/Aug/2017:21:55:39 +0800] "GET / HTTP/1.1" "192.168.223.136" 200 30 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" "192.168.223.1"
192.168.223.136 "-" - - [05/Aug/2017:21:55:40 +0800] "GET / HTTP/1.1" "192.168.223.136" 200 30 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" "192.168.223.1"

而httpd日志:

[root@wadeson ~]# tail -f /var/log/httpd/access_log
192.168.223.136 - - [05/Aug/2017:21:55:38 +0800] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

看不见真实客户端的ip,如何获取真实ip呢?

在haproxy配置文件中默认定义了:option forwardfor       except 127.0.0.0/8

这个参数的含义:允许在发往服务器的请求首部中插入“X-Forwarded-For”,是haproxy请求发往后端服务器的过程,只需要在后端服务器的日志格式中添加这个首部就能获取到真实ip的值

nginx的日志格式:

log_format main '$remote_addr "$http_x_real_ip" - $remote_user [$time_local] "$request" "$http_host" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';   已经默认自带了这个首部,所以无需修改就可以看见

现在设置httpd的日志格式:

LogFormat "%h %{X-Forwarded-For}i %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined

CustomLog logs/access_log combined

在httpd的日志格式中添加该首部,然后调用格式名称,再次访问网站,刷新日志如下:

192.168.223.136 - - [05/Aug/2017:21:55:43 +0800] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.223.136 192.168.223.1 - - [05/Aug/2017:22:23:02 +0800] "GET / HTTP/1.1" 200 30 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

至此,nginx和httpd两个后端都能收到真实的客户端的ip

haproxy的算法:

balance:负载均衡的调度算法
  动态:权重可以动态调整
  静态:调整权重不会实时生效,只能重启服务才会生效
  roundrobin:轮询,基于权重轮询,动态权重调整,每个后端主机最多支持4128个连接
  static-rr:静态权重轮询,不支持动态调整权重,若调整需要重启,每个后端主机支持的数量没有上线
  leastconn:最少连接数,动态算法,新的连接请求被派发至具有最少连接数据的后端服务器
    在有着较长时间会话的场景中推荐使用,如ldap、sql等,不适应较短时间会话场景,如http等
  source:静态算法,将请求的源地址进行hash,除模取余的算法,除以服务器个数
    可以使同一个客户端ip的请求始终被派发至某特定的服务器(缺点就是如果其中某个服务器 宕机了或者增加了,那么除模取余将会改变,会话信息就不复存在)
    如果需要将静态改为动态,可以使用hash-type进行修改
  hash_type分为:
    map-based(除模取余-------静态算法)、consistent(一致性hash-----动态算法)
  uri:uri算法,对uri的左半部分或对整个uri进行hash,除模取余的算法,除以服务器个数(总权重),可以使用hash-type进行修改到底是静态算法还是动态算法
    除非服务器数量变化,客户端请求的uri就会被派发至同一个后端服务器
    具体配置如下:
      balance uri
      hash-type consistent
  url_param:根据url中的指定的参数的值进行调度,然后进行hash,可以实现类似会话绑定
  hdr(name):header,请求报文首部进行调度,如报文的user-agent浏览器进行调度
    把指定的header的值进行hash调度,可以使用hash-type进行修改到底是静态算法还是动态算法设置如:hdr(User-Agent)
1、现在将balance设置为source:

backend web
  balance source
  hash-type consistent
  server web1 192.168.223.137:80 check
  server web2 192.168.223.146:80 check

查看haproxy日志:

Aug 5 22:32:25 localhost haproxy[66820]: Proxy webserver started.
Aug 5 22:32:25 localhost haproxy[66820]: Proxy web started.
Aug 5 22:32:31 localhost haproxy[66821]: 192.168.223.1:57002 [05/Aug/2017:22:32:31.349] webserver web/web2 1/0/0/1/2 200 297 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Aug 5 22:32:31 localhost haproxy[66821]: 192.168.223.1:57002 [05/Aug/2017:22:32:31.351] webserver web/web2 198/0/0/1/199 304 149 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Aug 5 22:32:31 localhost haproxy[66821]: 192.168.223.1:57002 [05/Aug/2017:22:32:31.551] webserver web/web2 183/0/1/1/185 304 149 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

可以看出请求都被发往web2这台后端服务器了

2、uri的hash算法:

现在将两台web服务器都增加一个test.html文件:

echo "<h1>test 192.168.223.137</h1>" > test.html

echo "<h1>test 192.168.223.146</h1>" > test.html

修改haproxy配置文件:

backend web
  balance uri
  hash-type consistent
  server web1 192.168.223.137:80 check
  server web2 192.168.223.146:80 check

访问网站:http://192.168.223.136/test.html

查看haproxy日志:

Aug 5 22:36:44 localhost haproxy[66860]: Proxy webserver started.
Aug 5 22:36:44 localhost haproxy[66860]: Proxy web started.
Aug 5 22:36:55 localhost haproxy[66861]: 192.168.223.1:57065 [05/Aug/2017:22:36:55.365] webserver web/web1 0/0/0/0/0 200 260 - - ---- 1/1/0/0/0 0/0 "GET /test.html HTTP/1.1"
Aug 5 22:36:57 localhost haproxy[66861]: 192.168.223.1:57065 [05/Aug/2017:22:36:55.366] webserver web/web1 1903/0/0/1/1904 304 173 - - ---- 1/1/0/0/0 0/0 "GET /test.html HTTP/1.1"

可以看出请求test.html的uri都被请求到web1这台服务器了

3、hdr(name),基于header内容的hash算法

修改haproxy配置文件:

backend web
  balance hdr(User-Agent)
  hash-type consistent
  server web1 192.168.223.137:80 check
  server web2 192.168.223.146:80 check

查看haproxy日志:

Aug 5 22:43:00 localhost haproxy[66910]: Proxy webserver started.
Aug 5 22:43:00 localhost haproxy[66910]: Proxy web started.
Aug 5 22:43:15 localhost haproxy[66911]: 192.168.223.1:57124 [05/Aug/2017:22:43:15.826] webserver web/web2 0/0/0/1/1 304 149 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Aug 5 22:43:17 localhost haproxy[66911]: 192.168.223.1:57124 [05/Aug/2017:22:43:15.827] webserver web/web2 1916/0/0/0/1916 304 149 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"

请求都被派发到了web2,而web2的日志如下:

192.168.223.136 192.168.223.1 - - [05/Aug/2017:22:43:22 +0800] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.223.136 192.168.223.1 - - [05/Aug/2017:22:43:22 +0800] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

配置文件说明:

1、代理

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

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

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

    -listen:把一个前端和一个后端绑在一起,通过关联前端和后端定义了一个完整的代理,通常只对tcp流量有用

    所有代理的名称只能使用大写字母、小写字母、数字、-、_、点号、冒号,此外ACL名称会区分字母大小写

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

  在前端定义一个或多个地址或者端口

mode { tcp|http|health }

  实例运行的模式或者协议

log <address> [len <length>] <facility> [<level> [<minlevel>]]
  如果使用了log global那么将会延续全局定义,或者在实例中单独定义
maxconn <conns>
  设定前端能接收的最大连接数,客户端与haproxy之间有maxconn连接,而haproxy与后端服务器也有连接数
  在backend中可以单独配置haproxy与后端主机每个服务器之间的连接数
default_backend <backend>
  定义默认后端,当然还有use_backend
  use_backend dynamic if url_dyn
  use_backend static if url_css url_img extension_img
  default_backend dynamic
server <name> <address>[:[port]] [param*]
  check健康状态检测
    inter <delay>:间隔多久检测,单位ms,默认值2000ms
    rise <count>:从离线状态恢复到可用状态的次数检查,默认2次
    fall <count>:几次不成功的检查后,服务器变为不可用状态,默认3次
  option httpchk
 
  option httpchk <uri>
  option httpchk <method> <uri>
  option httpchk <method> <uri> <version>
 
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
  在backend中启用cookie的持久连接
  基于cookie绑定后端服务器:
    cookie SRV insert indirect nocache
  修改配置文件:

backend web
  balance roundrobin
  cookie SRV insert indirect nocache        在原有的cookie信息上insert上SRV:{web1_session|web2_session},实现cookie的绑定
  server web1 192.168.223.137:80 check cookie web1_session
  server web2 192.168.223.146:80 check cookie web2_session

Aug 5 23:38:17 localhost haproxy[67250]: Proxy webserver started.
Aug 5 23:38:17 localhost haproxy[67250]: Proxy web started.
Aug 5 23:38:22 localhost haproxy[67251]: 192.168.223.1:58602 [05/Aug/2017:23:38:22.923] webserver web/web1 0/0/1/0/1 200 260 - - --NI 1/1/0/0/0 0/0 "GET / HTTP/1.1"
Aug 5 23:38:23 localhost haproxy[67251]: 192.168.223.1:58602 [05/Aug/2017:23:38:22.924] webserver web/web1 558/0/1/0/559 304 173 - - --VN 1/1/0/1/0 0/0 "GET / HTTP/1.1"

1、每一个server都有自己的唯一的cookie标识
2、在backend中定义为用户请求调度完成后操纵其cookie
 
haproxy的状态监控页面:
 frontend webserver *:80
  default_backend web
listen base_stats
  bind *:8090        选择不常有的端口进行访问
  stats enable     启用stats状态功能
  stats hide-version      隐藏haproxy的版本,避免收到版本漏洞攻击
  stats uri /haproxy?stats       访问的uri
  stats realm "haproxy statistics"      认证时的提示,表示转义后面的空格
  stats auth wadeson:redhat       认证,账号和密码(auth可以用多次)
  stats refresh 5s         每隔5s重新刷新

Aug 6 13:25:55 localhost haproxy[67660]: 192.168.223.1:53986 [06/Aug/2017:13:25:50.539] base_stats base_stats/<STATS> 5014/0/0/0/5015 200 18268 - - LR-- 1/1/0/0/0 0/0 "GET /haproxy?stats HTTP/1.1"
Aug 6 13:25:55 localhost haproxy[67660]: 192.168.223.1:54110 [06/Aug/2017:13:25:55.577] base_stats base_stats/<NOSRV> 0/-1/-1/-1/0 503 212 - - SC-- 1/1/0/0/0 0/0 "GET /favicon.ico HTTP/1.1"

日志显示也是五秒刷新一条记录

如果要做到在该页面进行后端服务器的操作,那么可以加上stats admin if true这条指令:

frontend webserver *:80
  default_backend web
listen base_stats
  bind *:8090
  stats enable
  stats hide-version
  stats uri /haproxy?stats
  stats realm "haproxy statistics"
  stats auth wadeson:redhat
  stats admin if TRUE    如果认证通过就能管理节点server

capture request header <name> len <length>

  捕获请求首部,并指定首部长度

frontend webserver *:80
  default_backend web
  capture request header Host len 15

  capture request  header Referer len 60         ----》跳转---》防盗链

查看haproxy日志:

Aug 6 13:32:11 localhost haproxy[67789]: Proxy web started.
Aug 6 13:32:21 localhost haproxy[67790]: 192.168.223.1:54212 [06/Aug/2017:13:32:21.201] webserver web/web1 0/0/0/0/0 304 173 - - --VN 1/1/0/0/0 0/0 {192.168.223.136} "GET / HTTP/1.1"
Aug 6 13:32:21 localhost haproxy[67790]: 192.168.223.1:54212 [06/Aug/2017:13:32:21.201] webserver web/web1 694/0/1/0/695 304 173 - - --VN 1/1/0/0/0 0/0 {192.168.223.136} "GET / HTTP/1.1"

可以看出标红的就是捕获的请求首部host的具体内容,捕获的内容出现在日志以{}出现

capture response header <name> len <length>

  捕获响应首部,并指定长度

frontend webserver *:80
  default_backend web
  capture request header Host len 15
  capture request header X-Forwarded-For len 15
  capture response header Content-length len 9
  capture response header Location len 15

Aug 6 13:43:58 localhost haproxy[67911]: 192.168.223.1:54419 [06/Aug/2017:13:43:58.989] webserver web/web1 1/0/0/1/2 304 173 - - --VN 1/1/0/0/0 0/0 {192.168.223.136|} {|} "GET / HTTP/1.1"
Aug 6 13:43:59 localhost haproxy[67911]: 192.168.223.1:54419 [06/Aug/2017:13:43:58.991] webserver web/web1 782/0/0/0/782 304 173 - - --VN 1/1/0/0/0 0/0 {192.168.223.136|} {|} "GET / HTTP/1.1"

响应捕获的首部{}不存在使用|为分隔符出现在日志中

option httplog [ clf ]

  启用该参数,能够看见在日志中记录更多内容,当然你也可以设置log-format,支持更多内置变量,该参数默认是开启的

option logasap

  更早的记录请求到日志中

option      dontlognull  

  启用该项,日志中将不会记录空连接。所谓空连接就是在上游的负载均衡器或者监控系统为了探测该 服务是否存活可用时,需要定期的连接或者获取某一固定的组件或页面,或者探测扫描端口是否在监听  或开放等动作被称为空连接;官方文档中标注,如果该服务上游没有其他的负载均衡器的话,建议不要使用该参数,因为互联网上的恶意扫描或其他动作就不会被记录下来

全局配置段的一些参数:

  nbproc <number>:只有运行在守护模式下才能创建更多进程数,因为一个进程所处理的文件描述符的数量有限,haproxy也能工作在多进程条件下

  ulimit-n <number>:设置一个进程所能处理的最大的文件描述符的数量,it is automatically computed, so it is recommended not to use this option.,不建议更改

  maxconn <number>:

    设定前端能接收的最大连接数,客户端与haproxy之间有maxconn连接,而haproxy与后端服务器也有连接数
    在backend中可以单独配置haproxy与后端主机每个服务器之间的连接数
    如果没有设置该值,可以使用命令haproxy -vv查看haproxy的一些默认配

    [root@node1 haproxy]# haproxy -v

    HA-Proxy version 1.5.18 2016/05/10

    Copyright 2000-2016 Willy Tarreau <willy@haproxy.org

    Build options :

    TARGET = linux2628
    CPU = generic
    CC = gcc
    CFLAGS = -O2 -g -fno-strict-aliasing
    OPTIONS = USE_LINUX_TPROXY=1 USE_ZLIB=1 USE_REGPARM=1 USE_OPENSSL=1 USE_PCRE=1

    Default settings :
    maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200

    Encrypted password support via crypt(3): yes
    Built with zlib version : 1.2.3
    Compression algorithms supported : identity, deflate, gzip
    Built with OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013
    Running on OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013
    OpenSSL library supports TLS extensions : yes
    OpenSSL library supports SNI : yes
    OpenSSL library supports prefer-server-ciphers : yes
    Built with PCRE version : 7.8 2008-09-05
    PCRE library supports JIT : no (USE_PCRE_JIT not set)
    Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND

    Available polling systems :
    epoll : pref=300, test result OK
    poll : pref=200, test result OK
    select : pref=150, test result OK
    Total: 3 (3 usable), will use epoll.

ACL:访问控制列表
    acl <aclname> <criterrion> [flags][operator]<value>区分字符大小写
    flags:
	-i:不区分字符大小
    path_beg <string>:path路径以某字符串开始
    path_end <string>:path路径以什么结尾(文件名扩展名都可以)
    path_reg <regex>:支持正则
    url <string>:整个后面的路径
    method <string> 
    acl url_static path_beg /static /images /img /css:定义以/images /img /css为开头的url
    acl url_static path_end -i .gif .png .jpg .css .js:定义以它们结尾,不区分大小写
    acl host_www hdr_beg(host) -i www  :hdr_reg(header) <regex>:对首部host进行正则表达式
    use_backend static if url_static  :如果满足url_static控制列表定义的使用后端static组
    use_backend www if host_www   :如果满足host_www控制列表定义的使用后端www组
    default_backend web    :其他没有满足的使用web后端组

实例:动静分离

frontend webserver *:80
  default_backend web
  capture request header Host len 15
  capture request header X-Forwarded-For len 15
  capture response header Content-length len 9
  capture response header Location len 15
  capture response header Via len 15
  acl url_static path_beg -i /static /images /javascript /stylesheets /css          以path的url开头为条件
  acl url_static path_end -i .jpg .jpeg .gif .png .css .js .html .htm               以结尾为条件
  use_backend static_servers if url_static                当满足url_static定义的条件时就使用静态服务器
  default_backend dynamic_servers                     默认使用动态服务器
listen base_stats
  bind *:8090
  stats enable
  stats hide-version
  stats uri /haproxy?stats
  stats realm "haproxy statistics"
  stats auth wadeson:redhat
  stats admin if TRUE

backend static_servers
  balance roundrobin
  server web2 192.168.223.146:80 check maxconn 6000

backend dynamic_servers
  balance roundrobin
  cookie SRV insert indirect nocache

  server  web1  192.168.223.137:80  check cookie web1_session maxconn 1000

 参考另一篇:

  http://huangsir007.blog.51cto.com/6159353/1840877

  http://blog.csdn.net/wylfengyujiancheng/article/details/52336854

原文地址:https://www.cnblogs.com/jsonhc/p/7291986.html