摘要:
- HAproxy的介绍安装及使用
- 配置文件的说明及用法
- ACL的配置文件选项说明
- 常用用法及实验
HAProxy
- 官网:
- 官方文档:
http://cbonte.github.io/haproxy-dconv/
- HAProxy简介:
HAProxy is a TCP/HTTP reverse proxy which is particularly suited
: for high availability environments. Indeed, it can:
: - route HTTP requests depending on statically assigned cookies
: - spread load among several servers while assuring server
: persistence through the use of HTTP cookies
: - switch to backup servers in the event a main server fails
: - accept connections to special ports dedicated to service monitoring
: - stop accepting connections without breaking existing ones
: - add, modify, and delete HTTP headers in both directions
: - block requests matching particular patterns
: - report detailed status to authenticated users from a URI
: intercepted by the application
- 反向代理的集群环境
七层反代:
nginx(http, ngx_http_upstream_module), haproxy(mode http), httpd, ats, perlbal, pound...
ssl/tls 会话卸载器
四层反代:
lvs, nginx(stream),haproxy(mode tcp)
数据分布:
结构化数据:mysql,50-100次/s
半结构化数据:mangodb,redis,50-100万次/s
非结构化数据:分布式存储系统
- 调度器
众多调度算法
事件驱动模型,单进程模型处理多应用请求
最好使用单线程
- 安装
$ yum install -y haproxy
$ rpm -ql haproxy
/etc/haproxy/haproxy.cfg #主配置文件
/etc/logrotate.d/haproxy
/etc/sysconfig/haproxy #Uint file配置文件
/usr/bin/halog
/usr/bin/iprange
/usr/lib/systemd/system/haproxy.service #Uint file
/usr/sbin/haproxy #主程序
Haproxy配置说明
配置文件:官网配置
- global全局配置段
配置段内容:
进程及安全配置相关的参数
性能调整相关参数
Debug参数
用户列表
peers
配置参数
进程及安全管理:chroot, daemon,user, group, uid, gid
log:定义全局的syslog服务器;最多可以定义两个;
log <address> [len <length>] <facility> [max level [min level]]
nbproc <number>:要启动的haproxy的进程数量;
ulimit-n <number>:每个haproxy进程可打开的最大文件数;
- 性能配置
maxconn <number>:设定每个haproxy进程所能接受的最大并发连接数;
Sets the maximum per-process number of concurrent connections to <number>.
总体的并发连接数:nbproc * maxconn
maxconnrate <number>:每个进程每秒种所能创建的最大连接数量;
Sets the maximum per-process number of connections per second to <number>.
maxsessrate <number>:
maxsslconn <number>: 设定每个haproxy进程所能接受的ssl的最大并发连接数;
Sets the maximum per-process number of concurrent SSL connections to <number>.
spread-checks <0..50, in percent>
- 代理配置段
defaults:为frontend, listen, backend提供默认配置;
fronted:前端,相当于nginx, server {}
backend:后端,相当于nginx, upstream {}
listen:同时拥前端和后端
- 代理配置端解释
A “frontend” section describes a set of listening sockets accepting client connections.
A “backend” section describes a set of servers to which the proxy will connect to forward incoming connections.
A “listen” section defines a complete proxy with its frontend and backend parts combined in one section. It is generally useful for TCP-only traffic.
All proxy names must be formed from upper and lower case letters, digits, ‘-’ (dash), ‘_’ (underscore) , ‘.’ (dot) and ‘:’ (colon). 区分字符大小写;
- 简单配置示例
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance roundrobin
server srv1 192.168.1.20:80 check
server srv2 192.168.1.13:80 check
代理参数说明
- bind
bind:Define one or several listening addresses and/or ports in a frontend.
bind [<address>]:<port_range> [, ...] [param*]
listen http_proxy
bind :80,:443
bind 10.0.0.1:10080,10.0.0.1:10443
bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy
- balance
balance:后端服务器组内的服务器调度算法
balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post]
算法:
roundrobin:Each server is used in turns, according to their weights.
server options: weight #
动态算法:支持权重的运行时调整,支持慢启动;每个后端中最多支持4095个server;
static-rr:
静态算法:不支持权重的运行时调整及慢启动;后端主机数量无上限;
leastconn:
推荐使用在具有较长会话的场景中,例如MySQL、LDAP等;
first:
根据服务器在列表中的位置,自上而下进行调度;
前面服务器的连接数达到上限,新请求才会分配给下一台服务;
source:源地址hash;
除权取余法:
一致性哈希:
uri:
对URI的左半部分做hash计算,并由服务器总权重相除以后派发至某挑出的服务器;
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分:/<path>;<params>
整个uri:/<path>;<params>?<query>#<frag>
username=jerry
url_param:
对用户请求的uri的<params>部分中的参数的值作hash计算;
并由服务器总权重相除以后派发至某挑出的服务器;
通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server;
hdr(<name>):
对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算;
并由服务器总权重相除以后派发至某挑出的服务器;没有有效值的会被轮询调度;
hdr(Cookie)
rdp-cookie
rdp-cookie(<name>)
- log
log <address> [len <length>] <facility> [max level [min level]]
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
log 127.0.0.1 local2
[root@haproxy ~]# systemctl restart haproxy
[root@haproxy ~]# vim /etc/rsyslog.conf
#### MODULES ####
$ModLoad imudp
$UDPServerRun 514
#### RULES ####
# Save haproxy log to haproxy.log
local2.* /var/log/haproxy.log
[root@haproxy ~]# systemctl restart rsyslog
- hash-type
hash-type:哈希算法
hash-type <method> <function> <modifier>
map-based:除权取余法,哈希数据结构是静态的数组;
consistent:一致性哈希,哈希数据结构是一个树;
<function> is the hash function to be used : 哈希函数
sdbm
djb2
wt6
- server
server <name> <address>[:[port]] [param*]
定义后端主机的各服务器及其选项;
server <name> <address>[:port] [settings ...]
default-server [settings ...]
<name>:服务器在haproxy上的内部名称;出现在日志及警告信息中;
<address>:服务器地址,支持使用主机名;
[:[port]]:端口映射;省略时,表示同bind中绑定的端口;
[param*]:参数
maxconn <maxconn>:当前server的最大并发连接数;
backlog <backlog>:当前server的连接数达到上限后的后援队列长度;
backup:设定当前server为备用服务器;
check:对当前server做健康状态检测;
addr :检测时使用的IP地址;
port :针对此端口进行检测;
inter <delay>:连续两次检测之间的时间间隔,默认为2000ms;
rise <count>:连续多少次检测结果为“成功”才标记服务器为可用;默认为2;
fall <count>:连续多少次检测结果为“失败”才标记服务器为不可用;默认为3;
注意:option httpchk,"smtpchk", "mysql-check", "pgsql-check" and "ssl-hello-chk" 用于定义应用层检测方法;
cookie <value>:为当前server指定其cookie值,用于实现基于cookie的会话黏性;
disabled:标记为不可用;
on-error <mode>:后端服务故障时的行动策略;
- fastinter: force fastinter
- fail-check: simulate a failed check, also forces fastinter (default)
- sudden-death: simulate a pre-fatal failed health check, one more failed
check will mark a server down, forces fastinter
- mark-down: mark the server immediately down and force fastinter
redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL;
weight <weight>:权重,默认为1;
- option httpchk
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
#用于定义应用层检测方法
http-check expect [!] <match> <pattern>
- 修改报文头部
reqadd <string> [{if | unless} <cond>] 在HTTP请求的末尾添加标头
rspadd <string> [{if | unless} <cond>] 在HTTP响应的末尾添加标头
reqdel <search> [{if | unless} <cond>] 删除与HTTP请求中的正则表达式匹配的所有标头
reqidel <search> [{if | unless} <cond>] (ignore case)
rspdel <search> [{if | unless} <cond>] 删除与HTTP响应中的正则表达式匹配的所有标头
rspidel <search> [{if | unless} <cond>] (ignore case)
#删除响应报文中的Server字段信息
rspidel Server.*
-
errorfile 和 errorloc
errorfile <code> <file>
errorloc <code> <url>
errorloc302 <code> <url>
#code:HTTP状态代码。 目前HAProxy能够支持的代码:
200, 400, 403, 408, 500, 502, 503, and 504
#file:指定包含完整HTTP响应的文件
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 408 /dev/null #解决方法Chrome预连接错误
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
- 统计接口
统计接口启用相关的参数:
stats enable
启用统计页;基于默认的参数启用stats page;
- stats uri : /haproxy?stats
- stats realm : "HAProxy Statistics"
- stats auth : no authentication
- stats scope : no restriction
stats auth <user>:<passwd>
认证时的账号和密码,可使用多次;
stats realm <realm>
认证时的realm;
stats uri <prefix>
自定义stats page uri
stats refresh <delay>
设定自动刷新时间间隔;
stats admin { if | unless } <cond>
启用stats page中的管理功能
配置示例:
listen stats
bind :9099
stats enable
stats realm HAPorxy\ Stats\ Page
stats auth admin:admin
stats admin if TRUE
ACL
访问控制列表的使用提供了一种灵活的解决方案来执行内容切换,并且通常基于从请求,响应或任何环境状态中提取的内容来做出决策
acl <aclname> <criterion> [flags] [operator] [<value>] ...
- aclname:ACL名称必须由大写和小写字母,数字,’ – ‘(短划线),’_’(下划线),’.’ 组成。ACL名称区分大小写
- value:值
boolean 布尔型
integer or integer range 整数或整数范围
IP address / network IP或网络地址
string (exact精确匹配, substring子串匹配, suffix前缀匹配, prefix后缀匹配, subdir子路径匹配, domain子域名匹配) 字符串匹配
regular expression 正则表示式匹配
hex block 16进制的块匹配
- flags:标志
-i : 忽略字符大小写
-m : 特定的模式
-n : 禁止DNS解析
-u : 要求acl使用唯一的名称
- operator:操作符
匹配整数值:eq、ge、gt、le、lt
匹配字符串:
exact match 精确匹配
substring match 子串匹配
prefix match 前缀匹配
suffix match 后缀匹配
subdir match 子路径匹配
domain match 子域名匹配
- acl作为条件时的逻辑关系:
if invalid_src invalid_port 或关系
if invalid_src || invalid_port 与关系
if ! invalid_src invalid_port 非invalid_src
- 检查URL的路径
path : 精确匹配
path_beg : 前缀匹配
path_dir : 子串匹配
path_dom : 子域名匹配
path_end : 路径后缀匹配
path_len : 路径长度匹配
path_reg : 路径的正则表达式模式匹配
path_sub : 路径的子字串匹配
- 整个URL检查
url : 精确匹配
url_beg : 前缀匹配
url_dir : 子串匹配
url_dom : 子域名匹配
url_end : 后缀匹配
url_len : 长度匹配
url_reg : 正则表达式匹配
url_sub : 子字串匹配
- 请求报文的指定头部检查
req.hdr([<name>[,<occ>]]) : string
This extracts the last occurrence of header <name> in an HTTP request.
hdr([<name>[,<occ>]]) : exact string match
hdr_beg([<name>[,<occ>]]) : prefix match
hdr_dir([<name>[,<occ>]]) : subdir match
hdr_dom([<name>[,<occ>]]) : domain match
hdr_end([<name>[,<occ>]]) : suffix match
hdr_len([<name>[,<occ>]]) : length match
hdr_reg([<name>[,<occ>]]) : regex match
hdr_sub([<name>[,<occ>]]) : substring match
示例:
acl bad_curl hdr_sub(User-Agent) -i curl
block if bad_curl
- 示例:阻止curl访问
frontend web *:80
acl bad_curl hdr_sub(User-Agent) -i curl
block if bad_curl
default_backend appsrvs
- 示例:
- 配置简单的动静分离
$ cp /etc/haproxy/haproxy.cfg{.bak}
$ vim /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local2
···
frontend main *:80
mode http
default_backend websrvs
backend websrvs
balance roundrobin
server websrv1 192.168.1.20:80 check
server websrv2 192.168.1.8:80 check
- apache服务的搭建
~]#yum install -y httpd
~]#echo srv1 > /var/www/html/index.html
~]#systemctl start httpd
~]#yum install -y httpd
~]#echo srv2 > /var/www/html/index.html
~]#systemctl start httpd
- 测试均衡调度
~]#for i in {1..10};do curl 192.168.1.18;done
srv1
srv2
srv1
srv2
srv1
srv2
srv1
srv2
srv1
srv2
实验wordpress的负载均衡
需求:
http:
(1) 动静分离部署wordpress,动静都要能实现负载均衡,要注意会话的问题;
(2) 给出设计拓扑,写成博客;
(3) haproxy的设定要求:
(a) stats page,要求仅能通过本地访问使用管理接口;
(b) 动静分离;
(c) 分别考虑不同的服务器组的调度算法;
(d) 压缩合适的内容类型;
- 首先,在192.168.1.8/24上实现lamp架构
1. 安装必要的软件
]# yum install -y mariadb-server httpd php-fpm php-mysql
]# wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
]# tar xf wordpress-4.9.4-zh_CN.tar.gz -C /var/www/html
]# chown -R apache.apache /var/www/html/*
]# cd /var/www/html/
]# cp wp-config-sample.php wp-config.php
]# vim wp-config.php
define('DB_NAME', 'wpdb');
/** MySQL数据库用户名 */
define('DB_USER', 'test');
/** MySQL数据库密码 */
define('DB_PASSWORD', 'centos');
/** MySQL主机 */
define('DB_HOST', '127.0.0.1');
2. 修改http配置文件
]# vim /etc/httpd/conf.d/fcgi.conf
DirectoryIndex index.php
ProxyRequests Off
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/html/$1
3. 授权mysql账户
]# systemctl start mariadb httpd
]# mysql -e "grant all on *.* to test@'192.168.1.%' identified by 'centos'"
]# mysql -e 'flush privileges'
4. 启动服务
]# systemctl start httpd
]# systemctl start php-fpm
]# systemctl start mariadb
5. 测试动静分离,停止服务,依旧能访问另一他台服务器的静态资源
]# systemctl stop httpd
- 其次,在192.168.1.20/24上实现静态资源
$ yum install -y httpd
$ wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
$ tar xf wordpress-4.9.4-zh_CN.tar.gz -C /var/www/html
$ chown -R apache.apache /var/www/html/*
- 最后,在haproxy服务器上配置动静分离
$ yum install -y haproaxy
$ cp /etc/haproxy/haproxy.cfg{,.bak}
$ vim /etc/haproxy/haproxy.cfg
···
frontend main *:80
mode http
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js .html .txt .htm
use_backend staticsrvs if url_static
default_backend phpsrvs
backend staticsrvs
balance roundrobin
#option httpchk GET /test1.html
#cookie WEBSRV insert nocache indirect
#server websrv1 192.168.1.20:80 weight 2 check cookie websrv1
#server websrv2 192.168.1.8:80 weight 1 check cookie websrv2
server websrv2 192.168.1.8:80 check
backend phpsrvs
balance roundrobin
server websrv1 192.168.1.20:80 check
listen stats
bind 127.0.0.1:80
stats enable
stats uri /admin?stats
stats realm HAProxy\ Stats
stats auth admin:admin
stats admin if TRUE
常用功能实现
- 压缩
frontend web *:80
default_backend appsrvs
compression algo gzip
compression type text/html text/plain
backend appsrvs
balance roundrobin
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
- stats page
listen stats
bind :8080
stats realm "HAProxy Stats Page"
stats auth admin:adminpass #认证用户:密码
stats admin if TRUE
访问:http://192.168.0.8:8080/haproxy?stats进入状态管理页
- 自定义错误页
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend web *:80
default_backend appsrvs
acl bad_guy src 192.168.0.7
block if bad_guy
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
backend appsrvs
balance roundrobin
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
[root@haproxy ~]# mkdir /etc/haproxy/errorfiles/ -p
[root@haproxy ~]# echo 'forbid' >/etc/haproxy/errorfiles/403forbid.http
[root@haproxy ~]# systemctl restart haproxy
[root@client ~]# curl http://192.168.0.8/
forbid
- 访问控制
listen stats
bind :8080
stats realm "HAProxy Stats Page"
stats auth admin:adminpass
stats admin if TRUE
acl admin_client src 192.168.0.254
block unless admin_client #只允许192.168.0.254访问状态管理页
- 日志功能
调度器中配置
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
backend appsrvs
balance roundrobin
option forwardfor
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
[root@haproxy haproxy]# systemctl restart haproxy.service
后端服务器配置(Apache)
[root@web2 ~]# vim /etc/httpd/conf/httpd.conf
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent
}i\"" combined #改变日志记录方式
[root@web2 ~]# systemctl restart httpd
[root@web2 ~]# tail -f /var/log/httpd/access_log
- 基于cookie的session粘滞
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend web *:80
mode http
default_backend appsrvs
backend appsrvs
balance roundrobin
option forwardfor
cookie WEBSRV insert nocache indirect
server app1 192.168.0.10:80 check inter 1000 rise 1 fall 2 maxconn 2000 cookie websrv1
server app2 192.168.0.11:80 check maxconn 1500 cookie websrv2
[root@client ~]# curl -b "WEBSRV=websrv1" http://192.168.0.8/
web1
[root@client ~]# curl -b "WEBSRV=websrv2" http://192.168.0.8/
web2
- 后端主机的健康状态检测
backend appsrvs
balance roundrobin
option httpchk GET /test.html
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
- 请求和响应报文首部的操纵:替换响应报文的Server字段信息
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend web *:80
mode http
rspidel ^Server:.*
rspadd Server:\ Apache\ or\ Nginx
default_backend appsrvs
[root@client ~]# curl -I http://192.168.0.8/
Server: Apache or Nginx #掩人耳目