HAProxy

post thumb
Ops
作者 Louis 发表于 2018年7月9日

摘要:

  • HAproxy的介绍安装及使用
  • 配置文件的说明及用法
  • ACL的配置文件选项说明
  • 常用用法及实验

HAProxy

  • 官网:

http://www.haproxy.org

http://www.haproxy.com

  • 官方文档:

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
  • 示例:
  1. 配置简单的动静分离
$ 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
  1. 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
  1. 测试均衡调度
~]#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

常用功能实现

  1. 压缩
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
  1. 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进入状态管理页
  1. 自定义错误页
[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
  1. 访问控制
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访问状态管理页
  1. 日志功能
调度器中配置
[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
  1. 基于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
  1. 后端主机的健康状态检测
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
  1. 请求和响应报文首部的操纵:替换响应报文的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  #掩人耳目
上一篇
Nginx