Nginx负载均衡概述
负载均衡简介
- 大型网站面临的挑战
大型网站都要面对庞大的用户量,高并发,海量数据等挑战。为了提升系统整体的性能,可以采用垂直扩展和水平扩展两种方式。
垂直扩展:在网站发展早期,可以从单机的角度通过增加硬件处理能力,比如 CPU 处理能力,内存容量,磁盘等方面,实现服务器处理能力的提升。但是,单机是有性能瓶颈的,一旦触及瓶颈,再想提升,付出的成本和代价会极高。这显然不能满足大型分布式系统(网站)所有应对的大流量,高并发,海量数据等挑战。
水平扩展:通过集群来分担大型网站的流量。集群中的应用服务器(节点)通常被设计成无状态,用户可以请求任何一个节点,这些节点共同分担访问压力。水平扩展有两个要点:
1.应用集群:将同一应用部署到多台机器上,组成处理集群,接收负载均衡设备分发的请求,进行处理,并返回相应数据。
2.负载均衡:将用户访问请求,通过某种算法,分发到集群中的节点
- 什么是负载均衡
负载均衡(Load Balance,简称 LB)是高并发、高可用系统必不可少的关键组件,目标是尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性。
负载均衡的主要作用如下:
1.**高并发:**负载均衡通过算法调整负载,尽力均匀的分配应用集群中各节点的工作量,以此提高应用集群的并发处理能力(吞吐量)。
2.**伸缩性:**添加或减少服务器数量,然后由负载均衡进行分发控制。这使得应用集群具备伸缩性。
3.**高可用:**负载均衡器可以监控候选服务器,当服务器不可用时,自动跳过,将请求分发给可用的服务器。这使得应用集群具备高可用的特性。
4.**安全防护:**有些负载均衡软件或硬件提供了安全性功能,如:黑白名单处理、防火墙,防 DDos 攻击等。
为什么要使用负载均衡
- 当我们的Web服务器直接面向用户,往往要承载大量并发请求,单台服务器难以负荷,我们使用多台Web服务器组成集群,前端使用Nginx负载均衡,将请求分散的打到我们的后端服务器集群中,实现负载的分发。那么会大大提升系统的吞吐率、请求性能、高容灾
- 往往我们接触的最多的是
SLB(Server Load Balance)
负载均衡,实现最多的也是SLB
、那么SLB
它的调度节点和服务节点通常是在一个地域里面。那么它在这个小的逻辑地域里面决定了他对部分服务的实时性、响应性是非常好的。 - 所以说当海量用户请求过来以后,它同样是请求调度节点,调度节点将用户的请求转发给后端对应的服务节点,服务节点处理完请求后在转发给调度节点,调度节点最后响应给用户节点。这样也能实现一个均衡的作用,那么Nginx则是一个典型的 SLB。
- 负载均衡的叫法有很多
- 负载均衡
- Load Balance
- LB
- 公有云中叫法
- SLB 阿里云负载均衡
- QLB 青云负载均衡
- CLB 腾讯云负载均衡
- ULB ucloud负载均衡
- 常见的负载均衡的软件
- Nginx
- Haproxy
- LVS
四层负载均衡与七层负载均衡
4层负载均衡本质是转发,而7层负载均衡本质是内容交换和代理
四层负载均衡
所谓四层负载均衡指的是 OSI 七层模型中的传输层,那么传输层Nginx已经能支持TCP/IP的控制,所以只需要对客户端的请求进行TCP/IP协议的包转发就可以实现负载均衡,那么它的好处是性能非常快、只需要底层进行应用处理,而不需要进行一些复杂的逻辑。
七层负载均衡
七层负载均衡它是在应用层,那么它可以完成很多应用方面的协议请求,比如我们说的http应用的负载均衡,它可以实现http信息的改写、头信息的改写、安全应用规则控制、URL匹配规则控制、以及转发、rewrite等等的规则,所以在应用层的服务里面,我们可以做的内容就更多,那么Nginx则是一个典型的七层负载均衡 SLB
值得一提的是:没有四层负载均衡就一定不会有七层负载均衡
四层负载均衡与七层负载均衡的对比
7层负载均衡相较于4层负载均衡在更耗费性能的同时,也获得了更加智能的优点,由于在应用层进行识别,所以7层负载均衡可以基于不同的协议(如http、radius、dns等)进行负载,也可以根据应用层协议中有意义的内容来进行负载,如:除了根据IP加端口进行负载外,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。
而4层负载均衡基本就是基于 IP + 端口进行负载均衡了。
四层负载均衡数据包在底层就进行了分发,而七层负载均衡数据包则是在最顶层进行分发、由此可以看出,七层负载均衡效率没有四负载均衡高。
但七层负载均衡更贴近于服务,如:http协议就是七层协议,我们可以用Nginx可以作会话保持,URL路径规则匹配、head头改写等等,这些是四层负载均衡无法实现的。
注意:四层负载均衡不识别域名,七层负载均衡识别域名
Nginx负载均衡配置场景
Nginx要实现负载均衡需要用到 proxy_pass
代理模块配置.
Nginx负载均衡与Nginx代理不同地方在于,Nginx的一个 location 仅能代理一台服务器,而Nginx负载均衡则是将客户端请求代理转发至一组upstream虚拟服务池
Nginx upstream虚拟配置语法
Syntax: upstream name { ... }
Default: -
Context: http
#upstream例
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
环境准备
角色 | 地址 | 主机名 |
---|---|---|
LB01 | ens33:192.168.175.10 | lb01 |
web01 | ens33:192.168.175.20 | web01 |
web02 | ens33:192.168.175.30 | web02 |
Web01服务器上配置nginx
[root@web01 ~]# cd /etc/nginx/conf.d/
[root@web01 conf.d]# vim node.conf
server {
listen 80;
server_name node.test.com;
location / {
root /code/node;
index index.html;
}
}
[root@web01 conf.d]# mkdir -p /code/node
[root@web01 conf.d]# echo "web01 ..." > /code/node/index.html
[root@web01 conf.d]# systemctl restart nginx
Web02服务器上配置nginx
[root@web02 ~]# cd /etc/nginx/conf.d/
[root@web02 conf.d]# vim node.conf
server {
listen 80;
server_name node.test.com;
location / {
root /code/node;
index index.html;
}
}
[root@web02 conf.d]# mkdir -p /code/node
[root@web02 conf.d]# echo "web02 ..." > /code/node/index.html
[root@web02 conf.d]# systemctl restart nginx
配置Nginx负载均衡
[root@lb01 ~]# cd /etc/nginx/conf.d/
[root@lb01 conf.d]# vim /etc/nginx/proxy_params
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;
[root@lb01 conf.d]# vim node_proxy.conf
upstream node {
server 192.168.175.20:80;
server 192.168.175.30:80;
}
server {
listen 80;
server_name node.test.com;
location / {
proxy_pass http://node;
include proxy_params;
}
}
[root@lb01 conf.d]# nginx -t
[root@lb01 conf.d]# systemctl restart nginx
打开浏览器访问:http://node.test.com
负载均衡常见典型故障
如果后台服务连接超时,Nginx是本身是有机制的,如果出现一个节点down掉的时候,Nginx会根据你具体负载均衡的设置,将请求转移到其他的节点上,但是,如果后台服务连接没有down掉,但是返回错误异常码了如:504、502、500,这个时候你需要加一个负载均衡的设置,如下:
proxy_next_upstream http_500 | http_502 | http_503 | http_504 |http_404;意思是,当其中一台返回错误码404,500…等错误时,可以分配到下一台服务器程序继续处理,提高平台访问成功率。
server {
listen 80;
server_name node.test.com;
location / {
proxy_pass http://node;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404;
}
}
Nginx负载均衡调度算法
调度算法 | 概述 |
---|---|
轮询rr | 按时间顺序逐一分配到不同的后端服务器(默认) |
weight | 加权轮询,weight值越大,分配到的访问几率越高 |
ip_hash | 每个请求按访问IP的hash结果分配,这样来自同一IP的固定访问一个后端服务器 |
url_hash | 按照访问URL的hash结果来分配请求,是每个URL定向到同一个后端服务器 |
least_conn | 最少链接数,那个机器链接数少就分发 |
Nginx负载均衡[rr]轮询具体配置
upstream load_pass {
server 192.168.175.10:80;
server 192.168.175.20:80;
}
Nginx负载均衡[wrr]权重轮询具体配置
upstream load_pass {
server 192.168.175.10:80 weight=5;
server 192.168.175.20:80;
}
Nginx负载均衡ip_hash
- 具体配置不能和weight一起使用。
#如果客户端都走相同代理, 会导致某一台服务器连接过多
upstream load_pass {
ip_hash;
server 192.168.175.10:80;
server 192.168.175.20:80;
}
Nginx负载均衡后端状态
- 后端Web服务器在前端Nginx负载均衡调度中的状态
状态 | 概述 |
---|---|
down | 当前的server暂时不参与负载均衡 |
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后, 服务暂停时间 |
max_conns | 限制最大的接收连接数 |
测试down状态测试该Server不参与负载均衡的调度
upstream load_pass {
server 192.168.175.10:80 down;#不参与任何调度, 一般用于停机维护
server 192.168.175.20:80;
}
测试backup以及down状态
upstream load_pass {
server 192.168.175.10:80 backup;
server 192.168.175.20:80 max_fails=1 fail_timeout=10s;
}
location / {
proxy_pass http://load_pass;
include proxy_params;
}
测试max_fails失败次数和fail_timeout多少时间内失败多少次则标记down
upstream load_pass {
server 192.168.175.10:80;
server 192.168.175.20:80 max_fails=2 fail_timeout=10s;
}
测试max_conns最大TCP连接数
upstream load_pass {
server 192.168.175.10:80;
server 192.168.175.20:80 max_conns=1;
}
Nginx负载均衡会话保持
- 在使用负载均衡的时候会遇到会话保持的问题,可通过如下方式进行解决
- 使用nginx的ip_hash,根据客户端的IP,将请求分配到对应的IP上
- 基于服务端的session会话共享(NFS,MySQL,memcache,redis,file)
- 在解决负载均衡会话问题,我们需要了解session和cookie的区别。
- 浏览器端存的是cookie每次浏览器发请求到服务端时,报文头是会自动添加cookie信息的。
- 服务端会查询用户的cookie作为key去存储里找对应的value(session)
- 同一域名下的网站的cookie都是一样的,所以无论几台服务器,无论请求分配到哪一台服务器上同一用户的cookie是不变的。也就是说cookie对应的session也是唯一的。所以,这里只要保证多台业务服务器访问同一个共享存储服务器(NFS,MySQL,memcache,redis,file)就行了。
会话保持配置
- 配置Nginx(两台机器都要配置)
[root@web01 ~]# vim /etc/nginx/conf.d/php.conf
server {
listen 80;
server_name php.test.com;
root /code/phpMyAdmin-4.8.4-all-languages;
location / {
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
[root@web01 ~]# nginx -t
[root@web01 ~]# systemctl restart nginx
[root@web02 ~]# vim /etc/nginx/conf.d/php.conf
server {
listen 80;
server_name php.test.com;
root /code/phpMyAdmin-4.8.4-all-languages;
location / {
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
[root@web02 ~]# nginx -t
[root@web02 ~]# systemctl restart nginx
安装phpmyadmin
web01和web02上都装
- 使用第三方扩展源安装php7.1
[root@localhost ~]# vim /etc/yum.repos.d/php.repo
[php]
name = php Repository
baseurl = https://repo.webtatic.com/yum/el7/x86_64/
gpgcheck = 0
[root@localhost ~]# yum install -y epel-release
[root@localhost ~]#yum -y install php71w php71w-cli php71w-common php71w-devel php71w-embedded php71w-gd php71w-mcrypt php71w-mbstring php71w-pdo php71w-xml php71w-fpm php71w-mysqlnd php71w-opcache php71w-pecl-memcached php71w-pecl-redis php71w-pecl-mongodb unzip
- 配置php-fpm用户与nginx的运行用户保持一致
[root@localhost ~]# sed -i '/^user/c user = nginx' /etc/php-fpm.d/www.conf
[root@localhost ~]# sed -i '/^group/c user = nginx' /etc/php-fpm.d/www.conf
- 启动php-fpm并加入开机自启
[root@localhost ~]# systemctl start php-fpm
[root@localhost ~]# systemctl enable php-fpm
- 安装mariadb数据库(可以在负载均衡服务器上安装)
[root@localhost ~]# yum install mariadb-server mariadb -y
[root@localhost ~]# systemctl start mariadb
[root@localhost ~]# systemctl enable mariadb
[root@localhost ~]# mysqladmin password '123456'
[root@localhost ~]# mysql -uroot -p123456
MariaDB [(none)]> grant all privileges on *.* to root@'%' identified by '123456' with grant option;
登录mysql中开启root的远程登录权限,否则phpmyadmin上连接不了mysql
- 安装phpmyadmin
[root@web01 ~]# cd /code
[root@web01 code]# wget https://files.phpmyadmin.net/phpMyAdmin/4.8.4/phpMyAdmin-4.8.4-all-languages.zip
[root@web01 code]# unzip phpMyAdmin-4.8.4-all-languages.zip
- 配置phpmyadmin连接远程的数据库,这个数据库可以安装在代理服务器上后做测试
[root@web01 code]# cd phpMyAdmin-4.8.4-all-languages/
[root@web01 phpMyAdmin-4.8.4-all-languages]# cp config.sample.inc.php config.inc.php
[root@web01 phpMyAdmin-4.8.4-all-languages]# vim config.inc.php
$cfg['Servers'][$i]['host'] = '192.168.175.10'
- 配置权限
[root@web01 ~]# chown -R nginx.nginx /var/lib/php/
此时访问http://php.test.com/index.php是可以的,但登录不进去
需要使用redis解决会话登录问题
使用浏览器访问页面,获取cookie信息
- 查看服务器上的session(会话)
[root@web01 ~]# ll /var/lib/php/session/
总用量 4
-rw------- 1 nginx nginx 2625 7月 11 20:08
sess_aa3bdfab93197f49bbfddb15cb41a595
- 使用
scp
可以跨会话将web01上配置好的phpmyadmin以及nginx的配置文件推送到web02主机上
[root@web01 code]# scp -rp phpMyAdmin-4.8.4-all-languages root@192.168.175.30:/code/
[root@web01 code]# scp /etc/nginx/conf.d/php.conf root@192.168.175.30:/etc/nginx/conf.d/
- 在web02上重启Nginx服务
[root@web02 ~]# systemctl restart nginx
- 在web02上配置权限
[root@web02 ~]# chown -R nginx.nginx /var/lib/php/
- 接入负载均衡
[root@lb01 ~]# vim /etc/nginx/conf.d/proxy_php.com.conf
upstream php {
server 192.168.175.20:80;
server 192.168.175.30:80;
}
server {
listen 80;
server_name php.test.com;
location / {
proxy_pass http://php;
include proxy_params;
}
}
[root@lb01 ~]# nginx -t
[root@lb01 ~]# systemctl restart nginx
- 使用负载均衡的轮询功能之后,会发现,如果将session保存在本地文件的话,永远都登录不上去。
使用redis解决会话登录问题
- 安装redis内存数据库
[root@lb01 ~]#yum -y install make gcc tcl
[root@lb01 ~]#wget https://download.redis.io/releases/redis-5.0.9.tar.gz
[root@lb01 ~]#tar xf redis-5.0.9.tar.gz
[root@lb01 ~]#vim redis_install.sh
#!/bin/bash
. /etc/init.d/functions
VERSION=redis-5.0.9
DIR1=/apps/redis
PASSWORD=centos
install() {
yum -y install make wget gcc tcl &> /dev/null || { action "安装所需包失败,请检测包或网>络配置" false;exit;}
wget http://download.redis.io/releases/${VERSION}.tar.gz &> /dev/null || {action "Redis 源码下载失败" false; exit; }
tar xf $VERSION.tar.gz
cd $VERSION/
make -j 2 &> /dev/null && make PREFIX=${DIR1} install &> /dev/null && action "Redis 编译
安装成功" || { action "Redis 编译安装失败" false;exit; }
ln -s ${DIR1}/bin/* /usr/bin/
mkdir -p ${DIR1}/{etc,data,log,run}
cd
cp $VERSION/redis.conf $DIR1/etc
sed -i -e "s/bind 127.0.0.1/bind 0.0.0.0/" -e "/# requirepass/a requirepass ${PASSWORD}" -e "/^dir .*/c dir ${DIR1}/data/" -e "/logfile .*/c logfile ${DIR1}/log/redis_6379.log" -e "/^pidfile .*/c pidfile ${DIR1}/run/redis_6379.pid" ${DIR1}/etc/redis.conf
if id redis &> /dev/null;then
action "redis 用户已经存在" false
else
useradd -r -s /sbin/nologin redis
action "redis 用户创建成功"
fi
chown -R redis.redis ${DIR1}
cat >> /etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOF
sysctl -p
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
/etc/rc.d/rc.local
cat > /lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=${DIR1}/bin/redis-server ${DIR1}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now redis &> /dev/null && action "redis 服务启动成功" || { action "redis 服务启动失败" false;exit; }
}
install
[root@lb01 ~]#sh redis_install.sh
[root@lb01 ~]# redis-cli -a centos
-
php配置session连接redis
php的配置文件的注解方式是在代码前加
;
[root@web01 ~]# vim /etc/php.ini
session.save_handler = redis
session.save_path = "tcp://192.168.175.10:6379"
;session.save_path = "tcp://192.168.175.10:6379?auth=centos" #如果redis存在密
码,则使用该方式
session.auto_start = 1 #开启session.auto_start的优点在于,任何时候都不会因忘记执行
session_start()或session_start()在程序里的位置不对,而导致错误;缺点在于,如果你使用的
是第三方代码,则必须删去其中的全部 session_start(),否则将不能得到正确的结果。
[root@web01 ~]# vim /etc/php-fpm.d/www.conf
#注释php-fpm.d/www.conf里面的两条内容,否则session内容会一直写入/var/lib/php/session
目录中
;php_value[session.save_handler] = files
;php_value[session.save_path] = /var/lib/php/session
- 重启php-fpm nginx
[root@web01 ~]# systemctl restart php-fpm
[root@web01 ~]# systemctl restart nginx
- 将web01上配置好的文件推送到web02
[root@web01 ~]# scp /etc/php.ini root@192.168.175.30:/etc/php.ini
[root@web01 ~]# scp /etc/php-fpm.d/www.conf root@192.168.175.30:/etc/php-fpm.d/www.conf
- 在web02上重启php-fpm nginx
[root@web02 ~]# systemctl restart php-fpm
[root@web02 ~]# systemctl restart nginx
- redis查看数据
[root@lb01 ~]# redis-cli -a centos
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:7e772fe37b1488069e3c54e419df7eda"
Nginx四层负载均衡概述
四层负载均衡是基于传输层协议包来封装的(如:TCP/IP),那我们前面使用到的七层是指的应用层,他的组装在四层的基础之上,无论四层还是七层都是指的OSI网络模型。
四层+七层来做负载均衡,四层可以保证七层的负载均衡的高可用性;如:nginx就无法保证自己的服务高可用,需要依赖LVS或者keepalive。
如:tcp协议的负载均衡,有些请求是TCP协议的(mysql、ssh),或者说这些请求只需要使用四层进行端口的转发就可以了,所以使用四层负载均衡。
四层+七层构建大规模集群架构使用场
四层负载均衡总结
- 四层负载均衡仅能转发TCP/IP协议、UDP协议、通常用来转发端口,如:tcp/22、udp/53;
- 四层负载均衡可以用来解决七层负载均衡端口限制问题;(七层负载均衡最大使用65535个端口号)
- 四层负载均衡可以解决七层负载均衡高可用问题;(多台后端七层负载均衡能同时的使用)
- 四层的转发效率比七层的高得多,但仅支持tcp/ip协议,不支持http和https协议;
- 通常大并发场景通常会选择使用在七层负载前面增加四层负载均衡。
Nginx四层负载均衡场景实践
Nginx如何配置四层负载均衡
1、通过访问负载均衡的5555端口,实际是后端的web01的22端口在提供服务;
2、通过访问负载均衡的6666端口,实际是后端的mysql的3306端口在提供服务。
- 创建存放四层负载均衡配置文件的目录
[root@lb01 ~]# vim /etc/nginx/nginx.conf
include /etc/nginx/conf.c/*.conf;
#include /etc/nginx/conf.d/*.conf;
[root@lb01 ~]# mkdir /etc/nginx/conf.c
- 配置四层负载均衡
[root@lb01 ~]# vim /etc/nginx/conf.c/lb_domain.conf
stream {
upstream lb {
server 192.168.175.20:80 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.175.30:80 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 8080;
proxy_connect_timeout 3s;
proxy_timeout 3s;
proxy_pass lb;
}
}
- 四层负载均衡开启日志
- 四层负载均衡是没有access的日志的,因为在nginx.conf的配置中,access的日志格式是配置在http下的,而四层负载均衡配置是在http以外的
- 如果需要日志则需要配置在stream下面
[root@lb01 ~]# cd /etc/nginx/conf.c/
[root@lb01 conf.c]# vim lb_domain.conf
stream {
log_format proxy '$remote_addr $remote_port -[$time_local] $status
$protocol ' '"$upstream_addr" "$upstream_bytes_sent" "$upstream_connect_time"';
access_log /var/log/nginx/proxy.log proxy;
upstream lb {
server 192.168.175.20:80 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.175.30:80 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 8080;
proxy_connect_timeout 3s;
proxy_timeout 3s;
proxy_pass lb;
}
}
[root@lb01 conf.c]# nginx -t
[root@lb01 conf.c]# systemctl restart nginx
- 浏览器访问域名或者IP,查看日志
[root@lb01 conf.c]# tail -f /var/log/nginx/proxy.log
192.168.175.1 55295 - [11/Jul/2021:23:27:09 +0800] 200 TCP "192.168.175.20:80" "0" "0.001"
192.168.175.1 64066 - [11/Jul/2021:23:27:13 +0800] 200 TCP "192.168.175.30:80" "0" "0.000"
192.168.175.1 58528 - [11/Jul/2021:23:27:16 +0800] 200 TCP "192.168.175.20:80" "0" "0.001"
192.168.175.1 65099 - [11/Jul/2021:23:27:20 +0800] 200 TCP "192.168.175.30:80" "0" "0.000"
192.168.175.1 55919 - [11/Jul/2021:23:27:20 +0800] 200 TCP "192.168.175.20:80" "6460" "0.001"
Nginx四层负载均衡端口转发
- 使用nginx四层负载均衡实现tcp的转发
请求负载均衡 5555 ---> 192.168.175.20:22;
请求负载均衡 6666 ---> 192.168.175.30:3306;
- 配置nginx四层负载均衡实现tcp的转发
[root@lb01 ~]# vim /etc/nginx/conf.c/lb_domain.conf
stream {
log_format proxy '$remote_addr $remote_port - [$time_local] $status $protocol '
'"$upstream_addr" "$upstream_bytes_sent" "$upstream_connect_time"' ;
access_log /var/log/nginx/proxy.log proxy;
#定义转发ssh的22端口
upstream ssh {
server 192.168.175.20:22;
}
#定义转发mysql的3306端口
upstream mysql {
server 192.168.175.30:3306;
}
server {
listen 5555;
proxy_connect_timeout 3s;
proxy_timeout 300s;
proxy_pass ssh;
}
server {
listen 6666;
proxy_connect_timeout 3s;
proxy_timeout 3s;
proxy_pass mysql;
}
}
[root@lb01 ~]# nginx -t
[root@lb01 ~]# systemctl restart nginx
- 测试
使用xshell测试ssh
ssh root@192.168.175.10 5555
命令行测试mysql连接
[root@web02 conf.d] # mysql -uroot -p123456 -h192.168.175.10 -P6666 -e"select user,host from mysql.user;"
Keepalived 高可用基本概述
一般是指2台机器启动着完全相同的业务系统,当有一台机器down机了,另外一台服务器就能快速的接管,对于访问的用户是无感知的。
硬件通常使用F5
软件通常使用keppalived
keepalived软件是基于VRRP协议实现的,VRRP虚拟路由冗余协议,主要用于解决单点故障问题
VRRP原理
-
VRRP协议是一种容错的主备模式的协议,保证当主机的下一跳路由出现故障时,由另一台路由器来代替出现故障的路由器进行工作,通过VRRP可以在网络发生故障时透明的进行设备切换而不影响主机之间的数据通信。
-
虚拟路由器:VRRP组中所有的路由器,拥有虚拟的IP+MAC(00-00-5e-00-01-VRID)地址
-
主路由器:虚拟路由器内部通常只有一台物理路由器对外提供服务,主路由器是由选举算法产生,对外提供各种网络功能。
-
备份路由器:VRRP组中除主路由器之外的所有路由器,不对外提供任何服务,只接受主路由的通告,当主路由器挂掉之后,重新进行选举算法接替master路由器。
-
选举机制
- 优先级
- 抢占模式下,一旦有优先级高的路由器加入,即成为Master
- 非抢占模式下,只要Master不挂掉,优先级高的路由器只能等待
-
三种状态
- Initialize状态:系统启动后进入initialize状态
- Master状态
- Backup状态
拓扑:
模拟R3为外网,R1,R2为你的两台网关路由器
R1
R1(config-if)#int e0/0
R1(config-if)#ip add 100.13.13.1 255.255.255.0
R1(config-if)#no sh
R1(config)#int e0/1
R1(config-if)#ip add 192.168.1.2 255.255.255.0
R1(config-if)#no sh
R1(config-if)#exit
R1(config)#access-list 1 per 192.168.1.0 /24
R1(config)#ip nat in so li 1 int e0/0 ov
R1(config)#int e0/0
R1(config-if)#ip nat out
R1(config-if)#int e0/1
R1(config-if)#ip nat in
R1(config)#ip route 0.0.0.0 0.0.0.0 100.13.13.3
R2
R2(config)#int e0/0
R2(config-if)#ip add 100.23.23.2 255.255.255.0
R2(config-if)#no sh
R2(config-if)#int e0/1
R2(config-if)#ip add 192.168.1.3 255.255.255.0
R2(config-if)#no sh
R2(config)#access-list 1 per 192.168.1.0 /24
R2(config)#ip nat in so li 1 int e0/0 ov
R2(config)#int e0/0
R2(config-if)#ip nat out
R2(config-if)#int e0/1
R2(config-if)#ip nat in
R2(config)#ip route 0.0.0.0 0.0.0.0 100.23.23.3
R3
R3(config)#int e0/0
R3(config-if)#ip add 100.13.13.3 255.255.255.0
R3(config-if)#no sh
R3(config-if)#int e0/1
R3(config-if)#ip add 100.23.23.3 255.255.255.0
R3(config-if)#no sh
R3(config-if)#int lo0
R3(config-if)#ip add 3.3.3.3 255.255.255.0
测试网络连通性
R1#ping 3.3.3.3
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds:
.!!!!
Success rate is 80 percent (4/5), round-trip min/avg/max = 1/1/2 ms
R2#ping 3.3.3.3
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds:
.!!!!
Success rate is 100 percent (4/5), round-trip min/avg/max = 1/1/1 ms
SW 配置dhcp:
Switch>en
Switch#conf t
Switch(config)#int vlan 1
Switch(config-if)#ip add 192.168.1.254 255.255.255.0
Switch(config-if)#no sh
Switch(config)#ip dhcp pool cisco
Switch(dhcp-config)#network 192.168.1.0 /24
Switch(dhcp-config)#default-router 192.168.1.1
Switch(dhcp-config)#ip dhcp excluded-address 192.168.1.1 192.168.1.100
开启vrrp:
R1(config)#int e0/1
R1(config-if)#vrrp 1 ip 192.168.1.1
R2(config)#int e0/1
R2(config-if)#vrrp 1 ip 192.168.1.1
pc:
ping 192.168.1.1
arp -a
查看vrrp竞选规则
R1#show vrrp br
Interface Grp Pri Time Own Pre State Master addr Group addr
Et0/1 1 100 3609 Y Backup 192.168.1.3 192.168.1.1
R2#show vrrp br
Interface Grp Pri Time Own Pre State Master addr Group addr
Et0/1 1 100 3609 Y Master 192.168.1.3 192.168.1.1
R1(config)#int e0/1
R1(config-if)#vrrp 1 priority 110
#R1手动提升优先级
R1#show vrrp br
Interface Grp Pri Time Own Pre State Master addr Group addr
Et0/1 1 110 3570 Y Master 192.168.1.2 192.168.1.1
测试:
pc:
ping 3.3.3.3 -t
R1(config)#int e0/1
R1(config-if)#sh
R1(config-if)#int e0/0
R1(config-if)#sh
#这种情况比较坑,不会发现断了,就没有自动切换,可以利用track追踪的方式去降低优先级来实现切
换主备
R1(config)#track 1 interface e0/0 line-protocol
R1(config-track)#int e0/1
R1(config-if)#vrrp 1 track 1 decrement 50
#惩罚优先级下降50
pc:
tacert 3.3.3.3
R1(config-if)#int e0/0
R1(config-if)#no sh
R1(config-if)#sh
同理也可以给R2配置上
R2(config)#track 1 interface e0/0 line-protocol
R2(config-track)#int e0/1
R2(config-if)#vrrp 1 track 1 decrement 50
Keepalived高可用安装配置
安装keepalived
[root@lb01 ~]# yum install -y keepalived
[root@lb02 ~]# yum install -y keepalived
配置master
- 找到配置文件
[root@lb02 ~]# rpm -qc keepalived
/etc/keepalived/keepalived.conf
/etc/sysconfig/keepalived
- 修改配置
[root@lb01 ~]# vim /etc/keepalived/keepalived.conf
global_defs { #全局配置
router_id lb01 #标识身份->名称
}
vrrp_instance VI_1 {
state MASTER #标识角色状态
interface ens33 #网卡绑定接口
virtual_router_id 50 #虚拟路由id
priority 150 #优先级
advert_int 1 #监测间隔时间
#use_vmac #使用虚拟mac地址,因为路由问题,可能导致原本的IP不可用
authentication { #认证
auth_type PASS #认证方式
auth_pass 1111 #认证密码
}
virtual_ipaddress {
192.168.175.100 #虚拟的VIP地址
}
}
配置backup
[root@lb02 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
router_id lb02
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 50
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.175.100
}
}
对比master与Backup的keepalived配置区别
Keepalived配置区别 | Master节点配置 | Backup节点配置 |
---|---|---|
route_id(唯一标识) | router_id lb01 | router_id lb02 |
state(角色状态) | state MASTER | state BACKUP |
priority(竞选优先级) | priority 150 | priority 100 |
启动Master和Backup节点的keepalived
[root@lb01 ~]# systemctl start keepalived
[root@lb01 ~]# systemctl enable keepalived
[root@lb02 ~]# systemctl start keepalived
[root@lb02 ~]# systemctl enable keepalived
高可用keepalived抢占式与非抢占式
- 由于节点1的优先级高于节点2,所以VIP在节点1上面,记得关闭防火墙selinux,否则会发现两个上都有vip(虚拟ip)
[root@lb01 ~]# ip addr |grep 192.168.175.100
inet 192.168.175.100/32 scope global ens33
#在节点2上是grep不出来的
- 关闭节点1的keepalived
[root@lb01 ~]# systemctl stop keepalived
- 节点2联系不上节点1,主动接管VIP
[root@lb02 ~]# ip addr |grep 192.168.175.100
inet 192.168.175.100/32 scope global ens33
- 此时重新启动Master上的keepalived,会发现VIP被强行抢占
[root@lb01 ~]# systemctl start keepalived
[root@lb01 ~]# ip addr |grep 192.168.175.100
inet 192.168.175.100/32 scope global ens33
- 配置非抢占式
- 两个节点的state都必须配置为BACKUP
- 两个节点都必须加上配置 nopreempt
- 其中一个节点的优先级必须要高于另外一个节点的优先级。
- 两台服务器都角色状态启用nopreempt后,必须修改角色状态统一为BACKUP,唯一的区分就是优先级。
Master配置
vrrp_instance VI_1 {
state BACKUP #修改为BACKUP
priority 150
nopreempt #加上这行
}
Backup配置
vrrp_instance VI_1 {
state BACKUP
priority 100
nopreempt #加上这行
}
systemctl restart keepalived
- 通过windows的arp去验证,是否会切换MAC地址
# 当前master在lb01上
[root@lb01 ~]# ip addr |grep 192.168.175.100
inet 192.168.175.100/32 scope global ens33
# windows查看mac地址
C:\Users\Aaron>arp -a |findstr 192.168.175.100
192.168.175.100 00-0c-29-bb-9a-49 动态
- 关闭lb01的keepalive
[root@lb01 ~]# systemctl stop keepalived
- lb02接管vIP
[root@lb02 ~]# ip addr |grep 192.168.175.100
inet 192.168.175.100/32 scope global ens33
- 再次查看windows的mac地址
C:\Users\Aaron>arp -a |findstr 192.168.175.100
192.168.175.100 00-0c-29-bb-9a-bb 动态
- 看到的是两次mac地址发生了变化,因为虚拟机的bug,无法实现ma地址不变,正常情况下开启use_vmac使用虚拟的mac地址后mac地址不会发生改变
高可用keepalived故障脑裂
由于某些原因,导致两台keepalived高可用服务器在指定时间内,无法检测到对方的心跳,各自取得资源及服务的所有权,而此时的两台高可用服务器又都还活着。
脑裂故障原因
- 服务器网线松动等网络故障
- 服务器硬件故障发生损坏现象而崩溃
- 主备都开启了firewalld防火墙
脑裂故障现象
- 正常情况下backup以监听为主,所以抓包会看到只有master在发送vrrp的数据包
- 打开设备的防火墙,查看抓包情况,可以看到两台设备认为自己是master
[root@lb01 ~]# ip a |grep 192.168.175.100
inet 192.168.175.100/24 scope global secondary ens33
[root@lb02 ~]# ip a |grep 192.168.175.100
inet 192.168.175.100/24 scope global secondary ens33
解决脑裂故障方案
- 如果发生脑裂,则随机kill掉一台即可
- 在backup上编写检测脚本, 测试如果能ping通master并且backup节点还有vIP的话则认为产生了脑裂
[root@lb02 ~]# vim check_split_brain.sh
#!/bin/sh
vip=192.168.175.100
lb01_ip=192.168.175.10
while true;do
ping -c 2 $lb01_ip &>/dev/null
if [ $? -eq 0 -a `ip add|grep "$vip"|wc -l` -eq 1 ];then
echo "ha is split brain.warning."
systemctl stop keepalived
else
echo "ha is ok"
fi
sleep 5
done
测试:
在lb02运行好脚本后再打开lb02的防火墙,这时与lb01连接不上发生脑裂,脚本开始报错
高可用keepalived与nginx
Nginx默认监听在所有的IP地址上,VIP会飘到一台节点上,相当于那台nginx多了VIP这么一个网卡,所以可以访问到nginx所在机器
但是…如果nginx宕机,会导致用户请求失败,但是keepalived没有挂掉不会进行切换,所以需要编写一个脚本检测Nginx的存活状态,如果不存活则kill掉keepalived
- 先给两台机器都装上nginx
yum install -y epel-release
yum install -y nginx
systemctl enable nginx --now
lb01:
echo "in lb01" > /usr/share/nginx/html/index.html
lb02:
echo "in lb02" > /usr/share/nginx/html/index.html
访问192.168.175.100的效果就是in lb01,但是如果关闭lb01的keepalived,就变成in lb02
但是如果nginx挂了,网页将会无法正常访问
- 用脚本解决nginx挂了vip没有切换的问题
[root@lb01 ~]# vim check_web.sh
#!/bin/sh
nginxpid=$(ps -C nginx --no-header|wc -l)
#1.判断Nginx是否存活,如果不存活则尝试启动Nginx
if [ $nginxpid -eq 0 ];then
systemctl start nginx
sleep 3
#2.等待3秒后再次获取一次Nginx状态
nginxpid=$(ps -C nginx --no-header|wc -l)
#3.再次进行判断, 如Nginx还不存活则停止Keepalived,让地址进行漂移,并退出脚本
if [ $nginxpid -eq 0 ];then
systemctl stop keepalived
fi
fi
[root@lb01 ~]#systemctl stop nginx
[root@lb01 ~]# watch -n 5 "sh /root/check_web.sh"
再次访问192.168.175.100发现仍然可以访问,因为脚本又把nginx开启了
集群和分布式
系统性能扩展方式:
- Scale UP:垂直扩展,向上扩展,增强,性能更强的计算机运行同样的服务,成本高。
- Scale Out:水平扩展,向外扩展,增加设备,并行地运行多个服务调度分配问题,Cluster
垂直扩展不再提及:
- 随着计算机性能的增长,其价格会成倍增长
- 单台计算机的性能是有上限的,不可能无限制地垂直扩展
- 多核CPU意味着即使是单台计算机也可以并行的。
集群 Cluster
Cluster:集群,为解决某个特定问题将多台计算机组合起来形成的单个系统
Cluster分为三种类型:
- LB:Load Balancing,负载均衡。调度负载,按照算法调度。
- HA:High Availiablity,高可用,避免SPOF(single Point Of failure)(单点失败)
- MTBF:Mean Time Between Failure 平均无故障时间
- MTTR:Mean Time To Restoration( repair)平均恢复前时间
- A=MTBF/(MTBF+MTTR) (0,1):99%,99.5%,99.9%,99.99%,99.999%
- HPC:High-performance computing,高性能 www.top500.org
分布式系统
分布式存储: Ceph,GlusterFS,FastDFS,MogileFS
分布式计算:hadoop,Spark
分布式常见应用
分布式应用-服务按照功能拆分,使用微服务
分布式静态资源–静态资源放在不同的存储集群上
分布式数据和存储–使用key-value缓存系统
分布式计算–对特殊业务使用分布式计算,比如Hadoop集群
集群和分布式
集群:同一个业务系统,部署在多台服务器上。集群中,每一台服务器实现的功能没有差别,数据和代码都是一样的
分布式:一个业务被拆成多个子业务,或者本身就是不同的业务,部署在多台服务器上。分布式中,每一台服务器实现的功能是有差别的,数据和代码也是不一样的,分布式每台服务器功能加起来,才是完整的业务。
分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。
对于大型网站,访问用户很多,实现一个群集,在前面部署一个负载均衡服务器,后面几台服务器完成同一业务。如果有用户进行相应业务访问时,负载均衡器根据后端哪台服务器的负载情况,决定由给哪一台去完成响应,并且一台服务器垮了,其它的服务器可以顶上来。分布式的每一个节点,都完成不同的业务,如果一个节点垮了,那这个业务可能就会失败。
集群设计原则
可扩展性—集群的横向扩展能力。小型机横向扩展小,面临淘汰
可用性—无故障时间(SLA)
性能—访问响应时间
容量—单位时间内的最大并发吞吐量(C10K 并发问题) 。LVS内核级,并发好。
集群设计实现
基础设施层面
提升硬件资源性能—从入口防火墙到后端web server均使用更高性能的硬件资源
多域名—DNS 轮询A记录解析。指向不同IP 访问入口增多
多入口—将A记录解析到多个公网IP入口
多机房—同城+异地容灾
CDN(Content Delivery Network)—基于GSLB(Global Server Load Balance)实现全局负载均衡,如:DNS
就近分配地址,提高效率
业务层面
分层:安全层、负载层、静态层、动态层、(缓存层、存储层)持久化与非持久化
分割:基于功能分割大业务为小服务
分布式:对于特殊场景的业务,使用分布式计
LB Cluster 负载均衡集群
按实现方式划分
- 硬件(大公司)
- F5 Big-IP
- Citrix Netscaler
- A10
- 软件(小公司)
- lvs:Linux Virtual Server,阿里四层SLB (Server Load Balance)使用下四层功能:物理层 数据链路层
- nginx:支持七层调度,阿里七层SLB使用Tengine
- haproxy:支持七层调度
- ats:Apache Traffic Server,yahoo捐助给apache
- perlbal:Perl 编写
- pound
基于工作的协议层次划分
- 传输层(通用):DNAT和DPORT
- LVS:Linux Virtual Server
- nginx:stream
- haproxy:mode tcp
- 应用层(专用):针对特定协议,常称为 proxy server
- http:nginx, httpd, haproxy(mode http), …
- fastcgi:nginx, httpd, …
- mysql:mysql-proxy, …
负载均衡的会话保持
- session sticky:同一用户调度固定服务器
- Source IP:LVS sh算法(对某一特定服务而言)
- Cookie
- session replication:每台服务器拥有全部session
- session multicast cluster (内存消耗大)
- session server:专门的session服务器
- Memcached,Redis (只放session,共享)也存在单点失败,即也要做集群哨兵机制
HA 高可用集群实现
keepalived:vrrp协议
Ais:应用接口规范
heartbeat
cman+rgmanager(RHCS)
coresync_pacemaker
Linux Virtual Server简介
LVS概述
LVS简介
负载调度器,内核集成
阿里的四层SLB(Server Load Balance)是基于LVS+keepalived实现。
LVS,是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项目。LVS由用户空间的ipvsadm和内核空间的IPVS组成,ipvsadm用来定义规则,IPVS利用ipvsadm定义的规则工作。现在LVS已经是 Linux标准内核的一部分,在Linux2.4内核以前,使用LVS时必须要重新编译内核以支持LVS功能模块,但是从Linux2.4内核以后,已经完全内置了LVS的各个功能模块,无需给内核打任何补丁,可以直接使用LVS提供的各种功能。
LVS特点
通过LVS提供的负载均衡技术和Linux操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。LVS的主要特点有以下几个方面:
- 高并发连接:LVS基于内核网络层面工作,有超强的承载能力和并发处理能力。单台LVS负载均衡器,可支持上万并发连接。稳定性强:是工作在网络4层之上仅作分发之用,这个特点也决定了它在负载均衡软件里的性能最强,稳定性最好,对内存和cpu资源消耗极低。
- 成本低廉:硬件负载均衡器少则十几万,多则几十万上百万,LVS只需一台服务器和就能免费部署使用,性价比极高。
- 配置简单:LVS配置非常简单,仅需几行命令即可完成配置,也可写成脚本进行管理。
- 支持多种算法:支持多种论调算法,可根据业务场景灵活调配进行使用
- 支持多种工作模型:可根据业务场景,使用不同的工作模式来解决生产环境请求处理问题。
- 应用范围广:因为LVS工作在4层,所以它几乎可以对所有应用做负载均衡,包括http、数据库、DNS、ftp服务等等
- 缺点:工作在4层,不支持7层规则修改,机制过于庞大,不适合小规模应用。
LVS常见术语
名称 | 解释 |
---|---|
ipvsadm | 用户空间的命令行工具,用于管理集群服务及集群服务上的RS等; |
IPVS | 工作于内核上的netfilter INPUT HOOK之上的程序,可根据用户定义的集群实现请求转发; |
VS | Virtual Server ,虚拟服务 |
Director, Balancer | 负载均衡器、分发器 |
RS | Real Server 后端请求处理服务器 负责真正的服务 |
CIP | Client IP,客户端IP |
VIP | Director Virtual IP,负载均衡器虚拟IP |
DIP | Director IP,负载均衡器IP |
RIP | Real Server IP,后端请求处理服务器IP |
访问流程:CIP <–> VIP == DIP <–> RIP
LVS组成
LVS 由2部分程序组成,包括 ipvs 和 ipvsadm。
-
IPVS(ip virtual server):一段代码工作在内核空间,叫IPVS,是真正生效实现调度的代码。IPVS的总体结构主要由IP包处理、负载均衡算法、系统配置与管理三个模块及虚拟服务器与真实服务器链表组成。
-
ipvsadm:另外一段是工作在用户空间,叫ipvsadm,即IPVS管理器,负责为ipvs内核框架编写规则,定义谁是集群服务,而谁是后端真实的服务器(Real Server)。
LVS基本原理
VS根据请求报文的目标IP和目标协议及端口将其调度转发至某RS,根据调度算法来挑选RS。LVS是内核级功能,工作在INPUT链的位置,将发往INPUT的流量进行“处理”
查看内核支持LVS
[root@localhost ~]# grep -i -C 10 ipvs /boot/config-3.10.0-957.el7.x86_64
1.当用户向负载均衡器(Director Server)发起请求,调度器将请求发往内核空间
2.PREROUTING链首先会接收到用户请求,判断目标ip确定是本机ip,将数据包发往INPUT链
3.IPVS是工作在INPUT链上的,当用户请求到达INPUT时,IPVS会将用户请求和自己已经定义好的集群服务进行比对,如果用户请求的就是定义的集群服务,那么此时IPVS会强行修改数据包里的目标IP地址及端口,并将新的数据包发往POSTROUTING链
4.POSTROUTING链接收数据包后发现目标ip地址刚好是自己的后端服务器,那么此时通过选路,将数据包最终发送给后端。
LVS集群体系架构
LVS 功能及组织架构
下面摘自于阿里云:https://help.aliyun.com/document_detail/27543.html?spm=5176.21213303.J_6028563670.7.505a3edaQq9WLJ&scm=20140722.S_help%40%40%E6%96%87%E6%A1%A3%40%4027543.S_0.ID_27543-OR_s%2Bhelpproduct-V_1-P0_0
负载均衡的应用场景为高访问量的业务,提高应用程序的可用性和可靠性。
应用于高访问量的业务
如果您的应用访问量很高,可以通过配置监听规则将流量分发到不同的云服务器 ECS(ElasticCompute Service 弹性计算服务)实例上。此外,可以使用会话保持功能将同一客户端的请求转发到同一台后端ECS
扩展应用程序
可以根据业务发展的需要,随时添加和移除ECS实例来扩展应用系统的服务能力,适用于各种Web服务器和App服务器。
消除单点故障
可以在负载均衡实例下添加多台ECS实例。当其中一部分ECS实例发生故障后,负载均衡会自动屏蔽故障的ECS实例,将请求分发给正常运行的ECS实例,保证应用系统仍能正常工作,LVS自身做不到,需要配合keepalive软件。
同城容灾 (多可用区容灾)
为了提供更加稳定可靠的负载均衡服务,阿里云负载均衡已在各地域部署了多可用区以实现同地域容灾。当主可用区出现机房故障或不可用时,负载均衡仍然有能力在非常短的时间内(如:大约30s中断)切换到另外一个备可用区恢复服务能力;当主可用区恢复时,负载均衡同样会自动切换到主可用区提供服务。
使用负载均衡时,您可以将负载均衡实例部署在支持多可用区的地域以实现同城容灾。此外,建议您结合自身的应用需要,综合考虑后端服务器的部署。如果您的每个可用区均至少添加了一台ECS实例,那么此种部署模式下的负载均衡服务的效率是最高的。
如下图所示,在负载均衡实例下绑定不同可用区的ECS实例。正常情况下,用户访问流量将同时转至发主、备可用区内的ECS实例;当可用区A发生故障时,用户访问流量将只转发至备可用区内的ECS实例。此种部署既可以避免因为单个可用区的故障而导致对外服务的不可用,也可以通过不同产品间可用区的选择来降低延迟。
如果您采取如下图所示的部署方案,即在负载均衡实例的主可用区下绑定多台ECS实例,而在备可用区没有任何ECS实例。当主可用区发生故障时会造成业务中断,因为备可用区没有ECS实例来接收请求。这样的部署方式很明显是以牺牲高可用性为代价来获取低延时。
跨地域容灾
您可以在不同地域下部署负载均衡实例,并分别挂载相应地域内不同可用区的ECS。上层利用云解析做智能DNS,将域名解析到不同地域的负载均衡实例服务地址下,可实现全局负载均衡。当某个地域出现不可用时,暂停对应解析即可实现所有用户访问不受影响
LVS应用场景
音视频/游戏等大并发流量场景
音视频/游戏等行业经常面临突发访问,海量流量,后端服务压力大。如短视频/长视频/直播/在校教育/游戏等业务中,由于服务端与用户端之间需要实时大量的互动,因此,用户流量非常大,而音视频业务的波峰波谷效应明显,这对整个系统的性能、弹性、稳定性和可用性带来了巨大的挑战,需要使用负载均衡进行流量分发
零售/金融/企业等弹性高可靠场景
新零售新金融业务变化快,新业务上线、老业务调整时常发生,大促大型活动常态化;因此,对即开即用网络,快速交付能力,弹性伸缩能力,安全可靠、灵活计费等需求显著,需要使用负载均衡搭建高可靠架构。
云原生网络应用场景
随着云原生逐步成熟,互联网/金融/企业等诸多行业新建业务时选择云原生部署,或对现有业务进行云原生化改造。无论是使用阿里云ACK/ASK/SAE还是开源K8S,云原生网络均可用到负载均衡服务来实现流量调度。
跨地域网络应用场景
跨地域跨可用区的容灾方案。互联网/金融/企业等业务逐步遍及全球,需要将不同地域用户智能调度访问到相应的业务系统,为了降本增效,线下IDC业务需要与云上业务互通,需要使用负载均衡构建跨地域或混合云容灾架构.
LVS工作模式
LVS集群的工作模式
lvs-nat:修改请求报文的目标IP,多目标IP的DNAT
lvs-dr:操纵封装新的MAC地址。MAC头的修改
lvs-tun:在原请求IP报文之外新加一个IP首部。
lvs-fullnat:修改请求报文的源和目标IP
NAT模式
lvs-nat:本质是多目标IP的DNAT,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和PORT实现转发
1.当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。此时报文的源ip为CIP,目标ip为VIP
2.PREROUTING检查发现数据包的目标ip是本机,将数据包送至INPUT链
3.IPVS比对数据包请求的服务是否为集群服务,若是,修改数据包的目标ip地址为后端服务器ip,然后将数据包发送至POSTROUTING链。此时报文的源ip为CIP,目标ip为RIP
4.POSTROUTING链通过选路,将数据包发送给Real Server
5.Real Server比对发现目标为自己的ip,开始构建响应报文发回给Director Server。此时报文的源ip为RIP,目标ip为CIP
6.Director Server在响应客户端前,此时会将源ip地址修改为自己的VIP地址,然后响应给客户端。此时报文的源ip为VIP,目标ip为CIP
NAT模式特性
- RIP最好是内网IP
- RS的网关必须指向DIP
- DIP和RIP必须在同一个网段内
- 请求和回应的报文都必须经过director,director容易成为瓶颈
- nat支持端口转发
- VS必须是Linux系统,RS可以是任意OS系统
DR模式
LVS-DR:Direct Routing,直接路由,LVS默认模式,应用最广泛,通过为请求报文重新封装一个MAC首部进行转发,源MAC是DIP所在的接口的MAC,目标MAC是某挑选出的RS的RIP所在接口的MAC地址;
源IP/PORT,以及目标IP/PORT均保持不变
1.首先用户用CIP请求VIP。
2.根据上图可以看到,不管是Director Server还是Real Server上都需要配置相同的VIP,那么当用户请求到达我们的集群网络的前端路由器的时候,请求数据包的源地址为CIP目标地址为VIP,此时路由器会发广播问谁是VIP,那么我们集群中所有的节点都配置有VIP,此时谁先响应路由器那么路由器就会将用户请求发给谁,这样一来我们的集群系统是不是没有意义了,那我们可以在网关路由器上配置静态路由指定VIP就是Director Server,或者使用一种机制不让Real Server 接收来自网络中的ARP地址解析请求,这样一来用户的请求数据包都会经过Director Servrer。
3.当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP。
4.PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链。
5.IPVS比对数据包请求的服务是否为集群服务,若是,将请求报文中的源MAC地址修改为DIP的MAC地址,将目标MAC地址修改RIP的MAC地址,然后将数据包发至POSTROUTING链。 此时的源IP和目的IP均未修改,仅修改了源MAC地址为DIP的MAC地址,目标MAC地址为RIP的MAC地址
6.由于DS和RS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MAC地址为RIP的MAC地址,那么此时数据包将会发至Real Server。
7.RS发现请求报文的MAC地址是自己的MAC地址,就接收此报文。处理完成之后,将响应报文通过lo接口传送给eth0网卡然后向外发出。 此时的源IP地址为VIP,目标IP为CIP
8.响应报文最终送达至客户端。
配置DR有三种方式:
- 第一种方式:
在路由器上明显说明vip对应的地址一定是Director上的MAC,只要绑定,以后再跟vip通信也不用再请求了,这个绑定是静态的,所以它也不会失效,也不会再次发起请求,但是有个前提,我们的路由设备必须有操作权限能够绑定MAC地址,万一这个路由器是运行商操作的,我们没法操作怎么办?第一种方式固然很简便,但未必可行。
- 第二种方式:
在一些主机上(例如:红帽),它们引进的有一种程序arptables,它有点类似于iptables,它肯定是基于arp或基于MAC做访问控制的,很显然我们只需要在每一个real server上定义arptables规则,如果用户arp广播请求的目标地址是本机的vip则不予相应,或者说相应的报文不让出去,很显然网关(gateway)是接受不到的,也就是director相应的报文才能到达gateway,这个也行。第二种方式我们可以基于arptables。
- 第三种方式:
在相对较新的版本中新增了两个内核参数(kernelparameter),第一个是arp_ignore定义接受到ARP请求时的相应级别;第二个是arp_announce定义将自己地址向外通告时的通告级别。【提示:很显然我们现在的系统一般在内核中都是支持这些参数的,我们用参数的方式进行调整更具有朴实性,它还不依赖于额外的条件,像arptables,也不依赖外在路由配置的设置,反而通常我们使用的是第三种配置】
arp_ignore:定义接受到ARP请求时的相应级别:
0: 只要本地配置的有相应地址,就给予响应。(默认)
1: 仅回应目标IP地址是本地的入网地址的arp请求。
2: 仅回应目标IP地址是本地的入网地址,而且源IP和目标IP在同一个子网的arp请求。
3: 不回应该网络界面的arp请求,而只对设置的唯一和连接地址做出回应
4-7:保留未使用
8: 不回应所有的arp请求。
arp_announce:定义将自己地址向外通告是的通告级别:
0: 将本地任何接口上的任何地址向外通告
1: 试图仅向目标网络通告与其网络匹配的地址
2: 仅向与本地接口上地址匹配的网络进行通告
DR模式特性
-
保证前端路由将目标地址为VIP报文统统发给Director Server,而不是RS。
-
Director和RS的VIP为同一个VIP。
-
RS可以使用私有地址;也可以是公网地址,如果使用公网地址,此时可以通过互联网对RIP进行直接访问。
-
RS跟Director Server必须在同一个物理网络中。
-
所有的请求报文经由Director Server,但响应报文必须不能进过Director Server。
-
不支持地址转换,也不支持端口映射
-
RS可以是大多数常见的操作系统
-
RS的网关绝不允许指向DIP(因为我们不允许他经过director)
-
RS上的lo接口配置VIP的IP地址
-
DR模式是市面上用得最广的。
-
缺陷:RS和DS必须在同一机房中
-
确保前端路由器将目标IP为VIP的请求报文发往Director三种方法
1.在前端网关做静态绑定VIP和Director的MAC地址(这样防止路由器将请求转发给rs主机)
此方法一般不使用,过于固定
2.在RS上使用arptables工具
arptables -A IN -d $VIP -j DROP
arptables -A OUT -s $VIP -j mangle --mangle-ip-s $RIP #不响应数据包
3.在RS上修改内核参数以限制arp通告及应答级别
/proc/sys/net/ipv4/conf/all/arp_ignore
/proc/sys/net/ipv4/conf/all/arp_announce
- RS的RIP可以使用私网地址,也可以是公网地址;RIP与DIP在同一IP网络;RIP的网关不能指向DIP,以确保响应报文不会经由Director
- RS和Director要在同一个物理网络(物理连接)
- physical network由电缆线路、调制解调器或其他硬件连接起来的设备所构成的网络,一个物理网络能包含一个或几个逻辑网络。
- 请求报文要经由Director,但响应报文不经由Director,而由RS直接发往Client
- 不支持端口映射(端口不能修改)
- RS可使用大多数OS系统
Tun模式
转发方式:不修改请求报文的IP首部(源IP为CIP,目标IP为VIP),而在原IP报文之外再封装一个IP首部(源IP是DIP,目标IP是RIP),将报文发往挑选出的目标RS;RS直接响应给客户端(源IP是VIP,目标IP是CIP)
1.当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP 。
2.PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链。
3.IPVS比对数据包请求的服务是否为集群服务,若是,在请求报文的首部再次封装一层IP报文,封装源IP为为DIP,目标IP为RIP。然后发至POSTROUTING链。 此时源IP为DIP,目标IP为RIP。
4.POSTROUTING链根据最新封装的IP报文,将数据包发至RS(因为在外层封装多了一层IP首部,所以可以理解为此时通过隧道传输)。 此时源IP为DIP,目标IP为RIP。
5.RS接收到报文后发现是自己的IP地址,就将报文接收下来,拆除掉最外层的IP后,会发现里面还有一层IP首部,而且目标是自己的lo接口VIP,那么此时RS开始处理此请求,处理完成之后,通过lo接口送给eth0网卡,然后向外传递。 此时的源IP地址为VIP,目标IP为CIP
6.响应报文最终送达至客户端
Tunnel模式特性
- RIP、VIP、DIP全是公网地址。
- RS的网关不会也不可能指向DIP
- 所有的请求报文经由Director Server,但响应报文必须不能进过Director Server
- 不支持端口映射
- RS的系统必须支持隧道功能
LVS-Tun工作原理
场景非常少,主要用来解决DR和RS必须要在同一个物理网络中的问题;主要使用tun技术去封装IP报头
在VS/NAT的集群系统中,请求和响应的数据报文都需要通过负载调度器,当真实服务器的数目在10台和20台之间时,负载调度器将成为整个集群系统的新瓶颈。大多数Internet服务都有这样的特点:请求报文较短而响应报文往往包含大量的数据。如果能将请求和响应分开处理,即在负载调度器中只负责调度请求而响应直接返回给客户,将极大地提高整个集群系统的吞吐量。
IP隧道(IP tunneling)是将一个IP报文封装在另一个IP报文的技术,这可以使得目标为一个IP地址的数据报文能被封装和转发到另一个IP地址。IP隧道技术亦称为IP封装技术(IP encapsulation)。IP隧道主要用于移动主机和虚拟私有网络(Virtual Private Network),在其中隧道都是静态建立的,隧道一端有一个IP地址,另一端也有唯一的IP地址。
我们利用IP隧道技术将请求报文封装转发给后端服务器,响应报文能从后端服务器直接返回给客户。但在这里,后端服务器有一组而非一个,所以我们不可能静态地建立一一对应的隧道,而是动态地选择一台服务器,将请求报文封装和转发给选出的服务器。这样,我们可以利用IP隧道的原理将一组服务器上的网络服务组成在一个IP地址上的虚拟网络服务。
FULLNAT模式
- 通过同时修改请求报文的源IP地址和目标IP地址进行转发
- CIP --> DIP
- VIP --> RIP
- fullnat模式特点:
- VIP是公网地址,RIP和DIP是私网地址,且通常不在同一IP网络;因此,RIP的网关一般不会指向DIP
- RS收到的请求报文源地址是DIP,因此,只需响应给DIP;但Director还要将其发往Client
- 请求和响应报文都经由Director
- 支持端口映射
- 注意:此类型kernel默认不支持
无论是 DR 还是 NAT 模式,不可避免的都有一个问题:LVS 和 RS 必须在同一个 VLAN 下,否则 LVS 无法作为 RS 的网关。
Full-NAT 相比 NAT 的主要改进是,在 SNAT/DNAT 的基础上,加上另一种转换,转换过程如下:
1.在包从 LVS 转到 RS 的过程中,源地址从客户端 IP 被替换成了 LVS 的内网ip。
2.内网 IP 之间可以通过多个交换机跨 VLAN 通信。
3.当RS处理完接收到的包,返回时,会将这个包返回给LVS的内网ip,这一步也不受限于VLAN。
4.LVS 收到包后,在 NAT 模式修改源地址的基础上,再把 RS 发来的包中的目标地址从 LVS 内网 IP 改为客户端的 IP。
Full-NAT 主要的思想是把网关和其下机器的通信,改为了普通的网络通信,从而解决了跨 VLAN 的问题。采用这种方式,LVS 和 RS 的部署在 VLAN 上将不再有任何限制,大大提高了运维部署的便利性。
fullnat模式和nat模式相似,但是与nat不同的是nat模式只做了两次地址转换,fullnat模式却做了四次
LVS工作模式总结和比较
NAT | TUN | DR | |
---|---|---|---|
Real server | any | Tunneling | Non-arp device |
Real server network | private | LAN/WAN | LAN |
Real Server number | low(10-20) | High(100) | High(100) |
Real server gateway | load balancer | own router | own router |
优点 | 端口转换 | WAN | 性能最好 |
缺点 | 性能瓶颈 | 支持隧道 | 不支持跨网段 |
- vs-nat与lvs-fullnat:
- 请求和响应报文都经由Director
- lvs-nat:RIP的网关要指向DIP
- lvs-fullnat:RIP和DIP未必在同一IP网络,但要能通信
- lvs-dr与lvs-tun:
- 请求报文要经由Director,但响应报文由RS直接发往Client
- lvs-dr:通过封装新的MAC首部实现,通过MAC网络转发
- lvs-tun:通过在原IP报文外封装新IP头实现转发,支持远距离通信
LVS的调度算法
静态调度算法:rr(轮询),wrr(加权轮询),dh(目标地址散列调度算法),sh(源地址散列调度算法)
动态调度算法:wlc(加权最少连接数),lc(最少连接数),lblc(基于局限性的最少连接调度算法),lblcr(基于地址的带重复最小连接数调度)
静态调度算法:即调度器不会去判断后端服务器的繁忙与否,一如既往得将请求派发下去。
动态调度算法:调度器会去判断后端服务器的繁忙程度,然后依据调度算法动态得派发请求。
rr:轮询(round robin)
这种算法是最简单的,就是按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点就是简单。轮询算法假设所有的服务器处理请求的能力都是一样的,调度器会将所有的请求平均分配给每个真实服务器,不管后端 RS 配置和处理能力,非常均衡地分发下去。这个调度的缺点是,不管后端服务器的繁忙程度是怎样的,调度器都会讲请求依次发下去。如果A服务器上的请求很快请求完了,而B服务器的请求一直持续着,将会导致B服务器一直很忙,而A很闲,这样便没起到均衡的左右。
wrr:加权轮询(weight round robin)
这种算法比 rr 的算法多了一个权重的概念,可以给 RS 设置权重,权重越高,那么分发的请求数越多,权重的取值范围 0 – 100。主要是对rr算法的一种优化和补充, LVS 会考虑每台服务器的性能,并给每台服务器添加要给权值,如果服务器A的权值为1,服务器B的权值为2,则调度到服务器B的请求会是服务器A的2倍。权值越高的服务器,处理的请求越多。
dh:目标地址散列调度算法 (destination hash)
简单的说,即将同一类型的请求分配给同一个后端服务器,例如将以 .jgp、.png等结尾的请求转发到同一个节点。这种算法其实不是为了真正意义的负载均衡,而是为了资源的分类管理。这种调度算法主要应用在使用了缓存节点的系统中,提高缓存的命中率。
sh:源地址散列调度算法(source hash)
即将来自同一个ip的请求发给后端的同一个服务器,如果后端服务器工作正常没有超负荷的话。这可以解决session共享的问题,但是这里有个问题,很多企业、社区、学校都是共用的一个IP,这将导致请求分配的不均衡。
lc:最少连接数(least-connection)
这个算法会根据后端 RS 的连接数来决定把请求分发给谁,比如 RS1 连接数比 RS2 连接数少,那么请求就优先发给 RS1。这里问题是无法做到会话保持,即session共享。
wlc:加权最少连接数(weight least-connection)
这个比最少连接数多了一个加权的概念,即在最少连接数的基础上加一个权重值,当连接数相近,权重值越大,越优先被分派请求。
lblc:基于局部性的最少连接调度算法(locality-based least-connection)
将来自同一目的地址的请求分配给同一台RS如果这台服务器尚未满负荷,否则分配给连接数最小的RS,并以它为下一次分配的首先考虑。
lblcr:基于地址的带重复最小连接数调度 (Locality-Based Least-Connection with Replication)
这个算法是请求数据包的目标 IP 地址的一种调度算法,该算法先根据请求的目标 IP 地址寻找最近的该目标 IP 地址所有使用的服务器,如果这台服务器依然可用,并且有能力处理该请求,调度器会尽量选择相同的服务器,否则会继续选择其它可行的服务器
sed:最少期望延迟
不考虑非活动链接,谁的权重大,优先选择权重大的服务器来接收请求,但权重大的机器会比较忙
nq:永不排队
无需队列,如果有realserver的连接数为0就直接分配过去
LVS 相关软件
程序包
- Unit File: ipvsadm.service
- 主程序:/usr/sbin/ipvsadm
- 规则保存工具:/usr/sbin/ipvsadm-save
- 规则重载工具:/usr/sbin/ipvsadm-restore
- 配置文件:/etc/sysconfig/ipvsadm-config
准备三台机器:
[root@localhost ~]# yum ‐y install ipvsadm #远程ssh连接下使用这个命令会出bug,需要直接在虚拟机里使用命令
[root@localhost ~]# cat /usr/lib/systemd/system/ipvsadm.service
[Unit]
Description=Initialise the Linux Virtual Server
After=syslog.target network.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c "exec /sbin/ipvsadm-restore < /etc/sysconfig/ipvsadm"
ExecStop=/bin/bash -c "exec /sbin/ipvsadm-save -n > /etc/sysconfig/ipvsadm"
ExecStop=/sbin/ipvsadm -C
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
ipvsadm 命令
- ipvsadm核心功能:
- 集群服务管理:增、删、改
- 集群服务的RS管理:增、删、改
- 查看
#管理集群服务
ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask]
[--pe persistence_engine] [-b sched-flags]
ipvsadm -A #创建集群
ipvsadm -E #修改集群
ipvsadm -D -t|u|f service-address #删除
ipvsadm –C #清空
ipvsadm –R #重载
ipvsadm -S [-n] #保存
ipvsadm -L #查看
#管理集群中的RS
ipvsadm -a|e -t|u|f service-address -r server-address [options]
ipvsadm -d -t|u|f service-address -r server-address
ipvsadm -L|l [options]
ipvsadm -Z [-t|u|f service-address] #清空计数器
#保存规则
‐S
# ipvsadm ‐S > /path/to/somefile
载入此前的规则:
‐R
# ipvsadm ‐R < /path/form/somefile
- 说明
service-address:
-t|u|f:
-t: TCP协议的端口,VIP:TCP_PORT 如:-t 192.168.175.20:80
-u: UDP协议的端口,VIP:UDP_PORT 如:-u 192.168.175.20:80
-f:firewall MARK,标记,一个数字
[-s scheduler]:指定集群的调度算法,默认为wlc
server-address:
rip[:port] 如省略port,不作端口映射
选项:
lvs类型:
-g: gateway, dr类型,默认
-i: ipip, tun类型
-m: masquerade, nat类型
-w weight:权重
- 举例
ipvsadm -A -t 192.168.175.100:80 -s wrr # 创建集群,算法为加权轮询
ipvsadm -D -t 192.168.175.100:80 # 删除集群
ipvsadm -a -t 192.168.175.100:80 -r 192.168.175.20:8080 -m -w 3 # 往集群中添加RS,-m配置为nat模式,配置权重为3
ipvsadm -d -t 192.168.175.100:80 -r 192.168.175.20:8080
# 删除RS
- 查看
ipvsadm -L|l [options]
–numeric, -n:以数字形式输出地址和端口号
–exact:扩展信息,精确值
–connection,-c:当前IPVS连接输出
–stats:统计信息
–rate :输出速率信息