目录
Nginx负载均衡
七层服务使用的是http的指令块,四层服务则使用stream指令块,http和stream指令块是同级的
如果proxy_pass指令是用URI指定的,那么当请求被传递到服务器时,与位置匹配的规范化请求URI部分将被指令中指定的URI替换
# 例:用户请求"IP/name/"会被转到"127.0.0.1/remote/"
location /name/ {
proxy_pass http://127.0.0.1/remote/;
}
upstream配置
七层均衡
nginx3配置(192.168.113.145)
错误的连接由proxy_next_upstream, fastcgi_next_upstream等指令决定,且默认情况下,后端某台
服务器出现故障了,nginx会自动将请求再次转发给其他正常的服务器(因为默认
proxy_next_upstream error timeout)。
所以即使我们没有配这个参数,nginx也可以帮我们处理error和timeout的相应,但是没法处理404等报
错。
为了看清楚本质,可以先将proxy_next_upstream设置为off,也就是不将失败的请求转发给其他正常
服务器,这样我们可以看到请求失败的结果。
upstream web {
#通过这个指令,可以处理当后端服务返回404等报错时,直接将请求转发给其他服务器,而不是把报错信息返回客户端。
server 192.168.113.146weight=1 max_fails=3 fail_timeout=9s;
server 192.168.113.147 weight=1;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web;
# 通过这个指令,可以处理当后端服务返回404等报错时,直接将请求转发给其他服务器,而不是把报错信息返回客户端。
# proxy_next_upstream error http_404 http_502;
proxy_next_upstream off;
# 如果不加该参数,那么在代理时,传入后端的HOST信息就是IP,那么会导致在访问时产生问题
# 设置或修改代理到后端请求头的内容
proxy_set_header Host $host;
# 通过该参数记录真实客户端地址(该变量值有两个,"$proxy_add_x_forwarded_for"记录了多个IP,"$remote_addr"只记录一个IP)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
# 代理服务器与后端节点建立链接的超时时间
proxy_connect_timeout 60;
# 代理服务器读取后端响应的超时时间
proxy_read_timeout 60;
# 代理服务器发送请求给后端节点的超时时间
proxy_send_timeout 60;
}
}
# 测试
# 设置的超时时间为9s,是每3s请求一次,可以看到后端一台服务器挂了后,请求没有直接转发给正常的服务器,而是直接返回了502。尝试三次后,等待9s,才开始再次尝试(最后一个502)
[root@node-3 conf]# while true;do curl -sI 192.168.113.145 |grep HTTP/1.1 ;sleep 3;done
HTTP/1.1 502 Bad Gateway
HTTP/1.1 200 OK
HTTP/1.1 502 Bad Gateway
HTTP/1.1 200 OK
HTTP/1.1 502 Bad Gateway
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 502 Bad Gateway
# nginx3打开location下的指令"proxy_next_upstream",再次测试
# 可以看到现在没有502报错,请求都处理了。因为错误的响应码被proxy_next_upstream 获取,这次请求被转发给下一个正常的服务器了。
[root@node-3 conf]# while true;do curl -sI 192.168.1.6 |grep HTTP/1.1 ;sleep 3;done
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
四层均衡
源码安装的nginx引用stream模块
# 预编译(编译upstream模块有两种编译方式,一种动态,一种静态,我这里使用的是静态)
[root@node-3 conf]# ./configure --prefix=/usr/local/nginx --with-stream
# 编译/安装:
[root@node-3 conf]# make && make install
# 如果使用的是动态编译,那么在nginx的目录中会生成一个modules模块,里面存放着stream的模块文件(so),需要在nginx.conf文件中引用他
# 在全局中加入load_module,如下
#user nobody;
worker_processes 1;
load_module /usr/local/nginx/modules/ngx_stream_module.so;
yum安装的nginx引用stream模块
# yum安装的nginx是自带stream模块的,只不过是动态编译好的
# 查看nginx的相关模块包
[root@node-3 conf]# yum list nginx*
# 安装stream模块包
[root@node-3 conf]# yum -y install nginx_mod_stream
# 查看模块文件
[root@node-3 conf]# rpm -ql nginx_mod_stream
/usr/lib64/nginx/modules/ngx_stream_module.so
/usr/share/nginx/modules/mod-stream.conf
# yum安装的nginx中有这样一处配置include,他回去引用/usr/share/nginx/modules/下的conf文件,所以不需要手动配置引用
使用四层均衡代理后端MySQL
节点
节点名称 | IP |
---|---|
代理服务器 | 192.168.113.146 |
后端服务器 | 192.168.113.147 |
客户端 | 192.168.113.148 |
# 三台都有mysql,并且做好了授权访问
# 在防火墙配置规则,使其客户端(192.168.113.148)无法访问后端服务器(模拟内外网)
[root@147 ~]# iptables -I INPUT -s 192.168.113.148 -j REJECT
或 #(hosts.deny文件可以拒绝指定IP或网段访问规则,ALL代表所有规则和端口)
[root@147 ~]# echo "ALL:192.168.113.148" >> /etc/hosts.deny
# 在代理服务器上配置nginx.conf
stream {
upstream web {
server 192.168.113.147:3306;
}
server {
listen 8080;
proxy_connect_timeout 3s;
# 设置超时时间,10s后断开
proxy_timeout 10s;
proxy_pass web;
}
# 我这里加入了日志,可以不用加入日志的
log_format proxy '$remote_addr $remote_port $protocol $status [$time_iso8601]'
'"$upstream_addr" "$upstream_bytes_sent" "$upstream_connect_time"';
access_log /usr/local/nginx/logs/proxy.log proxy;
}
# 用户端访问
[root@148 ~]# mysql -uihs_admin -p123456 -h192.168.113.146 -P8080
至此代理结束,很简单是吧
# 在main全局配置stream:
events {
worker_connections 1024;
}
stream {
upstream web {
# 必须要指定ip加port
server 192.168.75.128:80;
server 192.168.75.135:80;
}
server {
listen 80;
# 连接上游服务器超时间,超过则选择另外一个服务器
proxy_connect_timeout 3s;
# tcp连接闲置时间,超过则关闭
proxy_timeout 10s;
proxy_pass web;
}
log_format proxy '$remote_addr $remote_port $protocol $status
[$time_iso8601] '
'"$upstream_addr" "$upstream_bytes_sent"
"$upstream_connect_time"' ;
access_log /usr/local/nginx/logs/proxy.log proxy;
}
轮训算法
ip_hash
在nginx中,如果做负载均衡时,本来用户先建立的链接为nginx1,但是在用户刷新时就可能会变成nginx2,导致会话丢失,可以通过ip_hash来解决这个问题(ip_hash是指在用户与nginx1建立第一次链接后,暂时就不会去和nginx2去做链接)
upstream web {
ip_hash;
server 192.168.113.146 weight=1 max_fails=3 fail_timeout=9s;
server 192.168.113.147 weight=1;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web;
proxy_next_upstream error http_404 http_502;
# proxy_next_upstream off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 请求
# 可以看到113.147的服务是正常的,但是却不转发给113.147了,请求固定在了113.146的服务器上。
[root@node-3 conf]# while true;do curl 192.168.113.145;sleep 2;done
this is 113.146 page
this is 113.146 page
this is 113.146 page
[root@node-3 conf]# curl 192.168.113.147
this is 113.147 page
在使用负载均衡的时候会遇到会话保持的问题,常用的方法有:
a、ip hash,根据客户端的IP,将请求分配到不同的服务器上;
b、cookie,服务器给客户端下发一个cookie,具有特定cookie的请求会分配给它的发布者。
url_hash
url_hash不适用于四层,因为四层拆包只拆到了端口,而七层则拆到了路径
过请求url进行hash,再通过hash值选择后端server
upstream nginx_web {
hash $request_uri consistent;
server 192.168.113.146;
server 192.168.113.147;
}
根据响应时间均衡
# 下载模块:
wget https://github.com/gnosek/nginx-upstream-fair/archive/master.zip
# 解压:
unzip master.zip
# 修改源码bug:
sed -i 's/default_port/no_port/g' ngx_http_upstream_fair_module.c
# 预编译(其中"--add-module=../echo-nginx-module"这个模块是其他新加的模块,没有这个模块的,编译时不要加上)
./configure --prefix=/usr/local/nginx --add-module=../echo-nginx-module --with_http_stub_status_module --add-module=../nginx-upstream-fair-master
# 编译/安装:
make && make install
# 配置:
upstream web {
fair;
server 192.168.113.146 weight=1 max_fails=3 fail_timeout=9s;
server 192.168.113.147 weight=1;
}
备用服务器
1113.147的服务器做备用服务器,只有在113.146得服务器不能提供服务时,才会自动顶上,否则,默认是不提供服务的。
upstream web {
server 192.168.113.146 weight=1 max_fails=3 fail_timeout=9s;
server 192.168.113.147 weight=1 backup;
}
负载均衡回话保持
- cookie:用户浏览器中存放用户信息,session位置(钥匙)
- session:服务器回话,用户登录信息