负载均衡
当访问的服务具有多个实例时,需要根据某种“均衡”的策略决定请求发往哪个节点,这就是所谓的负载均衡,目的是为了将数据流量分摊到多个服务器执行,减轻每台服务器的压力,从而提高了数据的吞吐量
负载均衡的种类
- 常见的硬件有NetScaler、F5、Radware和Array等商用的负载均衡器
- 常见的软件有LVS、Nginx等,它们是基于Linux系统并且开源的负载均衡策略
Nginx负载均衡配置
-
利用upstream实现
-
upstream lbs { server localhost:8080; server localhost:8081; } server { # 跟路径 所有接口如果有统一的前缀就配置统一的前缀 比如 /api/,如果没有直接配置/ location / { # 这里的lbs 与 upstream后边的lbs相对应 proxy_pass http://lbs; proxy_redirect default; } }
负载均衡的集中策略
节点轮询
- 默认策略
- 简介:每个请求按顺序分配到不同的后端服务器
- 适用于静态文件服务器
weight 权重配置
-
简介:weight和访问比率成正比,数字越大,分配得到的流量越高
-
服务器性能差异大的情况使用
-
配置方式
upstream lbs { server localhost:8080 weight=5; server localhost:8081 weight=10; }
ip_hash
-
简介:根据请求按访问ip的hash结果分配,每个用户就可以固定访问一个后端服务器
-
服务器业务分区、业务缓存、Session需要单点的情况
-
配置方式
upstream lbs { ip_hash; server localhost:8080; server localhost:8081; }
利用upstream对节点进行设置
down:当前服务不参与负载
upstream lbs {
server localhost:8080 down;
server localhost:8081 weight=10;
}
backup:其它所有的非backup机器down的时候,会请求backup机器
upstream lbs {
server localhost:8080 backup;
server localhost:8081 weight=10;
}
Nginx探测后端节点可用性
思考:如果某个服务挂了,nginx无感知的情况下,还会将请求打到挂掉的服务上,此时会给用户带来很大的麻烦,如果是ip固定分发,就会造成很多用户使用不了我们的网站或者app,我们将如何解决这个问题呢?
配置参数解析:
- max_fails:设定Nginx与后端节点通信的尝试失败的次数,默认值是1
- fail_timeout:在fail_timeout参数定义的时间内,如果失败的次数达到max_fails设定值,Nginx就这个节点不可用
nginx认为的失败
- 可以通过指令proxy_next_upstream来配置什么是失败的尝试
- 注意默认配置时,http_404状态不被认为是失败的尝试
配置实操
upstream lbs {
server localhost:8080 max_fails=2 fail_timeout=60s ;
server localhost:8081 max_fails=2 fail_timeout=60s;
}
server {
location / {
proxy_pass http://lbs;
# 这里就是配置nginx认为的失败
proxy_next_upstream error timeout http_500 http_503 http_404;
}
}
Nginx自定义全局异常
server {
location / {
proxy_pass http://lbs;
proxy_set_header Host $host:$server_port;
proxy_next_upstream error timeout http_500 http_503 http_404;
# 存放用户的真实ip
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#开启错误拦截配置,一定要开启
proxy_intercept_errors on;
}
error_page 404 500 502 503 504 =200 /default_api;
location = /default_api {
default_type application/json;
return 200 '{"code":"999","msg":"request method failed"}';
}
}
Nginx配置浏览器跨域
location / {
proxy_pass http://lbs;
proxy_set_header Host $host:$server_port;
proxy_next_upstream error timeout http_500 http_503 http_404;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
# 配置跨域
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 200;
}
}
Nginx配置websocket反向代理
server {
listen 80;
server_name xdclass.net;
location / {
proxy_pass http://lbs;
proxy_read_timeout 300s; //websocket空闲保持时长
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
nginx重定向
rewrite 地址重定向语法:
rewrite regex replacement[flag]
server {
listen 80;
server_name xdclass.net;
location / {
proxy_pass http://lbs;
proxy_read_timeout 300s; //websocket空闲保持时长
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
rewrite ^/(.*) https:787k.fun/$1 permanent
}
}
replacement部分是https://787k.fun/$1,$1是取自regex部分()里的内容即「.*」
flag参数
标记符号 | 说明 |
---|---|
last | 本条规则匹配完成后继续向下匹配新的location URI规则 |
break | 本条规则匹配完成后终止,不在匹配任何规则 |
redirect | 返回302临时重定向 |
permanent | 返回301永久重定向 |
正则表达式
字符 | 描述 |
---|---|
^ | 匹配输入字符串的起始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的字符零次或者多次 |
+ | 匹配前面字符串一次或者多次 |
? | 匹配前面字符串的零次或者一次 |
. | 匹配除“\n”之外的所有单个字符 |
(pattern) | 匹配括号内的pattern |
Nginx配置网关缓存
参数解析
- /root/cache:本地路径,用来设置Nginx缓存资源的存放地址
- levels=1:1:1
表示是三级目录,且每级目录数均为16个,总目录数为:16*16*16
- key_zone:在共享内存中定义一块存储区域来存放缓存的 key 和 metadata
- max_size:最大 缓存空间,如果不指定会使用掉所有磁盘空间。当达到 disk 上限后,会删除最少使用的 cache
- inactive:某个缓存在inactive指定的时间内如果不访问,将会从缓存中删除
- proxy_cache_valid:配置nginx cache中的缓存文件的缓存时间,proxy_cache_valid 200 304 2m 对于状态为200和304的缓存文件的缓存时间是2分钟
- use_temp_path:建议为 off,则 nginx 会将缓存文件直接写入指定的 cache 文件中
- proxy_cache:启用proxy cache,并指定key_zone,如果proxy_cache off表示关闭掉缓存
- add_header Nging-Cache “$upstream_cache_status”:用于前端判断是否是缓存,miss、hit、expired(缓存过期)、updating(更新,使用旧的应答)
nginx配置缓存
proxy_cache_path /root/cache levels=1:2 keys_zone=just_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
location /{
...
proxy_cache xd_cache;
proxy_cache_valid 200 304 10m;
proxy_cache_valid 404 1m;
proxy_cache_key $host$uri$is_args$args;
add_header Nginx-Cache "$upstream_cache_status";
}
}
Nginx的压缩配置
#开启gzip,减少我们发送的数据量
gzip on;
gzip_min_length 1k;
#4个单位为16k的内存作为压缩结果流缓存
gzip_buffers 4 16k;
#gzip压缩比,可在1~9中设置,1压缩比最小,速度最快,9压缩比最大,速度最慢,消耗CPU
gzip_comp_level 4;
#压缩的类型
gzip_types application/javascript text/plain text/css application/json application/xml text/javascript;
#给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
gzip_vary on;
#禁用IE6以下的gzip压缩,IE某些版本对gzip的压缩支持很不好
gzip_disable "MSIE [1-6].";
server {
location /static {
alias /usr/local/software/static;
}
location / {
proxy_pass http://lbs;
proxy_read_timeout 300s; //websocket空闲保持时长
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
rewrite ^/(.*) https:787k.fun/$1 permanent
}
}
Nginx配置https
安装nginx的时候要这样执行
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
make&make install
Nginx配置https证书
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
server {
listen 443 ssl;
server_name localhost;
ssl_certificate pem的路径;
ssl_certificate_key key的路径;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
Nginx高可用
部署Nginx集群LVS+keepalive
LVS
LVS是Linux Virtual Server,Linux虚拟服务器,是一个虚拟的服务器集群系统,解决的两个核心问题是:选谁、转发
-
三种负载均衡转发技术
NAT:数据进出都通过 LVS, 前端的Master既要处理客户端发起的请求,又要处理后台RealServer的响应信息,将RealServer响应的信息再转发给客户端, 容易成为整个集群系统性能的瓶颈; (支持任意系统且可以实现端口映射)
DR: 移花接木,最高效的负载均衡规则,前端的Master只处理客户端的请求,将请求转发给RealServer,由后台的RealServer直接响应客户端,不再经过Master, 性能要优于LVS-NAT; 需要LVS和RS集群绑定同一个VIP(支持多数系统,不可以实现端口映射)
TUNL:隧道技术,前端的Master只处理客户端的请求,将请求转发给RealServer,然后由后台的RealServer直接响应客户端,不再经过Master;(支持少数系统,不可以实现端口映射))
keepalive
监控并管理 LVS 集群系统中各个服务节点的状态,keepalived是一个类似于交换机制的软件,核心作用是检测服务器的状态,如果有一台web服务器工作出现故障,Keepalived将检测到并将有故障的服务器从系统中剔除,使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成。
后来加入了vrrp(虚拟路由器冗余协议),除了为lvs提供高可用还可以为其他服务器比如Mysql、Haproxy等软件提供高可用方案
-
需要在多台机器上安装keepalive
-
yum install -y gcc yum install -y openssl-devel yum install -y libnl libnl-devel yum install -y libnfnetlink-devel yum install -y net-tools yum install -y vim wget yum install -y keepalived 安装路径 cd /etc/keepalived
-
启动和查看命令
-
#启动 service keepalived start #停止 service keepalived stop #查看状态 service keepalived status #重启 service keepalived restart #停止防火墙 systemctl stop firewalld.service
keepalive配置
- 配置文件地址:/etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL # 设置lvs的id,在一个网络内应该是唯一的
enable_script_security #允许执行外部脚本
}
#配置vrrp_script,主要用于健康检查及检查失败后执行的动作。
vrrp_script chk_real_server {
#健康检查脚本,当脚本返回值不为0时认为失败
script "/usr/local/software/conf/chk_server.sh"
#检查频率,以下配置每2秒检查1次
interval 2
#当检查失败后,将vrrp_instance的priority减小5
weight -5
#连续监测失败3次,才认为真的健康检查失败。并调整优先级
fall 3
#连续监测2次成功,就认为成功。但不调整优先级
rise 2
user root
}
#配置对外提供服务的VIP vrrp_instance配置
vrrp_instance VI_1 {
#指定vrrp_instance的状态,是MASTER还是BACKUP主要还是看优先级。
state MASTER
#指定vrrp_instance绑定的网卡,最终通过指定的网卡绑定VIP
interface ens33
#相当于VRID,用于在一个网内区分组播,需要组播域内内唯一。
virtual_router_id 51
#本机的优先级,VRID相同的机器中,优先级最高的会被选举为MASTER
priority 100
#心跳间隔检查,默认为1s,MASTER会每隔1秒发送一个报文告知组内其他机器自己还活着。
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
#定义虚拟IP(VIP)为787k.fun,可多设,每行一个
virtual_ipaddress {
787k.fun
}
#本vrrp_instance所引用的脚本配置,名称就是vrrp_script 定义的容器名
track_script {
chk_real_server
}
}
# 定义对外提供服务的LVS的VIP以及port
virtual_server 787k.fun 80 {
# 设置健康检查时间,单位是秒
delay_loop 6
# 设置负载调度的算法为rr
lb_algo rr
# 设置LVS实现负载的机制,有NAT、TUN、DR三个模式
lb_kind NAT
# 会话保持时间
persistence_timeout 50
#指定转发协议类型(TCP、UDP)
protocol TCP
# 指定real server1的IP地址
real_server 真实ip(192.168.1.1) 80 {
# 配置节点权值,数字越大权重越高
weight 1
# 健康检查方式
TCP_CHECK { # 健康检查方式
connect_timeout 10 # 连接超时
retry 3 # 重试次数
delay_before_retry 3 # 重试间隔
connect_port 80 # 检查时连接的端口
}
}
}
- 注意事项
router_id后面跟的自定义的ID在同一个网络下是一致的
state后跟的MASTER和BACKUP必须是大写;否则会造成配置无法生效的问题
interface 网卡ID;要根据自己的实际情况来看,可以使用以下方式查询 ip a 查询
在BACKUP节点上,其keepalived.conf与Master上基本一致,修改state为BACKUP,priority值改小即可
authentication主备之间的认证方式,一般使用PASS即可;主备的配置必须一致,不能超过8位
- 两个机器全部启动nginx和keepalive后根据虚拟ip(787k.fun)来访问
如果某个Nginx挂了,但是该机器上的keepalive正常,请求依旧可以过来但是响应会失败,如何解决?
- 需要关闭selinux
getenforce 查看
setenforce 0 关闭
- 创建/usr/local/software/conf目录
- 通过脚本实现监听
#配置vrrp_script,主要用于健康检查及检查失败后执行的动作。
vrrp_script chk_real_server {
#健康检查脚本,当脚本返回值不为0时认为失败
script "/usr/local/software/conf/chk_server.sh"
#检查频率,以下配置每2秒检查1次
interval 2
#当检查失败后,将vrrp_instance的priority减小5
weight -5
#连续监测失败3次,才认为真的健康检查失败。并调整优先级
fall 3
#连续监测2次成功,就认为成功。但不调整优先级
rise 2
user root
}
- chk_server.sh脚本内容(需要 chmod +x chk_server.sh)
#!/bin/bash
#检查nginx进程是否存在
counter=$(ps -C nginx --no-heading|wc -l)
if [ "${counter}" -eq "0" ]; then
service keepalived stop
echo 'nginx server is died.......'
fi
- 重启keepalive,重启nginx