目录
四、Keepalived实例--实现单主架构的LVS-DR模型
五、实例--通过Keepalived实现HAProxy高可用
一、HAProxy介绍
负载均衡(Load Balance),简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了公司业务的并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展。
HAProxy是使用C语言开发的开源软件,具有高并发(一万以上)、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统计。
#包安装HAProxy
root@ubuntu-test1:~# apt-get install --no-install-recommends software-properties-common
root@ubuntu-test1:~# add-apt-repository ppa:vbernat/haproxy-2.8
root@ubuntu-test1:~# apt-get install haproxy=2.8.\*
#编译安装HAProxy
#编译安装Lua
root@ubuntu-test1:~# apt update && apt -y install gcc make libssl-dev libpcre3 libpcre3-dev zlib1g-dev libreadline-dev libsystemd-dev #安装依赖包
root@ubuntu-test1:~#wget http://www.lua.org/ftp/lua-5.3.5.tar.gz #下载新版源码
root@ubuntu-test1:~#tar xf lua-5.3.5.tar.gz -C /usr/local/src/;cd /usr/local/src/
root@ubuntu-test1:/usr/local/src/lua-5.3.5# make linux test #编译安装
root@ubuntu-test1:/usr/local/src/lua-5.3.5#cd ~
root@ubuntu-test1:~# export PATH=$PATH:/usr/local/src/lua-5.3.5/src
root@ubuntu-test1:~# lua -v
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
#编译安装HAProxy
root@ubuntu-test1:~# wget http://www.haproxy.org/download/2.8/src/haproxy-2.8.0.tar.gz
root@ubuntu-test1:~# mkdir /home/apps/
root@ubuntu-test1:~# tar xf haproxy-2.8.0.tar.gz
root@ubuntu-test1:~# cd haproxy-2.8.0/
root@ubuntu-test1:~/haproxy-2.8.0# make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_PROMEX=1 USE_LUA=1 LUA_INC=/usr/local/src/lua-5.3.5/src/ LUA_LIB=/usr/local/src/lua-5.3.5/src/ #编译安装源码
root@ubuntu-test1:~/haproxy-2.8.0# make install prefix=/home/apps/haproxy
root@ubuntu-test1:~/haproxy-2.8.0#ln -s /home/apps/haproxy/sbin/haproxy /usr/local/sbin/
root@ubuntu-test1:~/haproxy-2.8.0# cd ~
root@ubuntu-test1:~# haproxy -v
HAProxy version 2.8.0-fdd8154 2023/05/31 - https://haproxy.org/
#配置HAProxy
root@ubuntu-test1:~#useradd -m -r -s /sbin/nologin -d /var/lib/haproxy haproxy
root@ubuntu-test1:~# mkdir /etc/haproxy
root@ubuntu-test1:~# vim /etc/haproxy/haproxy.cfg #编辑配置文件
global
maxconn 100000
chroot /home/apps/haproxy
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
user haproxy
group haproxy
daemon
nbthread 4
cpu-map auto:1-4 0-3
#log 127.0.0.1 local2 info
defaults
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
listen stats
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth admin:123456
root@ubuntu-test1:~# vim /lib/systemd/system/haproxy.service #编辑service文件
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target
[Service]
ExecStartPre=/usr/local/sbin/haproxy -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/ -c -q
ExecStart=/usr/local/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/ -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target
root@ubuntu-test1:~# chown haproxy.haproxy /home/apps/haproxy/ -R
root@ubuntu-test1:~# chown haproxy.haproxy /etc/haproxy/ -R
root@ubuntu-test1:~# systemctl daemon-reload
root@ubuntu-test1:~# systemctl enable --now haproxy.service
二、HAProxy基本使用
2.1,HAProxy调度算法
#Socat是Linux下的一个多功能的网络工具,可以对服务器动态权重和其它状态进行调整
root@ubuntu-test1:~# apt update && apt -y install socat
root@ubuntu-test1:~# echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
|-----------------------|----------------|-------------------------------------------------------------------------------|
| 静态算法 不支持socat | static-rr | 基于权重的轮询调度,,其后端主机数量没有限制,相当于 LVS 中的 wrr |
| 静态算法 不支持socat | first | 根据服务器列表位置,自上而下调度,只有第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置 |
| 动态算法支持socat | roundrobin | 基于权重的轮询动态调度算法 |
| 动态算法支持socat | leastconn | 加权的最少连接的动态,支持权重的运行时调整和慢启动,即根据当前连接最少的后端服务器而非权重进行优先调度,适合MySQL场景 |
| 动态算法支持socat | random | 基于随机数作为一致性 hash 的 key ,支持weight 的动态调整,权重越大越容易 获取新请求,适用于大型服务器场或经常添加或删除服务器 |
| source 算法 | map-based | 取模法,对 源地址进行hash计算,再基于服务器总权重的取模,不支持在线调整权重,此算法为hash-type 指定的默认值 |
| source 算法 | consistent | 一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,支持在线调整权重 |
| uri算法 || 基于对用户请求的 URI 的左半部分或整个 uri 做 hash ,再将 hash 结果对总权重进行取模,此算法基于应用层至支持mode http |
| url_param算法 || 对用户请求的 url 中的规定的 params 部分进行 hash计算,再将hash结果对总权重进行取模,若未指定param按 roundrobin 算法 |
| hdr算法 || 对用户每个 http 头部 请求中的指定信息做hash,再将hash结果对总权重进行取模 |
| rdp-cookie算法 || 对 Windows 远程桌面的负载,使用 cookie 保持会话,默认是静态,也可通过指定 hash-type 来定义使用取模法还是一致性 hash |
#HAProxy配置案例-源地址一致性哈希配置
#10.0.0.151--Rocky-test1
#10.0.0.152--Rocky-test2
[root@Rocky-test1 ~]# yum -y install nginx
[root@Rocky-test1 ~]# systemctl enable --now nginx.service
[root@Rocky-test1 ~]# echo www.wlm.com > /usr/share/nginx/html/index.html
[root@Rocky-test2 ~]#echo www.wlm.io > /usr/share/nginx/html/index.html
root@ubuntu-test1:~# vim /etc/haproxy/conf.d/web.cfg #创建子配置文件
frontend web_http
bind 10.0.0.161:80
use_backend web_hosts
backend web_hosts
balance source
hash-type consistent
server web1 10.0.0.151:80 check weight 2 inter 3000 fall 3 rise 2
server web2 10.0.0.152:80 check weight 1 inter 3000 fall 3 rise 2
root@ubuntu-test1:~#haproxy -c -f /etc/haproxy/conf.d/web.cfg #检测配置文件
root@ubuntu-test1:~# systemctl reload haproxy.service
root@ubuntu-test1:~# curl 10.0.0.161 #测试
2.2,HAProxy高级用法
#ACL实例
#ACL实例--域名匹配
root@ubuntu-test1:~# vim /etc/hosts
10.0.0.161 www.wlm.com www.wlm.io www.wlm.org
root@ubuntu-test1:~# vim /etc/haproxy/conf.d/web.cfg
frontend web_http
bind 10.0.0.161:80
balance roundrobin
acl com_domain hdr_dom(host) -i www.wlm.com
acl io_domain hdr_dom(host) -i www.wlm.io
use_backend com_hosts if com_domain
use_backend io_hosts if io_domain
default_backend com_hostsbackend com_hosts
server web1 10.0.0.151:80 check weight 2 inter 3000 fall 3 rise 2
backend io_hosts
server web2 10.0.0.152:80 check weight 1 inter 3000 fall 3 rise 2
root@ubuntu-test1:~# systemctl reload haproxy.service
root@ubuntu-test1:~# curl www.wlm.org
root@ubuntu-test1:~#curl www.wlm.com
root@ubuntu-test1:~# curl www.wlm.io
#ACL实例--基于源地址访问控制
root@ubuntu-test1:~# vim /etc/haproxy/conf.d/web.cfg
frontend web_http
......
acl inter_src src 10.0.0.151 10.0.0.152
http-request deny if inter_src......
root@ubuntu-test1:~# systemctl reload haproxy.service
root@ubuntu-test1:~# curl 10.0.0.161
[root@Rocky-test1 ~]# curl 10.0.0.161
curl: (7) Failed to connect to 10.0.0.161 port 80: Connection refused
#ACL实例--动静分离
root@ubuntu-test1:~# vim /etc/haproxy/conf.d/web.cfg
frontend web_http
bind 10.0.0.161:80
balance roundrobin
acl static path_end -i .jpg .jpeg .html .css .js .png .gif
acl php path_end -i .php
use_backend com_hosts if static
use_backend io_hosts if php
default_backend com_hostsbackend com_hosts
server web1 10.0.0.151:80 check weight 2 inter 3000 fall 3 rise 2
backend io_hosts
server web2 10.0.0.152:80 check weight 1 inter 3000 fall 3 rise 2
root@ubuntu-test1:~# systemctl reload haproxy.service
三、高可用Keepalived介绍
3.1,Keepalived介绍
VRRP(Virtual Router Redundancy Protocol),虚拟路由冗余协议,解决静态网关单点风险。物理层面通过路由器、三层交换机实现,软件层面通过Keepalived实现。
Keepalived是高可用集群的通用无状态应用解决方案,其主要功能:
1,基于vrrp协议完成地址流动;
2,为vip地址所在的节点生成ipvs规则(在配置文件中预先定义);
3,为ipvs集群的各RS做健康状态检测;
4,基于脚本调用接口完成脚本中定义的功能,进而影响集群事务,以此支持nginx、haproxy等服务
#Keepalived安装root@ubuntu-test1:~# apt list keepalived -a
Listing... Done
keepalived/focal-updates 1:2.0.19-2ubuntu0.2 amd64
#编译安装
root@ubuntu-test1:~# apt update && apt -y install make gcc ipvsadm build-essential pkg-config automake autoconf libipset-dev libnl-3-dev libnl-genl-3-dev libssl-dev libxtables-dev libip4tc-dev libip6tc-dev libmagic-dev libsnmp-dev libglib2.0-dev libpcre2-dev libnftnl-dev libmnl-dev libsystemd-dev #安装依赖包
root@ubuntu-test1:~# wget https://keepalived.org/software/keepalived-2.3.0.tar.gz
root@ubuntu-test1:~# tar xf keepalived-2.3.0.tar.gz -C /usr/local/src/
root@ubuntu-test1:~# mkdir /home/apps/
root@ubuntu-test1:~# cd /usr/local/src/keepalived-2.3.0/
root@ubuntu-test1:/usr/local/src/keepalived-2.3.0#./configure --prefix=/home/apps/keepalived --disable-iptables #指定目录编译
root@ubuntu-test1:/usr/local/src/keepalived-2.3.0# make -j2 && make install
root@ubuntu-test1:/usr/local/src/keepalived-2.3.0# cp ./keepalived/keepalived.service /lib/systemd/system/ #复制service文件
root@ubuntu-test1:/usr/local/src/keepalived-2.3.0# cd ~
root@ubuntu-test1:~# systemctl daemon-reload
root@ubuntu-test1:~# cp /home/apps/keepalived/etc/keepalived/keepalived.conf.sample /home/apps/keepalived/etc/keepalived/ #拷贝模板配置文件至本地,注意网卡名称
root@ubuntu-test1:/home/apps/keepalived#systemctl enable --now keepalived.service
root@ubuntu-test1:~#hostname -I
10.0.0.161 192.168.200.16 192.168.200.17 192.168.200.18
root@ubuntu-test1:~#vim /home/apps/keepalived/etc/keepalived/keepalived.conf #添加子配置文件路径
include /etc/keepalived/*.conf
root@ubuntu-test1:~# vim /home/apps/keepalived/etc/sysconfig/keepalived #开启日志
KEEPALIVED_OPTIONS="-D -S 6"
root@ubuntu-test1:~# vim /etc/rsyslog.conf
local6.* /var/log/keepalived.log
root@ubuntu-test1:~# systemctl restart rsyslog.service keepalived.service
root@ubuntu-test1:~#ll /var/log/keepalived.log
-rw-r----- 1 syslog adm 6261 Oct 23 10:44 /var/log/keepalived.log
3.2,Keepalived单主架构实现
#root@ubuntu-test1--10.0.0.161--主节点
#root@ubuntu-test2--10.0.0.162--备节点
#对两台主机进行编译安装Keepalived,同时添加网卡(仅主机模式)做心跳网络
root@ubuntu-test1:~# ip link set ens36 up
root@ubuntu-test1:~#vim /etc/netplan/00-installer-config.yaml
network:
ethernets:
ens33:
dhcp4: no
addresses:
- 10.0.0.161/24
gateway4: 10.0.0.2
nameservers:
addresses: [8.8.8.8,223.5.5.5]
ens36:
dhcp4: no
addresses:
- 192.168.10.10/24
version: 2
root@ubuntu-test1:~# netplan apply
#同样操作为ubuntu-test2添加192.168.10.20的网卡
#为两个节点配置keepalived配置文件
root@ubuntu-test1:~# vim /home/apps/keepalived/etc/keepalived/keepalived.conf
global_defs {
router_id LVS_DEVEL_161
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
vrrp_mcast_group4 230.0.0.100
}
include /etc/keepalived/*.conf
root@ubuntu-test1:~# vim /etc/keepalived/domain1.conf
vrrp_instance VI_1 {
state MASTER
interface ens36
virtual_router_id 88
priority 100advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
10.0.0.160/24 dev ens33 label ens33:1
}
}
root@ubuntu-test1:~# hostname -I
10.0.0.161 10.0.0.160 192.168.10.10
root@ubuntu-test2:~# vim /etc/keepalived/domain1.conf
vrrp_instance VI_1 {
state BACKUP
interface ens36
virtual_router_id 88
priority 80
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
10.0.0.160/24 dev ens33 label ens33:1
}
}
root@ubuntu-test2:~# hostname -I
10.0.0.162 192.168.10.20
#在心跳网络抓包
root@ubuntu-test2:~# tcpdump -i ens36 -nn host 230.0.0.100
15:24:52.577437 IP 192.168.10.10 > 230.0.0.100: VRRPv2, Advertisement, vrid 88, prio 100, authtype simple, intvl 1s, length 20
#默认使用多播通信会造成网络堵塞,可设置单播模式减少流量,单播优先级高于多播
root@ubuntu-test1:~# vim /etc/keepalived/domain1.conf
vrrp_instance VI_1 {
.......
unicast_src_ip 192.168.10.10
unicast_peer {
192.168.10.20
}
}
root@ubuntu-test2:~# vim /etc/keepalived/domain1.conf
vrrp_instance VI_1 {
.......
unicast_src_ip 192.168.10.20
unicast_peer {
192.168.10.10
}
}
3.3,脑裂
脑裂现象:主备节点同时拥有同一个VIP
产生原因:
1,心跳线故障(在虚拟机环境中测试可以通过修改网卡的工作模式实现,断开网卡不行)
2,防火墙错误配置(在从节点执行iptables -A INPUT -s 主服务心跳网卡IP -j DROP进行模拟)
3,Keepalived配置错误(多播地址不同,interface错误,virtual_router_id不一致,密码不一致)
脑裂检测方法:
在网络相连的其他主机使用arping -I 网卡 -c1 VIP命令
[root@Rocky-test1 ~]# arping -I ens160 -c1 10.0.0.160
ARPING 10.0.0.160 from 10.0.0.151 ens160
Unicast reply from 10.0.0.160 [00:0C:29:40:FA:70] 1.172ms
Unicast reply from 10.0.0.160 [00:0C:29:F7:F6:CF] 1.264ms
四、Keepalived实例--实现单主架构的LVS-DR模型
#在3.2单主架构的基础上配置两台后端真实服务器
#root@Rocky-test1--10.0.0.151
#root@Rocky-test2--10.0.0.152
#在真实服务器配置
[root@Rocky-test1 ~]# echo `hostname` > /usr/share/nginx/html/index.html
[root@Rocky-test1 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@Rocky-test1 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
[root@Rocky-test1 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@Rocky-test1 ~]#echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@Rocky-test1 ~]# ifconfig lo:1 10.0.0.160/32
#在Rocky-test2上进行同样操作
#在Keepalived节点上为子文件追加相同配置
root@ubuntu-test2:~# vim /etc/keepalived/domain1.conf
......
virtual_server 10.0.0.160 80 {
delay_loop 3
lb_algo wrr
lb_kind DR
protocol TCP
real_server 10.0.0.151 80 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 1
nb_get_retry 3
delay_before_retry 1
}
}
real_server 10.0.0.152 80 {
weight 2
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 1
nb_get_retry 3
delay_before_retry 1
}
}
}
root@ubuntu-test2:~# systemctl restart keepalived.service
root@ubuntu-test1:~# ipvsadm -Ln #查看LVS调度规则
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.160:80 wrr
-> 10.0.0.151:80 Route 1 0 0
-> 10.0.0.152:80 Route 2 0 0root@ubuntu-test3:~# while true;do curl 10.0.0.160;sleep 1;done #在其他客户端访问测试
Rocky-test1
Rocky-test2
Rocky-test2
Rocky-test1
Rocky-test2
Rocky-test2
Rocky-test1
Rocky-test2
Rocky-test2
#添加vrrp_script自定义资源监控脚本,实现节点自动切换
root@ubuntu-test1:~# vim /home/apps/keepalived/etc/keepalived/keepalived.conf
.......
vrrp_script check_keepalived {
script /etc/keepalived/check_keepalived.sh
interval 1
timeout 2
weight -30
fall 2
rise 3
}
root@ubuntu-test1:~# vim /etc/keepalived/domain1.conf
vrrp_instance VI_1 {
.......
track_script {
check_keepalived
}}
root@ubuntu-test1:~# vim /etc/keepalived/check_keepalived.sh
#!/bin/bash
/usr/bin/killall -0 keepalived
root@ubuntu-test1:~# chmod +x /etc/keepalived/check_keepalived.sh
root@ubuntu-test1:~#systemctl restart keepalived.service
root@ubuntu-test1:~# systemctl stop keepalived.service #模拟服务故障
root@ubuntu-test1:~# hostname -I
10.0.0.161 192.168.10.10
五、实例--通过Keepalived实现HAProxy高可用
#ubuntu-test1--10.0.0.161--部署Keepalived+HAProxy
#ubuntu-test2--10.0.0.162--部署Keepalived+HAProxy
#Rocky-test1--10.0.0.151--部署Nginx
#Rocky-test2--10.0.0.152--部署Nginx
#先在ubuntu-test1,2创建HAProxy和keepalived子配置文件
root@ubuntu-test1:~# vim /etc/keepalived/domain1.conf
vrrp_instance VI_1 {
state MASTER
interface ens36
virtual_router_id 88
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
10.0.0.160/24 dev ens33 label ens33:1
}
unicast_src_ip 192.168.10.10
unicast_peer {
192.168.10.20
}
track_script {
check_keepalived
}
}
root@ubuntu-test1:~#vim /etc/haproxy/conf.d/web.cfg
frontend web_http
bind 10.0.0.160:80
use_backend web_hosts
backend web_hosts
balance roundrobin
server web1 10.0.0.151:80 check weight 2 inter 3000 fall 3 rise 2
server web2 10.0.0.152:80 check weight 1 inter 3000 fall 3 rise 2
root@ubuntu-test1:~#systemctl reload haproxy.service keepalived.service
#编辑内核参数,允许进程绑定到不属于本机接口的 IP 地址
root@ubuntu-test1:~# vim /etc/sysctl.conf
net.ipv4.ip_nonlocal_bind = 1
root@ubuntu-test1:~# sysctl -p
#在其他客户端访问测试
[root@Rocky-test3 ~]# curl 10.0.0.160
10.0.0.151 Rocky-test1
[root@Rocky-test3 ~]# curl 10.0.0.160
10.0.0.151 Rocky-test1
[root@Rocky-test3 ~]# curl 10.0.0.160
10.0.0.152 Rocky-test2
#在ubuntu-test1添加VRRP脚本实现高可用
root@ubuntu-test1:~# vim /etc/keepalived/check_haproxy.sh
#!/bin/bash
if /usr/bin/killall -0 haproxy ;then
exit 0
else
systemctl restart haproxy
fi
root@ubuntu-test1:~# chmod +x /etc/keepalived/check_haproxy.sh
root@ubuntu-test1:~# vim /home/apps/keepalived/etc/keepalived/keepalived.conf
.......
vrrp_script check_haproxy {
script /etc/keepalived/check_haproxy.sh
interval 1
timeout 2
weight -30
fall 2
rise 3
}
root@ubuntu-test1:~#vim /etc/keepalived/domain1.conf
.......
track_script {
check_keepalived
check_haproxy
}
}
root@ubuntu-test1:~# systemctl restart keepalived.service
#对后端服务器进行证书加密,HAProxy配置四层代理
[root@Rocky-test1 ~]# mkdir /home/nginx.cert
[root@Rocky-test1 ~]#cd /home/nginx.cert
[root@Rocky-test1 nginx.cert]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
[root@Rocky-test1 nginx.cert]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.wlm.com.key -out www.wlm.com.csr
[root@Rocky-test1 nginx.cert]#openssl x509 -req -days 365 -in www.wlm.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out www.wlm.com.crt
[root@Rocky-test1 nginx.cert]# cat www.wlm.com.crt ca.crt > www.wlm.com.pem
[root@Rocky-test1 ~]# vim /etc/nginx/nginx.conf
server {
listen 80;
listen 443 ssl http2;
server_name www.wlm.com;
root /usr/share/nginx/html;
ssl_certificate /home/nginx.cert/www.wlm.com.pem;
ssl_certificate_key /home/nginx.cert/www.wlm.com.key;
if ( $scheme = http ) {
rewrite ^(.*) https://$server_name/$1 redirect;
}
[root@Rocky-test1 ~]# systemctl reload nginx.service
root@ubuntu-test1:~#vim /etc/haproxy/conf.d/web.cfg
frontend web_http
mode tcp
bind 10.0.0.160:80
use_backend web_hosts
backend web_hosts
balance roundrobin
mode tcp
server web1 10.0.0.151:80 check weight 2 inter 3000 fall 3 rise 2
server web2 10.0.0.152:80 check weight 1 inter 3000 fall 3 rise 2
[root@Rocky-test3 ~]# curl -k https://www.wlm.com #测试成功
10.0.0.151 Rocky-test1
六、NoSQL数据库Redis
6.1,Redis简介
NoSQL 数据库,全称为****Not Only SQL,既可以适用关系型数据库也可以使用其他类型的数据存储。
Redis是一个开源的Key-Value存储系统,使用C语言开发,支持多种编程语言的API。它是一个高速缓存数据库,采用内存存储,并支持持久化,能够提供高性能的数据读写操作。
Redis特性:
属于非关系数据库,键值对数据库
高性能
纯内存操作,数据操作采用单线程(还有其他线程做备份等操作)
支持持久化
支持多种数据结构,编程语言
Redis高性能原因:纯内存,数据操作较硬盘快
单线程操作数据,避免线程竞争,非阻塞IO,取消锁机制,epoll机制IO
|----------------|---------------------------------------|
| Redis常见应用场景 ||
| 缓存 | 缓存RDBMS中数据,比如网站的查询结果、商品信息、微博、新闻、消息 |
| Session 共享 | 实现Web集群中的多服务器间的session共享 |
| 计数器 | 商品访问排行榜、浏览数、粉丝数、关注、点赞、评论等和次数相关的数值统计场景 |
| 社交 | 朋友圈、共同好友、可能认识他们等 |
| 地理位置 | 基于地理信息系统实现摇一摇、附近的人、外卖等功能 |
| 消息队列 | ELK等日志系统缓存、业务的订阅/发布系统 |
|----------|----------------------------------------|-----------------------------------------------------|
| 名称 | 概念 | 解决方法 |
| 缓存穿透 | 缓存和Redis数据库中没有, MySQL关系数据库也没有的数据,被请求访问 | 在接口层增加校验,如用户鉴权校验 对无法查询的数据短期定义key-null |
| 缓存击穿 | 缓存和Redis数据库中没有, MySQL数据库中有的数据,被请求访问 | 设置热点数据永远不过期 |
| 缓存雪崩 | 缓存中数据大批量到过期时间, 而查询数据量巨大,引起数据库压力过大甚至宕机 | 设置热点数据永远不过期 缓存数据的过期时间设置随机 若数据库为分布式,热点数据均匀 分布不同缓存数据库 |
#编译安装Redis
root@ubuntu-test1:~# apt update && apt -y install gcc make libjemalloc-dev libsystemd-dev#安装依赖包
root@ubuntu-test1:~# wget http://download.redis.io/releases/redis-7.2.0.tar.gz
root@ubuntu-test1:~# tar xf redis-7.2.0.tar.gz
root@ubuntu-test1:~# mkdir /home/apps
root@ubuntu-test1:~#cd redis-7.2.0/
root@ubuntu-test1:~/redis-7.2.0# make -j 2 USE_SYSTEMD=yes PREFIX=/home/apps/redis install
root@ubuntu-test1:~# echo 'PATH=/home/apps/redis/bin:$PATH' > /etc/profile.d/redis.sh
root@ubuntu-test1:~#. /etc/profile.d/redis.sh
#优化参数,消除报警
root@ubuntu-test1:~# cat /proc/sys/net/core/somaxconn #需要大于128
4096root@ubuntu-test1:~# echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local
root@ubuntu-test1:~# chmod +x /etc/rc.local
root@ubuntu-test1:~# vim /etc/sysctl.conf
vm.overcommit_memory = 1
root@ubuntu-test1:~# sysctl -p
#创建Redis用户和Service文件
root@ubuntu-test1:~# useradd -r -s /sbin/nologin redis
root@ubuntu-test1:~# mkdir /home/apps/redis/{etc,data,log,run}
root@ubuntu-test1:~# cp /root/redis-7.2.0/redis.conf /home/apps/redis/etc/
root@ubuntu-test1:~# chown redis.redis -R /home/apps/redis/
root@ubuntu-test1:~#vim /lib/systemd/system/redis.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=/home/apps/redis/bin/redis-server /home/apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
LimitNOFILE=1000000
[Install]
WantedBy=multi-user.target
root@ubuntu-test1:~# systemctl daemon-reload
root@ubuntu-test1:~# systemctl enable --now redis.service
root@ubuntu-test1:~# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> info
Server
redis_version:7.2.0
......
Keyspace
127.0.0.1:6379> exit
#修改配置文件,开启远程端口
root@ubuntu-test1:~# vim /home/apps/redis/etc/redis.conf
bind 0.0.0.0
logfile "/home/apps/redis/log/redis.log"
save 3600 1 300 100 60 10000
dir /home/apps/redis/data
repl-diskless-sync no #取消无盘同步,使用硬盘同步
rename-command FLUSHALL "" #禁用该命令
rename-command SHUTDOWN ""
requirepass 123456
root@ubuntu-test1:~# systemctl restart redis.service
root@ubuntu-test1:~# grep -vE '^#|^$' /home/apps/redis/etc/redis.conf | grep slow
slowlog-log-slower-than 10000 #慢查询定义的时间
slowlog-max-len 128 #保留的最近慢查询记录上限
root@ubuntu-test1:~# redis-cli -a 123456
127.0.0.1:6379> slowlog len #查询慢查询条数
(integer) 0
127.0.0.1:6379> slowlog get #查看慢查询记录
6.2,Redis持久化
|---------------|------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| 方法 | RDB(Redis DataBase) | AOF(AppendOnlyFile) |
| 概念 | 基于某个时间点的快照, 只保留一个最新版本, 相当于MySQL 的完全备份 | 初次启动时进行完全备份, 后续将持续执行增量性备份 |
| 实现 方式 | save: 同步, 不推荐, 使用主进程完成,会阻赛其它命令 bgsave:异步后台执行 , 会开启子进程,不会阻赛其它命令 | bgrewriteaof:会自动开启,也可手动执行,对数据进行重新整理 |
| 优点 | 1,只保存某个时间点的数据,恢复无需额外操作,适合灾备处理 2,在大集群时恢复速度较AOF快 | 1,数据安全性相对较高,每秒自动执行 2,写入操作采用append模式,宕机也不会损坏数据 3,会自动重写,重写操作绝对安全 4,AOF有记录所有操作的日志文件,可用于数据重建 |
| 缺点 | 1,不能实时保存,存在少量数据丢失风险 2,在数据集较大时,子进程可能会非常耗时,导致客户端长时间等待 | 1,AOF会记录重复操作,数据量大 2,AOF在恢复大数据集的速度比 RDB慢 3,fsync策略是appendfsync no时, AOF保存到磁盘的速度可能会慢于RDB 4,更易出现BUG |
redis.conf内的RDB相关参数
save 3600 1 300 100 60 10000 #bgsave触发条件
dir /home/apps/redis/data #bgsave存放位置
dbfilename dump.rdb #RDB文件名
#正确开启AOF功能(RDB已开启且已有数据),先动态修改内存参数,再修改配置文件#AOF默认为关闭,初次开启并重启服务后,AOF会因为较高优先级先启动,AOF默认无数据文件会导致旧数据丢失
root@ubuntu-test1:~#ll /home/apps/redis/data/
-rw-r--r-- 1 redis redis 108 Oct 30 16:17 dump.rdb
root@ubuntu-test1:~# redis-cli -a 123456
127.0.0.1:6379>KEYS *
"b"
"a"
"c"
127.0.0.1:6379> CONFIG GET appendonly
"appendonly"
"no"
127.0.0.1:6379> CONFIG SET appendonly yes
OK
127.0.0.1:6379> exit
root@ubuntu-test1:~#ll /home/apps/redis/data/
drwxr-xr-x 2 redis redis 4096 Oct 30 16:40 appendonlydir/
-rw-r--r-- 1 redis redis 108 Oct 30 16:17 dump.rdb
root@ubuntu-test1:~# vim /home/apps/redis/etc/redis.conf
appendonly yes
#模拟服务重启,测试数据是否会丢失
root@ubuntu-test1:~# systemctl restart redis.service
root@ubuntu-test1:~# redis-cli -a 123456
127.0.0.1:6379> KEYS *
"a"
"c"
"b"
#Redis服务BGWRITEAOF配置介绍
root@ubuntu-test1:~# grep -vE '^#|^$' /home/apps/redis/etc/redis.conf|grep aof
appendfilename "appendonly.aof"
auto-aof-rewrite-percentage 100 #当增长超过100比例会触发执行
auto-aof-rewrite-min-size 64mb #触发的最小文件大小
aof-load-truncated yes #是否加载末尾异常的AOF文件(如断电,主进程kill)
aof-use-rdb-preamble yes
aof-timestamp-enabled no
aof-rewrite-incremental-fsync yes
root@ubuntu-test1:~# grep -vE '^#|^$' /home/apps/redis/etc/redis.conf|grep appendfsync
appendfsync everysec
no-appendfsync-on-rewrite no #是否暂缓AOF记录立即同步至磁盘,默认否最安全但是会造成阻塞;开启暂时会避免阻塞,但是Redis故障会导致数据丢失
6.3,Redis使用介绍
Redis常用命令:
INFO--显示Redis运行状态信息
SELECT--切换数据库
KEYS--查看当前数据库下的所有key,慎用
BGSAVE--手动执行RDB
DBSIZE --返回当前库下的所有key 数量
FLUSHDB --强制清空当前库中的所有key,慎用
FLUSHALL --删除所有数据,慎用
SHUTDOWN--关闭服务
TYPE--查询key的数据类型
|---------------|----------------------------------------|
| 数据类型 | 特点 |
| 字符串string | 基本数据类型,能包含任意类型的数据,单个值最大512M字节 |
| 列表list | 有序,可重复,可实现队列和栈 |
| 集合set | 无序,不可重复,实现集合操作(与sinter,或sunion,非sdiff) |
| 有序集合zset | 有序,无重复元素,由score(不可重复)和value组成,用于实现排行榜 |
| 字典hash | 无序,每个元素都是键值对,可存储复杂数据 |
七、实例--构建Redis主从哨兵模式
7.1,主从复制优化
Redis的主从同步是非阻塞的,即同步过程不会影响主服务器的正常访问;其主从复制分为全量同步和增量同步两种,主节点重启会导致全量同步,从节点重启只会导致增量同步。
全量复制触发情况:
1,从节点首次连接主节点;
2,从节点的复制偏移量不在复制积压缓冲区内;
3,从节点无法连接主节点超过一定的时间;
避免全量复制:
1,初次全量复制不可避免,后续全量复制可利用级联结构在低业务量时进行;
2,增大repl-backlog-size数值,避免复制积压缓冲区不足;3,节点RUN_ID不匹配:主节点重启导致RUN_ID变化,会触发全量复制,可用config命令动态修改配置。故障转移例如哨兵或集群选举新的主节点也不会全量复制(从主节点重启只会触发增量复制);
避免复制风暴:
1,单主节点复制风暴(当主节点重启,多从节点复制)
解决方法:使用级联复制
2,单机器多实例复制风暴(机器宕机后,大量全量复制)
解决方法:主节点分散多机器
7.2,常见主从复制故障
1,主从节点的maxmemory不一致,主节点内存大于从节点内存,主从复制可能丢失数据
2,rename-command命令不一致,错执行被禁用的命令会导致主从节点不同步
3,从节点配置的master密码错误,验证不通过,无法建立主从同步
4,Redis版本不同导致兼容问题
5,开启了安全模式且未开启远程设置,无法进行远程连接
7.3,实例--构筑主从哨兵模式
#ubuntu-test1--10.0.0.161
#ubuntu-test2--10.0.0.162
#ubuntu-test3--10.0.0.163
#为三台服务器编译安装Redis并保持redis.conf配置一致(注意,Redis密码需要相同)
#以162为主节点,163为从节点创建主从同步测试
root@ubuntu-test3:~# vim /home/apps/redis/etc/redis.conf #修改配置文件重启生效
replicaof 10.0.0.162 6379
masterauth 123456
root@ubuntu-test3:~# redis-cli -a 123456 #配置修改在从节点进行
127.0.0.1:6379> replicaof 10.0.0.162 6379 #在线修改配置
OK
127.0.0.1:6379> config set masterauth 123456
OK
127.0.0.1:6379> info replication
Replication
role:slave
master_host:10.0.0.162
master_port:6379
master_link_status:up
root@ubuntu-test2:~# redis-cli -a 123456 #登录主节点查看信息
127.0.0.1:6379>info replication
role:master
connected_slaves:1
slave0:ip=10.0.0.163,port=6379,state=online,offset=3290,lag=0
127.0.0.1:6379> set key1 1
root@ubuntu-test3:~# redis-cli -a 123456 get key1 #确认主节点数据同步
"1"
#取消163从节点
root@ubuntu-test3:~# redis-cli -a 123456 replicaof no one #在从节点执行取消主从命令
root@ubuntu-test3:~# redis-cli -a 123456 info replication #验证信息
Replication
role:master
connected_slaves:0
#正式搭建主从哨兵架构
#在所有节点配置下列信息
root@ubuntu-test1:~#vim /home/apps/redis/etc/redis.conf
replicaof 10.0.0.161 6379 #7.2版本主节点不能配置该项
masterauth 123456
requirepass 123456
root@ubuntu-test1:~# cp ./redis-7.2.0/sentinel.conf /home/apps/redis/etc/
root@ubuntu-test1:~# chown redis.redis /home/apps/redis/etc/sentinel.conf
root@ubuntu-test1:~# vim /home/apps/redis/etc/sentinel.conf
dir /home/apps/redis/data
logfile "/home/apps/redis/log/sentinel.log"
sentinel monitor mymaster 10.0.0.161 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 5000 #判断主节点下线时间5s
root@ubuntu-test1:~# systemctl restart redis.service
root@ubuntu-test1:~# vim /lib/systemd/system/redis-sentinel.service
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
ExecStart=/home/apps/redis/bin/redis-sentinel /home/apps/redis/etc/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
User=redis
Group=redis
RuntimeDirectory=redis RuntimeDirectory
Mode=0755
[Install]
WantedBy=multi-user.target
root@ubuntu-test1:~#systemctl enable --now redis-sentinel.service
root@ubuntu-test1:~#redis-cli -p 26379 info sentinel #查看哨兵状态
Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.161:6379,slaves=2,sentinels=3#停止主节点服务,验证哨兵机制
root@ubuntu-test1:~# systemctl stop redis.service
root@ubuntu-test2:~# redis-cli -a 123456 info replication
Replication
role:slave
master_host:10.0.0.163master_port:6379
master_link_status:up
root@ubuntu-test3:~# redis-cli -a 123456 info replication
Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.162,port=6379,state=online,offset=88277,lag=0
master_failover_state:no-failover
#重启启动ubuntu-test1上的Redis
root@ubuntu-test1:~# systemctl start redis.service
root@ubuntu-test1:~# redis-cli -a 123456 info replication
Replication
role:slave
master_host:10.0.0.163master_port:6379
master_link_status:up
root@ubuntu-test1:~# cat /home/apps/redis/etc/redis.conf | grep replicaof #哨兵自动修改配置文件
replicaof 10.0.0.163 6379
八、实例--三节点Redis集群搭建
哨兵只能解决Redis****高可用,实现自动故障转移,无法解决单主节点的写入性能瓶颈,使用分布式集群可解决该问题(建立Cluster时,节点需要清空数据,且网络中不能有哨兵主从)
#ubuntu-test1--10.0.0.161--Redis主节点
#ubuntu-test2--10.0.0.162--Redis主节点
#ubuntu-test3--10.0.0.163--Redis主节点
#ubuntu-test--10.0.0.160--安装多实例Redis做从节点
#在10.0.0.161/162/163主节点上修改配置文件
root@ubuntu-test1:~# vim /home/apps/redis/etc/redis.conf
masterauth "123456"
requirepass "123456"
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-require-full-coverage no
#在10.0.0.160上配置多实例
root@ubuntu:~# vim /home/apps/redis/etc/redis6379.conf
bind 0.0.0.0
port 6379
pidfile "/var/run/redis_6379.pid"
logfile "/home/apps/redis/log/redis6379.log"
dbfilename "dump6379.rdb"
masterauth "123456"
requirepass "123456"
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-require-full-coverage no
root@ubuntu:~# sed 's/6379/6380/' /home/apps/redis/etc/redis6379.conf > /home/apps/redis/etc/redis6380.conf
root@ubuntu:~# sed 's/6379/6381/' /home/apps/redis/etc/redis6379.conf > /home/apps/redis/etc/redis6381.conf
root@ubuntu:~# vim /lib/systemd/system/redis6379.service
......
ExecStart=/home/apps/redis/bin/redis-server /home/apps/redis/etc/redis6379.conf --supervised systemd
......
root@ubuntu:~#sed 's/6379/6380/' /lib/systemd/system/redis6379.service > /lib/systemd/system/redis6380.service
root@ubuntu:~# sed 's/6379/6381/' /lib/systemd/system/redis6379.service > /lib/systemd/system/redis6381.service
root@ubuntu:~#systemctl daemon-reload
root@ubuntu:~# systemctl enable --now redis6379.service redis6380.service redis6381.service
root@ubuntu:~#tree /home/apps/redis/
/home/apps/redis/
├── bin
│ ├── redis-benchmark
│ ├── redis-check-aof -> redis-server
│ ├── redis-check-rdb -> redis-server
│ ├── redis-cli
│ ├── redis-sentinel -> redis-server
│ └── redis-server
├── data
│ ├── nodes-6379.conf
│ ├── nodes-6380.conf
│ └── nodes-6381.conf
├── etc
│ ├── redis6379.conf
│ ├── redis6380.conf
│ └── redis6381.conf
├── log
│ ├── redis6379.log
│ ├── redis6380.log
│ ├── redis6381.log
│ └── redis.log
└── run
root@ubuntu-test1:~# redis-cli -a 123456 --cluster create 10.0.0.161:6379 10.0.0.162:6379 10.0.0.163:6379 10.0.0.160:6379 10.0.0.160:6380 10.0.0.160:6381 --cluster-replicas 1 #组建集群
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.0.0.160:6380 to 10.0.0.161:6379
Adding replica 10.0.0.160:6381 to 10.0.0.162:6379
Adding replica 10.0.0.160:6379 to 10.0.0.163:6379
M: d48544aa7962934c443741a43f88cbb38cb5244d 10.0.0.161:6379
slots:[0-5460],[7365],[15495] (5461 slots) master
M: c954b82ff2f86fc5feecca51b6e481010e98dc3c 10.0.0.162:6379
slots:[3300],[5461-10922],[15495] (5462 slots) master
M: fba93a9b96fff704a86b66fbf83ffb33824bc466 10.0.0.163:6379
slots:[3300],[7365],[10923-16383] (5461 slots) master
S: ddc047ac5f0ef2bdc1e77076aace31ecc219d7fa 10.0.0.160:6379
replicates fba93a9b96fff704a86b66fbf83ffb33824bc466
S: bfd046c0b9f4ac6318cfb218edb2327d8b2d5daa 10.0.0.160:6380
replicates d48544aa7962934c443741a43f88cbb38cb5244d
S: 7f2e05c72c2c54eece48a908d0a3c59662d0f8c7 10.0.0.160:6381
replicates c954b82ff2f86fc5feecca51b6e481010e98dc3c
Can I set the above configuration? (type 'yes' to accept): yes
root@ubuntu-test1:~# cat /home/apps/redis/data/nodes-6379.conf #节点信息存放文件
root@ubuntu-test1:~# redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
15af0ab4decfe08de958223266efb401dd29b377 10.0.0.161:6379@16379 myself,master - 0 1730704529000 1 connected 0-5460
60d3a2d1b5c24e03683e7453e7c05f6b6ebdeb56 10.0.0.162:6379@16379 master - 0 1730704533365 2 connected 5461-10922
148d09fcaa36daeb8ab367338eede0f6a01dd941 10.0.0.160:6381@16381 slave 60d3a2d1b5c24e03683e7453e7c05f6b6ebdeb56 0 1730704531000 2 connected
d8ee0bd1c084a34e3a77ebfc860156ea44a54644 10.0.0.160:6380@16380 slave 15af0ab4decfe08de958223266efb401dd29b377 0 1730704531000 1 connected
be21431937366822cb55ef481d9562c0e9253583 10.0.0.160:6379@16379 slave 40d8dfe76324fab1925bf1c457eb4aaf2f9b9ac4 0 1730704532328 3 connected
40d8dfe76324fab1925bf1c457eb4aaf2f9b9ac4 10.0.0.163:6379@16379 master - 0 1730704531291 3 connected 10923-16383
root@ubuntu-test1:~# redis-cli -a 123456 -c #-c自动跳转槽位
127.0.0.1:6379> set a 1-> Redirected to slot [15495] located at 10.0.0.163:6379
OK
10.0.0.163:6379> set z 2-> Redirected to slot [8157] located at 10.0.0.162:6379
OK
10.0.0.162:6379>get a-> Redirected to slot [15495] located at 10.0.0.163:6379
"1"
**Redis cluster的从节点是只读连接的,也就是说集群模式中的从节点是拒绝任何读写请求的。并且当多个节点运行一段时间后,可能会出现倾斜现象,**某个节点数据偏多,内存消耗更大,或者用户请求访问更多,主要原因如下:
节点和槽分配不均
不同槽对应键值数量差异较大
包含bigkey,建议少用
内存相关配置不一致
热点数据不均衡 : 一致性不高时,可以使用本缓存和MQ