首页 > 代码库 > haproxy 实现集群

haproxy 实现集群

实验环境,

haproxy  bridge eth0 172.16.26.6    VMnet2 eth1 192.168.1.11

httpd node1 VMnet2 eth0 192.168.1.21

httpd node2 VMnet2 eth0 192.168.1.22

192.168.1.21  192.168.1.22 两个节点都装上 httpd服务

192.168.1.21  index.html主页内容

httpd node1 192.168.1.21

192.168.1.22  主页内容

httpd node2 192.168.1.22

clipboard

haproxy的配置:

  [global settings]: 全局配置段

   主要用于定义haproxy进程自身的工作特性;

  [proxies[: 代理配置段

       backend: 后端服务器组

       frontend: 定义面向客户端的监听的地址和端口,以及关联到的后端服务器组;

        [一般是frontend调用backend]

       listen: 组合方式直接定义frontend及相关的backend的一种机制;

       defaults: 定义默认配置; =>不管哪种机制,都需要用到某些通用的配置,可以在defaults中定义

spread-checks  50, ==>[这个数值是%比,如果是每隔3秒检查一次,那么,会分散到前1.5秒或后1.5秒检查,可以防止服务器突然压力过大]

下面开启配置haproxy 的日志信息

** /etc/haproxy/haproxy.cfg =>配置haproxy的工作机制

log 127.0.0.1 local2    ==>配置文件中定义了本机的日志记录在 local2上

切记这仅仅是定义具体实现在/etc/rsyslog.conf

**/etc/rsyslog.conf

要让haproxy记录系统日志 要确保/etc/rsyslog.conf 中的

$InputTCPServerRun 514 这一行开启,让其监听在 TCP的514端口上

local2.* /var/log/haproxy.log    =>在/etc/rsyslog.conf 中添加这一项,记录 local2的所有级别的日志

配置好/etc/rsyslog.conf后 重启系统日志服务

service rsyslog restart  

[root@php5_6 ~]# ss -tnl  =>检查, 系统tcp514端口已启动,能记录系统日志了
LISTEN 0 25 :::514 :::* 
LISTEN 0 25 *:514 *:*

我们来了解一下,配置文件中的原有配置示例

frontend main *:5000    ==>前端定义了一个main的方法

    acl url_static path_beg -i /static /images /javascript /stylesheets   定义usr_static 的目录法则

    acl url_static path_end -i .jpg .gif .png .css .js                                    定义usr_static 的后缀法则

    use_backend static if url_static        =>如果满足条件则转发到一个名叫 static 的backend上,

    default_backend app                        否则默认发送到一个叫app的backend上

backend static

balance roundrobin    =>轮询方式

    server static 127.0.0.1:4331 check

backend app                =>此处定义了app中,接受分发请求的主机ip地址

    balance roundrobin    =>轮询方式

    server app1 127.0.0.1:5001 check   

    server app2 127.0.0.1:5002 check

    server app3 127.0.0.1:5003 check

    server app4 127.0.0.1:5004 check

有了以上的知识和概念,我们可以依照博文开头处的实验环境,配置haproxy的分发机制了

设定frontend 为main 的所有ip都监听在80端口

frontend main *:80 

    default_backend app    =>所有来的请求,一律交由 app 处理

backend app    定义backend 为app

    balance roundrobin    =>以轮询方式工作

    server app 192.168.1.21    =>里面拥有两个可分发的主机

    server app 192.168.1.22

重启服务 service haproxy restart

测试

clipboard[1]

clipboard[2]

已轮询成功

上面是haproxy 的基本用法, haproxy还有许多可定制的参数,如下

用绑定端口的方法,指定绑定要监听的端口

bind :80,443     ==>一般用在frontend中, 如果要指定多个监听端口的话,可以用" , " 分隔开

haproxy的轮询配置参数

balance  =>一般用在backend中, 有各种轮询的方法 以下是各方法的详解

roundrobin:基于权重进行轮叫,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,这表示其权重可以在运行时进行调整,不过,在设计上,每个后端服务器仅能最多接受4128个连接;

static-rr:基于权重进行轮叫,与roundrobin类似,但是为静态方法,在运行时调整其服务器权重不会生效;不过,其在后端服务器连接数上没有限制;

leastconn:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重,支持慢启动; 短连接就不建议用了

source:将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议;其默认为静态,不过也可以使用hash-type修改此特性; 

建议用于tcp模式使用, 因为http模式,还有更高级的算法

相当于ipvs的sh算法, nginx的ip_hash算法

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修改此特性;

use_domain_only =>意思是只hash域名, 如

www.mageedu.com

mail.mageedu.com

ftp.mageedu.com        都只hash , mageedu.com

        rdp-cookie
        rdp-cookie(name):

frontend main

    bind :80    ==>如果要指定多个监听端口的话,可以用" , " 分隔开

    default_backend app    =>所有来的请求,一律交由 app 处理

backend app    定义backend 为app

    balance roundrobin    =>以轮询方式工作

    server app 192.168.1.21    =>里面拥有两个可分发的主机

    server app 192.168.1.22

tune.maxaccept <number> 一批接受的最大请求数,默认单线程为100个,多线程为8个

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

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

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

“listen”整合frontend,backend 定义了一个完整的代理,通常只对TCP流量有用。

另附 haproxy的其它参数

1.1 cookie  cookie_name

     rewrite    =>重写

    insert         =>插入

    prefix        =>作为前缀

    indirect

    nocache    =>不缓存敏感信息

    postonly   

    preserve

    httponly

    secure

    domain <domain>   

    maxidle <idle>

    maxlife <life>   

基本cookie的session绑定实现

backend webapp

balance roundrobin

cookie webappck insert nocache     =>此处加上cookie参数 insert 插入方式写入cookie,并且不保存用户的敏感信息

server app1 192.168.1.21 cookie app1    并且标识cookie名

server app2 192.168.1.22 cookie app2

clipboard[3]

打开chrome的调试器,可以看到, Set-Cookie:webappck=app2;   说明基于cookie的sesssion绑定已实现

1.2 mode

HAProxy有两种工作模式;     即调度时发生的协议层次 . 两种工作模式所能提供的功能是各不相同的, tcp只能以简单模式工作.

  http:仅用于调度http协议的服务器

   会对应用层数据做深入分析,因此支持7层过滤、处理、转换等机制

  tcp:非http协议的服务器调度,包括https

   默认模式,不会对应用层协议做任何检查;

   通过在客户端和backend server之间建立一个全双工的连接   =>

hash-type <method>

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

map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。

consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。

当所有的后端轮询主机都不可用时,又不希望用户看到不友好的错误信息,我们还可以设定一个sorryserver

只需要在要轮询的主机列表后,加一个主机ip, 并指明是backup属性即可

backend webapp

    balance roundrobin

    cookie webappck insert nocache

    server app1 192.168.1.21 cookie app1 check port 80  =>都检查节点的健康状态 必须检查端口,因为下面的backup server监听的是非80端口

    server app2 192.168.1.22 cookie app2 check port 80 

server sorry1 127.0.0.1:8080   backup     =>因为haproxy已经监听在80端口上了,所以改不同的端口

保存配置文件, 重启 haproxy 服务

service haproxy restart

clipboard[4]

backup server 已然工作

1.4

我们还可以加最大连接请求限制

frontend main

    bind :80

maxconn 6000        =>    最大连接请求限制为6000个

    default_backend webapp

backend webapp

    balance roundrobin

    cookie webappck insert nocache

    server app1 192.168.1.21 cookie app1 check port 80 maxconn 4000 weight 2    可以自行安排, 如 app1性能好,可以多安排些,权重也可以设置高一些

    server app2 192.168.1.22 cookie app2 check port 80 maxconn 2000 weight 1

    server s1 127.0.0.1:8080 backup

附check  有很多种, 还有mysql-check , http-check等方法

option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www.robert.com  指明用httpchk检查

1.5 启动haproxy 状态页

backend webapp

    balance roundrobin

    cookie webappck insert nocache

    server app1 192.168.1.21 cookie app1 check port 80 maxconn 4000 weight 2

stats enable        =>在任一server后面 添加 stats enable

=>当然这些页面不是希望所有人都能看到的,要有验证机制

    stats hide-version       =>隐藏版本                

    stats scope     .         =>表示作用范围 仅为当前页面

    stats uri /haproxyadmin?stats    =>自定义状态页地址

    stats realm Haproxy\ Statistics    配合 用户名和口令做认证

    stats auth statsadmin:abcd1234    =>定义认证信息和口令

    stats admin if TRUE                =>开启管理功能 [如果认证通过的话] 如果希望 statsmaster也有这功能得在它后面的那行也加这一行内容

    stats auth statsmaster:1234abcd

    server app2 192.168.1.22 cookie app2 check port 80 maxconn 2000 weight 1

    server s1 127.0.0.1:8080 backup

访问上述定义的地址,输入正确的用户名和口令即可访问

clipboard[5]

clipboard[6]

还有一种定义的方法  这种方法相对安全,但是可以提供的功能也少很多,看生产环境取舍吧

listen statss

    bind:2009   =>指定监听的端口

stats enable        =>在任一server后面 添加 stats enable

=>当然这些页面不是希望所有人都能看到的,要有验证机制

    stats hide-version       =>隐藏版本                

    stats scope     .         =>表示作用范围 仅为当前页面

    stats uri /haproxyadmin?stats    =>自定义状态页地址

    stats realm Haproxy\ Statistics    配合 用户名和口令做认证

    stats auth statsadmin:abcd1234    =>定义认证信息和口令

    stats admin if TRUE                =>开启管理功能 [如果认证通过的话] 如果希望 statsmaster也有这功能得在它后面的那行也加这一行内容

    stats auth statsmaster:1234abcd 

实现动静分离

frontend main *:80

    acl url_static path_beg -i /static /images /javascript /stylesheets  定义为静态资源的目录

    acl url_static path_end -i .jpg .gif .png .css .js .html    定义为静态资源的后缀

    use_backend static if url_static    =>如果满足静态资源特征,则分发到定义的 static 的backend

    maxconn 6000

    default_backend webapp

backend static

    balance roundrobin

    server static 192.168.1.21    =>定义静态资源主机ip

配置完成重启haproxy服务

#service haproxy restart

在两个节点的根目录下,都创建一个 images的目录,里面写入一个test.html的文件

节点1的内容为21test.html

节点2的内容为22test.html

clipboard[7]

从结果得知,很明显的,haproxy将其分发到 192.168.1.21的节点上了

如果遭到攻击了,怎么办呢?

backend dynamic

        mode http

        acl being_scanned be_sess_rate gt 50 =>如果每秒发起讲求超过50个,那么就认为遭到攻击了

        redirect location /error_pages/denied.html if being_scanned    =>将其引导到另一个显示页面

        tcp-request inspect-delay 50ms        => 如果不想使用上面的直接将其粗暴的引导到另一个显示内容 可以让请求在后边等待

        tcp-request content accept if ! too_fast     =>如果请求速率没超过,允许接入

        tcp-request content accept if WAIT_END    =>等待完成,可以接入

还可以基于请求的url头部来做分发条件,如 

  acl http url_beg http://

  acl https url_beg https://

   use_backend backend_http if http=>如果url满足http://开头则分发到定义的backend_http 

   use_backend backend_https if https=>如果url满足http://开头则分发到定义的 backend_https

haproxy 实现集群