1、简述keepalived工作原理
keepalived能够为很多不支持HA功能的程序填补HA的空缺,它对外提供一个虚拟的VIP,这个VIP并不是固定在某台机器的,而是可以根据状态或事件在多台主机之间依靠优先级进行浮动。
主机将根据配置决定以什么样的角色上线,上线后,主机将开始对外以单播方式,或组播(224.0.0.18,默认)地址发送VRRP消息,携带了VRRP的优先级等信息,其他主机监听后如果判断自己的优先级较低,将被阻塞,不会发送自己的VRRP消息,此时通过优先级就决定了主备关系,VIP则浮动在主设备上。
当主设备故障时,主设备停止,或发送被降低了优先级的VRRP报文,其他备机根据超时时间,或报文的优先级,判断主设备失效,它们会开始发送自己的VRRP消息,此时网络将发生主备切换,VIP将浮动到新的主设备。
当主设备从故障中恢复后,它的优先级可能也会恢复,此时默认情况下,主设备会抢占为新的MASTER,同时导致网络出现切换,通常为了避免这样的问题需要关闭主设备的抢占功能。
如果备设备因为某种原因无法收到主设备的VRRP通告,此时备设备会认为主设备故障,会切换到Master状态,这时两台主机都会变为Master,也就是脑裂现象,此时需要人为干涉以避免误导客户端,导致网络中断。
除了上述VRRP Stack提供的功能外,Keepalived还通过checkers组件提供对后端RS的状态监控,弥补LVS的不足。
keepalived也支持system call,能够调用脚本,判断并执行状态的通知、切换等功能。
keepalived也能作为IPVS的用户空间程序,不需要依赖ipvsadm,直接下发IPVS规则。
2、编译安装haproxy
#!/bin/bash
#****************************************************************************************#
#Author: Yabao11
#QQ: what QQ,no QQ
#Date: 2022-01-04
#FileName: nginx.sh
#URL: https://github.com/yabao11
#Description: Test Script
#Copyright (C): 2022 All rights reserved
#*******************************定义颜色*************************************************#
RED="\e[1;31m"
GREEN="\e[1;32m"
SKYBLUE="\e[1;36m"
YELLOW="\e[1;43m"
BLUE="\e[1;44m"
END="\e[0m"
RandomColor="\e[1;32m"
#****************************************************************************************#
function Ostype {
if grep -i -q "release 6" /etc/centos-release;then
echo Centos6
elif grep -i -q Centos-8 /etc/os-release;then
echo Centos
elif grep -i -q Centos-7 /etc/os-release;then
echo Centos7
elif grep -i -q Ubuntu /etc/os-release;then
echo Ubuntu
elif grep -i -q "RedHat" /etc/os-release;then
echo Redhat
fi
}
function color {
RES_COL=60
MOVE_TO_COL="echo -en \E[${RES_COL}G"
SETCOLOR_SUCCESS="echo -en \E[1;32m"
SETCOLOR_FAILURE="echo -en \E[1;31m"
SETCOLOR_WARNING="echo -en \E[1;33m"
SETCOLOR_NORMAL="echo -en \E[0m"
echo -n "$1" && $MOVE_TO_COL
echo -n "["
if [[ $2 = "success" || $2 = "0" ]]; then
${SETCOLOR_SUCCESS}
echo -n " OK "
elif [[ $2 = "failure" || $2 = "1" ]]; then
${SETCOLOR_FAILURE}
echo -n "FAILED"
else
${SETCOLOR_WARNING}
echo -n "WARNING"
fi
${SETCOLOR_NORMAL}
echo -n "]"
echo
}
function inputerror {
echo -en "输入错误!"
echo -e "\E[${RES_COL}G["$RED"退出"$END"]"
}
lua_file=${2:-lua-5.3.5}
haproxy_file=${1:-haproxy-2.4.12}
local_ip=(`hostname -I`)
function haproxy_install {
echo -e $GREEN"关闭防火墙和selinux"$END
systemctl disable --now firewalld
setenforce 0
echo -e $GREEN"开始编译lua"$END
yum -y install gcc readline-devel > /dev/null
[ -e ${lua_file}.tar.gz ] || ( wget http://www.lua.org/ftp/${lua_file}.tar.gz || { color "文件下载失败.." 1;exit; } )
[ -e ${lua_file} ] && rm -rf /usr/local/src/${lua_file}
[ -e /usr/local/src ] && tar xvf ${lua_file}.tar.gz -C /usr/local/src || color "解压失败.." 1
cd /usr/local/src/${lua_file}
make linux test && color "make成功" 0 || { color "make失败" 1;exit; }
echo -e $GREEN"开始编译HAProxy"$END
yum -y install gcc openssl-devel pcre-devel systemd-devel > /dev/null
cd /root
[ -e /root/${haproxy_file}.tar.gz ] || wget http://www.haproxy.org/download/2.4/src/${haproxy_file}.tar.gz -P /root/ -t 3
[ -e /root/${haproxy_file}.tar.gz ] || read -p "文件下载失败,请自行下载后将文件放到/root目录下,然后按回车继续.."
[ -e /root/${haproxy_file}.tar.gz ] || { color "找不到文件,请确认你已将正确的文件放到正确的路径.." 1;exit; }
tar xvf /root/${haproxy_file}.tar.gz -C /usr/local/src || { color "解压缩文件失败.." 1;exit; }
cd /usr/local/src/${haproxy_file}/ || { color "目录不存在" 1;exit; }
echo -e $GREEN"开始执行程序编译安装"$END
make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_LUA=1 LUA_INC=/usr/local/src/lua-5.3.5/src/ LUA_LIB=/usr/local/src/lua-5.3.5/src/ && color "make成功!" 0 || { color "make失败.." 1;exit; }
make install PREFIX=/data/haproxy && color "make install成功!" 0 || { color "make install失败.." 1;exit; }
echo -e $GREEN"创建软链接"$END
[ -e /usr/sbin/haproxy ] && rm -rf /usr/sbin/haproxy
ln -s /data/haproxy/sbin/haproxy /usr/sbin && color "软链接创建成功" 0 || color "软链接创建失败" 1
echo -e $GREEN"复制man帮助"$END
tar czf /usr/share/man/man1/haproxy.1.gz -P /data/haproxy/share/man/man1/haproxy.1
echo 'OPTIONS=""' >> /etc/sysconfig/haproxy
mkdir /etc/haproxy
mkdir /var/lib/haproxy
useradd -r -M -s /usr/nologin haproxy
chown haproxy.haproxy /etc/sysconfig/haproxy
chown haproxy.haproxy /var/lib/haproxy -R
chown haproxy.haproxy /etc/haproxy -R
chown haproxy.haproxy /data/haproxy -R
cat > /usr/lib/systemd/system/haproxy.service <<\EOF
[Unit]
Description=HAProxy Load Balancer
After=network-online.target
Wants=network-online.target
[Service]
Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid"
EnvironmentFile=/etc/sysconfig/haproxy
ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $OPTIONS
ExecStart=/usr/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE $OPTIONS
ExecReload=/usr/sbin/haproxy -f $CONFIG -c -q $OPTIONS
ExecReload=/bin/kill -USR2 $MAINPID
SuccessExitStatus=143
KillMode=mixed
Type=notify
[Install]
WantedBy=multi-user.target
EOF
echo -e $GREEN"创建初始配置文件,仅提供一个简单的上线配置文件"$END
cat > /etc/haproxy/haproxy.cfg <<EOF
#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
# https://www.haproxy.org/download/1.8/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2 info
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
nbproc 2
#stats socket /var/lib/haproxy/socket.sock mode 600 level admin
stats socket /var/lib/haproxy/socket1.sock mode 600 level admin process 1
stats socket /var/lib/haproxy/socket2.sock mode 600 level admin process 2
spread-checks 2
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen stats
mode http
bind *:9000
stats enable
log global
stats uri /stats
stats auth admin:123
stats auth mxx:123
stats refresh 3
stats admin if TRUE
# listen www
# bind ${local_ip[0]}:80
# server rs1 192.168.32.212:80
# server rs2 192.168.32.213:80
frontend www
log global
option httplog
bind ${local_ip[0]}:80
use_backend aaa
mode http
capture request header Host len 256
capture request header User-Agent len 512
capture request header Referer len 15
capture request header X-Forwarded-For len 15
backend aaa
server rs1 192.168.32.212:80 check inter 3000 fall 2 rise 5
server rs2 192.168.32.213:80 check inter 3000 fall 2 rise 5
EOF
echo -e $GREEN"提前开启日志功能,本脚本为测试环境"$END
sed -i.bak -r -e '/local7/a\local2.* /var/log/haproxy.log' \
-e 's/#(module\(load=\"imudp\"\).*)/\1/' \
-e 's/#(input\(type=\"imudp\".*)/\1/' /etc/rsyslog.conf
systemctl restart rsyslog
}
#exec
haproxy_install $1 $2
测试结果:
3、总结haproxy各调度算法的实现方式及其应用场景
static-RR:属于静态算法,不支持运行时修改权重以及后端服务器的慢启动,基于预先定义好的权重进行调度;
- 通常使用在做了session共享的web集群
first:静态算法,权重的设置无效,只有当第一台服务器连接数达到上限,新的请求才会分配给下一台服务器;
- 主要目的是使用最少的服务器提供业务支持,其他服务器可以执行停机维护等。
roundrobin:动态算法,支持慢启动和运行中通过socat调整权重;是默认的调度算法,按照权重的值进行调度;
- 默认调度算法
leastconn:权重次优于连接数,根据当前连接最少的后端服务器,而非权重进行优先调度;
- 长连接应用常用的调度算法,比如数据库
random:基于随机数作为一致性hash的key,支持weight的动态调整,weight大的有更大几率获取新请求。
source、URL、URL_PARAM、hdr等,根据hash-type来决定动态或静态的算法,分为取模和一致性hash两种:
- 取模是静态算法,对source、URL、URL_PARAM、hdr、rdp-cookie等执行HASH运算后,与服务器的总权重进行取模运算,根据得到的值来选取一台服务器,但会因为服务器的增加减少,导致总权重出现变化,而出现调度结果的整体改变。
- 一致性hash是动态算法,和nginx一样,构建hash环,服务器和请求计算的结果都会落在hash环上,然后通过顺时针查找,第一个匹配的服务器就是该请求发送的服务器。
- uri常用于缓存服务器场景
- url_param常用于实现会话保持
- hdr基于客户端请求报文头部做下一步处理
- rdp-cookie,基于windows主机
4、使用haproxy的ACL实现基于文件后缀名的动静分离
- HAproxy上添加ACL,匹配文件后缀,指向后端不同的服务器;可以只添加动态的.php和/,静态的设置为default:
frontend www
log global
option httplog
bind 192.168.32.197:80
use_backend dynamic if { path_end -i .php / }
default_backend static
mode http
capture request header Host len 256
capture request header User-Agent len 512
capture request header Referer len 15
capture request header X-Forwarded-For len 15
#http-request deny if { src 192.168.32.82 }
#http-request deny if { hdr_sub(User-Agent) -i curl }
backend static
server rs1 192.168.32.212:80 check inter 3000 fall 2 rise 5
backend dynamic
server rs2 192.168.32.213:80 check inter 3000 fall 2 rise 5
- 后端服务器dynamic那台需要配置fastcgi,动静两台服务器之间通过rsync同步wordpress数据,这部分是之前的作业内容;
#212服务器,配置add_header X-Via,方便判断资源从哪台服务器响应
[root@centos8mini 01]# cat /data/nginx/conf/conf.d/server1.conf
server {
listen 80;
server_name www.mxx.com;
access_log logs/www-access.log main;
client_max_body_size 10m;
location / {
add_header X-Via $server_addr;
root /data/server1/wordpress;
}
}
#213服务器同样配置add_header X-Via
[root@centos8mini wp-content]# cat /data/nginx/conf/conf.d/server1.conf
server {
listen 80;
server_name www.mxx.com;
access_log logs/www-access.log main;
client_max_body_size 10m;
index index.php;
location ~ \.php$|ping|status|/ {
root /data/server1/wordpress;
add_header X-Via $server_addr;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
#213上的php-fpm配置文件
[root@centos8mini wp-content]# cat /data/php74/etc/php-fpm.d/www.conf | grep -E -v "^;|^$"
[www]
php_value[session.save_handler] = files
user = nginx
group = nginx
listen = /var/run/php.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /status
ping.path = /ping
ping.response = pong
access.log = /data/php74/var/log/access.log
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
php_value[session.save_path] = /data/php74/log/session
- 访问测试
静态CSS资源通过212获取
动态php通过213获取: