35.第29章 HAProxy负载均衡
一.HAProxy调度算法
1.静态算法
静态算法:按照事先定义好的规则轮询公平调度,不关⼼后端服务器的当前负载、链接数和响应速度等,且⽆法实时修改权重,只能靠重启HAProxy⽣效。
1.1 static-rr
static-rr:基于权重的轮询调度,不⽀持权重的运⾏时调整及后端服务器慢启动,其后端主机数量没有限制
1.2 first
first:根据服务器在列表中的位置,⾃上⽽下进⾏调度,但是其只会当第⼀台服务器的连接数达到上限,新请求才会分配给下⼀台服务,因此会忽略服务器的权重设置。
2.动态算法
动态算法:基于后端服务器 状态进⾏调度适当调整,⽐如优先调度⾄当前负载较低的服务器,且权重可以在haproxy运⾏时动态调整⽆需重启。
2.1 roundrobin
roundrobin:基于权重的轮询动态调度算法,⽀持权重的运⾏时调整,不完全等于lvs中的rr轮训模式,HAProxy中的roundrobin⽀持慢启动(新加的服务器会逐渐增加转发数),其每个后端backend中最多⽀持4095个real server,roundrobin为默认调度算法,且⽀持对real server权重动态调整。
2.2 leastconn
leastconn加权的最少连接的动态,⽀持权重的运⾏时调整和慢启动,即当前后端服务器连接最少的优先调度(新客户端连接),⽐较适合⻓连接的场景使⽤,⽐如MySQL等场景。
3.其他算法
其他部分算法即可作为静态算法,⼜可以通过选项成为动态算法
3.1 source
源地址hash,基于⽤户源地址hash并将请求转发到后端服务器,默认为静态即取模⽅式,但是可以通过hash-type⽀持的选项更改,后续同⼀个源地址请求将被转发⾄同⼀个后端web服务器,⽐较适⽤于session保持/缓存业务等场景。
源地址有两种转发客户端请求到后端服务器的服务器选取计算⽅式,分别是取模法和⼀致性hash
3.1.1 map-base取模法
map-based:取模法,基于服务器总权重的hash数组取模,该hash是静态的即不⽀持在线调整权重,不⽀持慢启动,其对后端服务器调度均衡,缺点是当服务器的总权重发⽣变化时,即有服务器上线或下线,都会因权重发⽣变化⽽导致调度结果整体改变。
所谓取模运算,就是计算两个数相除之后的余数,10%7=3,7%4=3,基于权重取模:(2^32-1)%(1+1+2),公式为,hash(o)mod n,即a mod b=c,表明a除以b余数为c。
3.1.2 ⼀致性hash
⼀致性哈希,该hash是动态的,⽀持在线调整权重,⽀持慢启动,优点在于当服务器的总权重发⽣变化时,对调度结果影响是局部的,不会引起⼤的变动。
3.2 uri
基于对⽤户请求的uri做hash并将请求转发到后端指定服务器,也可以通过map-based和consistent定义使⽤取模法还是⼀致性hash。
3.3 url_param
url_param对⽤户请求的url中的 params 部分中的参数name作hash计算,并由服务器总权重相除以后派发⾄某挑出的服务器;通常⽤于追踪⽤户,以确保来⾃同⼀个⽤户的请求始终发往同⼀个real server
3.4 hdr
针对⽤户每个http头部(header)请求中的指定信息做hash,此处由name 指定的http⾸部将会被取出并做hash计算,然后由服务器总权重相除以后派发⾄某挑出的服务器,假如⽆有效的值,则会使⽤默认的轮询调度。
3.5 rdp-cookie
rdp-cookie使⽤客户端cookie保持会话,可以实现对windows远程桌⾯的负载等
3.6 random
在1.9版本开始增加⼀个叫做random的负载平衡算法,其基于⼀个随机数作为⼀致性hash的key,随机负载平衡对于⼤型服务器场或经常添加或删除服务器⾮常有⽤。
算法总结:
static-rr--------->tcp/http 静态
first------------->tcp/http 静态
roundrobin-------->tcp/http 动态
leastconn--------->tcp/http 动态
random------------>tcp/http 动态
source------------>tcp/http
Uri--------------->http
url_param--------->http 取决于hash_type是否
consistent
hdr--------------->http
rdp-cookie-------->tcp
各算法使⽤场景:
first #使⽤较少
static-rr #做了session共享的web集群
roundrobin
random
leastconn #数据库
source #基于客户端公⽹IP的会话保持
Uri--------------->http #缓存服务器,CDN服务商,蓝汛、百度、阿⾥云、腾讯
url_param--------->http
hdr #基于客户端请求报⽂头部做下⼀步处理
rdp-cookie #很少使⽤
二.HAProxy一键编译安装
[root@centos7 ~]# cat install_haproxy.sh
#!/bin/bash
#
#******************************************************************************
#Author: zhanghui
#QQ: 19661891
#Date: 2021-09-03
#FileName: install_haproxy.sh
#URL: www.cnblogs.com/neteagles
#Description: install_haproxy for centos 7/8 & ubuntu 18.04/20.04
#Copyright (C): 2021 All rights reserved
#******************************************************************************
SRC_DIR=/usr/local/src
COLOR="echo -e \\033[01;31m"
END='\033[0m'
CPUS=`lscpu |awk '/^CPU\(s\)/{print $2}'`
LUA_FILE=lua-5.4.3.tar.gz
HAPROXY_FILE=haproxy-2.4.3.tar.gz
HAPROXY_INSTALL_DIR=/apps/haproxy
STATS_AUTH_USER=admin
STATS_AUTH_PASSWORD=123456
NET_NAME=`ip a |awk -F"[: ]" '/^2/{print $3}'`
IP=`ip addr show ${NET_NAME}| awk -F" +|/" '/global/{print $3}'`
os(){
if grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release;then
rpm -q redhat-lsb-core &> /dev/null || { ${COLOR}"安装lsb_release工具"${END};yum -y install redhat-lsb-core &> /dev/null; }
fi
OS_ID=`lsb_release -is`
}
check_file (){
cd ${SRC_DIR}
${COLOR}'检查HAPROXY相关源码包'${END}
if [ ! -e ${LUA_FILE} ];then
${COLOR}"缺少${LUA_FILE}文件"${END}
exit
elif [ ! -e ${HAPROXY_FILE} ];then
${COLOR}"缺少${HAPROXY_FILE}文件"${END}
exit
else
${COLOR}"相关文件已准备好"${END}
fi
}
install_haproxy(){
[ -d ${HAPROXY_INSTALL_DIR} ] && { ${COLOR}"haproxy已存在,安装失败"${END};exit; }
${COLOR}"开始安装HAPROXY"${END}
${COLOR}"开始安装HAPROXY依赖包"${END}
if [ ${OS_ID} == "CentOS" ] &> /dev/null;then
yum -y install gcc make gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel libtermcap-devel ncurses-devel libevent-devel readline-devel &> /dev/null
else
apt update &> /dev/null;apt -y install gcc make openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev libreadline-dev libsystemd-dev &> /dev/null
fi
tar xf ${LUA_FILE}
LUA_DIR=`echo ${LUA_FILE} | sed -nr 's/^(.*[0-9]).*/\1/p'`
cd ${LUA_DIR}
make all test
cd ${SRC_DIR}
tar xf ${HAPROXY_FILE}
HAPROXY_DIR=`echo ${HAPROXY_FILE} | sed -nr 's/^(.*[0-9]).*/\1/p'`
cd ${HAPROXY_DIR}
make -j ${CPUS} ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 USE_LUA=1 LUA_INC=/usr/local/src/${LUA_DIR}/src/ LUA_LIB=/usr/local/src/${LUA_DIR}/src/ PREFIX=${HAPROXY_INSTALL_DIR}
make install PREFIX=${HAPROXY_INSTALL_DIR}
[ $? -eq 0 ] && $COLOR"HAPROXY编译安装成功"$END || { $COLOR"HAPROXY编译安装失败,退出!"$END;exit; }
cat > /lib/systemd/system/haproxy.service <<-EOF
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target
[Service]
ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
EOF
[ -L /usr/sbin/haproxy ] || ln -s ../../apps/haproxy/sbin/haproxy /usr/sbin/ &> /dev/null
[ -d /etc/haproxy ] || mkdir /etc/haproxy &> /dev/null
[ -d /var/lib/haproxy/ ] || mkdir -p /var/lib/haproxy/ &> /dev/null
cat > /etc/haproxy/haproxy.cfg <<-EOF
global
maxconn 100000
chroot /apps/haproxy
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
#nbproc 4
#cpu-map 1 0
#cpu-map 2 1
#cpu-map 3 2
#cpu-map 4 3
pidfile /var/lib/haproxy/haproxy.pid
log 127.0.0.1 local3 info
defaults
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth ${STATS_AUTH_USER}:${STATS_AUTH_PASSWORD}
EOF
echo "PATH=${HAPROXY_INSTALL_DIR}/sbin:${PATH}" > /etc/profile.d/haproxy.sh
systemctl daemon-reload
systemctl enable --now haproxy &> /dev/null
systemctl is-active haproxy &> /dev/null || { ${COLOR}"HAPROXY 启动失败,退出!"${END} ; exit; }
${COLOR}"HAPROXY安装完成"${END} && ${COLOR}"HAPROXY状态页地址: http://${IP}:9999/haproxy-status,用户名:admin,密码:123456"${END}
}
main(){
os
check_file
install_haproxy
}
main