目录
1、什么是代理服务
1.1、正向代理
1.2、反向代理
2、Nginx + Tomcat 构筑Web服务器集群的负载均衡
2.1、Nginx的核心特点
2.2、Nginx 的 upstream 负载的5种策略
2.3、环境拓扑
2.4、nginx部署
2.5、部署web服务器tomcat1
2.5.1、安装tomcat
2.6、部署web服务器tomcat2
2.7、配置nginx负载均衡
2.7.1、nginx-sticky-module模块
2.7.3、load-balance调度算法
2.7.4、负载均衡与健康检查
2.7.5、nginx的proxy缓存使用
2.7.6、修改nginx配置文件
2.7.7、重启nginx服务
2.8、测试
2.8.1、测试缓存功能
2.8.2、测试负载均衡
2.8.3、测试健康检查即容错性
2.8.4、后端服务器获取客户端真实ip
2.9、补充说明
3、使用nginx实现动静分离
3.1、原理
3.2、修改nginx代理服务器配置文件
3.3、测试
介绍
代理其实就是一个中介,A和B本来可以直连,中间插入一个C,C就是中介。
刚开始的时候,代理多数是帮助内网client访问外网server用的
后来出现了反向代理,"反向"这个词在这儿的意思其实是指方向相反,即代理将来自外网客户端的请求转发到内网服务器,从外到内
正向代理类似一个跳板机,代理访问互联网资源
正向代理的用途:
(1) 可以做缓存,加速访问资源
(2)对客户端访问授权,上网进行认证
(3)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器
反向代理的作用:
(1)保证内网的安全,阻止web攻击,大型网站,通常将反向代理作为公网访问地址,Web服务器是内网
(2)负载均衡,通过反向代理服务器来优化网站的负载
Nginx是一款轻量级的网页服务器、反向代理器以及电子邮件代理服务器。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。Nginx(发音同engine x),它是由俄罗斯程序员Igor Sysoev所开发的。起初是供俄国大型的门户网站及搜索引擎Rambler使用。此软件BSD-like协议下发行,可以在UNIX、GNU/Linux、BSD、Mac OS X、Solaris,以及Microsoft Windows等操作系统中运行。
(1)跨平台:Nginx 可以在大多数OS编译运行,而且也有Windows的版本;
(2)配置异常简单:非常容易上手。
(3)非阻塞、高并发连接
(4)事件驱动:通信机制采用epoll模型,支持更大的并发连接
(5)Master/Worker结构:一个master进程,生成一个或多个worker进程
(6)内存消耗小:处理大并发的请求内存消耗非常小。
(7)内置的健康检查功能:如果 Nginx 代理的后端的某台 Web 服务器宕机了,不会影响前端访问
(8)节省带宽:支持 GZIP 压缩,可以添加浏览器本地缓存的 Header 头
(9)稳定性高:用于反向代理,宕机的概率微乎其微
1、轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、指定权重
指定轮询权重,用于后端服务器性能不均的情况。
3、IP绑定 ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
5、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
主机 | IP | 角色 |
nginx | 192.168.121.10 | 反向代理服务器 |
tomcat1 | 192.168.121.11 | web服务器 |
tomcat2 | 192.168.121.12 | web服务器 |
上传软件包并解压
解压
[root@nginx ~]# tar -zxvf nginx-1.10.3.tar.gz -C /usr/local/src/
安装依赖包
[root@nginx ~]# yum install -y gcc gcc-c++ autoconf automake zlib zlib-devel openssl openssl-devel pcre pcre-devel
预编译
添加www组,创建nginx运行账户www并加入到www组,不允许www用户直接登录系统。
[root@nginx ~]# groupadd www
[root@nginx ~]# useradd -g www -s /sbin/nologin www
注:
结合proxy和upstream模块实现后端web负载均衡
使用proxy模块实现静态文件缓存
结合nginx默认自带的ngx_http_proxy_module模块 和ngx_http_upstream_module模块实现后端服务器的健康检查,也可以使用第三方模块nginx_upstream_check_module
使用nginx-sticky-module扩展模块实现会话黏贴(保持会话)
使用ngx_cache_purge [pɜːrdʒ]实现更强大的缓存清除功能
上面提到的2个模块都属于第三方扩展模块,需要提前下好源码,然后编译时通过--add-moudle=src_path一起安装。
[root@nginx nginx-1.10.3]# tar zxf ngx_cache_purge-2.3.tar.gz -C /usr/local/src/
[root@nginx nginx-1.10.3]# tar zxf master.tar.gz -C /usr/local/src/
[root@nginx nginx-1.10.3]# cd /usr/local/src/nginx-1.10.3/
[root@nginx nginx-1.10.3]# ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_realip_module --with-http_ssl_module --with-http_gzip_static_module --http-client-body-temp-path=/var/tmp/nginx/client --http-proxy-temp-path=/var/tmp/nginx/proxy --http-fastcgi-temp-path=/var/tmp/nginx/fcgi --with-http_dav_module --with-http_stub_status_module --with-http_addition_module --with-http_sub_module --with-http_flv_module --with-http_mp4_module --with-pcre --with-http_flv_module --add-module=../ngx_cache_purge-2.3 --add-module=../nginx-goodies-nginx-sticky-module-ng-08a395c66e42
编译安装
[root@nginx nginx-1.10.3]# make && make install
启动nginx
[root@nginx nginx-1.10.3]# mkdir -p /var/tmp/nginx/{client,proxy,fcgi}
[root@nginx nginx-1.10.3]# chown -R www:www /var/tmp/nginx/
[root@nginx nginx-1.10.3]# /usr/local/nginx/sbin/nginx
查看端口号
[root@nginx nginx-1.10.3]# netstat -antup | grep 80
网站访问测试
注:nginx的所有模块必须在编译的时候添加,不能再运行的时候动态加载。
注:如果你想在已安装好的nginx上添加第三方模块,依然需要重新编译,但为了不覆盖你原有的配置,请不要make install,而是直接拷贝可执行文件:
[root@cong11 nginx-1.10.3]#./configure --add-module=…… #你的第三方模块
[root@cong11 nginx-1.10.3]#make 后不要make install,改为手动拷贝,先备份
[root@cong11 nginx-1.10.3]#cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
[root@cong11 nginx-1.10.3]#cp objs/nginx /usr/local/nginx/sbin/nginx
安装JDK
上传需要的软件包
解压JDK
[root@tomcat1 ~]# tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/local/
配置JDK环境变量
[root@tomcat1 ~]# vim /etc/profile
#在文件最后加入一下行
JAVA_HOME=/usr/local/jdk1.8.0_171
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar
export PATH JAVA_HOME CLASSPATH
#使环境变量生效
[root@tomcat1 ~]# source /etc/profile
解压软件包
[root@tomcat1 ~]# tar -zxvf apache-tomcat-8.5.42.tar.gz -C /usr/local/
重命名目录
[root@tomcat1 ~]# cd /usr/local/
[root@tomcat1 local]# mv apache-tomcat-8.5.42/ tomcat
建立系统服务文件
[root@tomcat1 local]# vim /lib/systemd/system/tomcat.service
[Unit]
Description=tomcat
After=network.target
[Service]
Type=forking
Environment=JAVA_HOME=/usr/local/jdk1.8.0_171/
Environment=CATALINA_HOME=/usr/local/tomcat
ExecStart=/etc/init.d/tomcat start
ExecStop=/etc/init.d/tomcat stop
ExecRestart=/etc/init.d/tomcat restart
PrivateTmp=true
[Install]
WantedBy=multi-user.target
#重载service文件
systemctl daemon-reload
启动tomcat
systemctl start tomcat
添加开机自启动
systemctl enable tomcat
查看是否成功启动
ps -ef | grep tomcat
安装 mysql-connector
tar -zxvf mysql-connector-java-5.1.47.tar.gz -C /usr/local/src/
cd /usr/local/src/mysql-connector-java-5.1.47/
cp mysql-connector-java-5.1.47-bin.jar /usr/local/tomcat/lib/
systemctl restart tomcat
创建测试页面
echo "tomcat server1" > /usr/local/tomcat/webapps/ROOT/index.jsp
测试
部署tomcat参照tomcat1
创建测试页面
echo "tomcat server2" > /usr/local/tomcat/webapps/ROOT/index.jsp
测试
配置nginx反向代理:反向代理+负载均衡+健康探测
查看nginx加载的模块
这个模块的作用是通过cookie黏贴的方式将来自同一个客户端(浏览器)的请求发送到同一个后端服务器上处理,这样一定程度上可以解决多个backend servers的session同步的问题 —— 因为不再需要同步,而RR轮询模式必须要运维人员自己考虑session同步的实现(例如通过memcache/redis缓存session)。
另外内置的ip_hash也可以实现根据客户端IP来分发请求,但它很容易造成负载不均衡的情况,而如果nginx前面有CDN网络或者来自同一局域网的访问,它接收的客户端IP是一样的,容易造成负载不均衡现象。
nginx-sticky-module的cookie过期时间,默认浏览器关闭就过期。
这个模块并不合适不支持Cookie 或手动禁用了cookie的浏览器,此时默认sticky就会切换成RR。它不能与ip_hash同时使用。
upstream backend {
server 192.168.1.12:8080 weight=1;
server 192.168.1.13:8080 weight=1;
sticky;
}
配置起来超级简单,一般来说一个sticky指令就够了。
相关信息可以查看官方文档https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng
严格来说,nginx自带是没有针对负载均衡后端节点的健康检查的,但是可以通过默认自带的ngx_http_proxy_module模块和ngx_http_upstream_module模块中的相关指令来完成当后端节点出现故障时,自动切换到下一个节点来提供访问。
upstream backend {
sticky;
server 192.168.1.12:8080 weight=2 max_fails=1 fail_timeout=10s;
server 192.168.1.13:8080 weight=2 max_fails=1 fail_timeout=10s;
}
server {
……
location / {
proxy_pass http://backend;
}
……
}
sticky:同一IP只访问同一服务器,不加则是采用轮询访问
weight :轮询权值也是可以用在ip_hash的,默认值为1。
max_fails=1 fail_timeout=10s:这个是Nginx在负载均衡功能中,用于判断后端节点状态,所用到两个参数。
Nginx基于连接探测,如果发现后端异常,在单位周期为fail_timeout设置的时间,中达到max_fails次数,这个周期次数内,如果后端同一个节点不可用,那么将把节点标记为不可用,并等待下一个周期(同样时长为fail_timeout)再一次去请求,判断是否连接是否成功。如果成功,将恢复之前的轮询方式,如果不可用将在下一个周期(fail_timeout)再试一次。
默认:fail_timeout为10s,max_fails为1次。
如上配置表明如果后端节点10秒内出现1次不可用情况,判定节点不可用。判定不可用后10秒内请求不会转发到此节点,直到10秒后重新检测节点健康情况。
缓存也就是将js、css、image等静态文件从后端服务器缓存到nginx指定的缓存目录下,既可以减轻后端服务器负担,也可以加快访问速度。但这样缓存及时清理成为了一个问题,所以需要ngx_cache_purge这个模块来在过期时间未到之前,手动清理缓存。
proxy模块中常用的指令时proxy_pass和proxy_cache.
nginx的web缓存功能的主要是由proxy_cache、fastcgi_cache指令集和相关指令集完成。
proxy_cache指令负责反向代理缓存后端服务器的静态内容。
fastcgi_cache主要用来处理FastCGI动态进程缓存。
http {
#$upstream_cache_status记录缓存命中率
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'"$upstream_cache_status"';
access_log logs/access.log main;
proxy_buffering on; #代理的时候,开启或关闭缓冲后端服务器的响应
proxy_temp_path /usr/local/nginx/proxy_temp;
proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2 keys_zone=my-cache:100m inactive=600m max_size=2g;
server {
listen 80;
server_name localhost;
root html;
index index.php index.html index.htm;
#ngx_cache_purge实现缓存清除
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 192.168.1.0/24;
deny all;
proxy_cache_purge my-cache $host$1$is_args$args;
}
location ~ .*\.(gif|jpg|png|html|htm|css|js|ico|swf|pdf)(.*) {
proxy_pass http://backend;
proxy_redirect off;
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_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_cache my-cache;
add_header Nginx-Cache $upstream_cache_status;
proxy_cache_valid 200 304 301 302 8h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1d;
proxy_cache_key $host$uri$is_args$args;
expires 30d;
}
相关选项说明:
proxy_buffering on; 代理的时候,开启或关闭缓冲后端服务器的响应。
当开启缓冲时,nginx尽可能快地从被代理的服务器接收响应,再将它存入缓冲区中。
proxy_temp_path:缓存临时目录。后端的响应并不直接返回客户端,而是先写到一个临时文件中,然后被rename一下当做缓存放在proxy_cache_path。0.8.9版本以后允许temp和cache两个目录在不同文件系统上(分区),然而为了减少性能损失还是建议把它们设成一个文件系统上。
proxy_cache_path:设置缓存目录,目录里的文件名是cache_key的MD5值。
levels=1:2 keys_zone=my-cache:100m表示采用2级目录结构,第一层目录只有一个字符,是由levels=1:2设置,总共二层目录,子目录名字由二个字符组成。Web缓存区名称为my-cache,内存缓存空间大小为100MB。文件系统上看到的缓存文件名类似于
/usr/local/nginx/proxy_cache/c/29/b7f54b2df7773722d382f4809d65029c 。
inactive=600 max_size=2g表示600分钟没有被访问的内容自动清除,硬盘最大缓存空间为2GB,超过这个大小将清除最近最少使用的数据。
默认情况,nginx不缓存从后端响应的http头中带有Set-Cookie的对象。如果客户端发送的请求带有Cookie header,nginx将忽略缓存,直接将请求传递到后端。nginx中通过proxy_ignore_headers设置忽略它们,设置方法如下:
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_cache:引用前面定义的缓存区my-cache
proxy_cache_key:定义如何生成缓存的键,设置web缓存的key值,nginx根据key值md5哈希存储缓存
proxy_cache_valid:为不同的响应状态码设置不同的缓存时间,比如200、302等正常结果可以缓存的时间长点,而404、500等缓存时间设置短一些,这个时间到了文件就会过期,而不论是否刚被访问过。
add_header指令来设置response header,语法: add_header name value;
$upstream_cache_status这个变量来显示缓存的状态,我们可以在配置中添加一个http头来显示这一状态,
$upstream_cache_status包含以下几种状态:
·MISS 未命中,请求被传送到后端
·HIT 缓存命中
·EXPIRED 缓存已经过期请求被传送到后端
·UPDATING 正在更新缓存,将使用旧的应答
·STALE 后端将得到过期的应答
expires :在响应头里设置Expires:或Cache-Control:max-age,返回给客户端的浏览器缓存失效时间。
下面的nginx.conf实现nginx在前端做反向代理服务器的完整配置文件的例子,处理js、png等静态文件,jsp/php等动态请求转发到其它服务器tomcat/apache
[root@cong11 ~]# vim /usr/local/nginx/conf/nginx.conf
user www www;
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
error_log logs/error.log;
worker_rlimit_nofile 10240;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'"$upstream_cache_status"';
access_log logs/access.log main;
server_tokens off;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_proxied any;
gzip_min_length 1k;
gzip_buffers 16 8k;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_buffering on;
proxy_temp_path /usr/local/nginx/proxy_temp;
proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2 keys_zone=my-cache:100m max_size=1000m inactive=600m max_size=2g;
upstream backend {
sticky;
server 192.168.121.11:8080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.121.12:8080 weight=1 max_fails=2 fail_timeout=10s;
}
server {
listen 80;
server_name localhost;
charset utf-8;
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 192.168.121.0/24;
deny all;
proxy_cache_purge my-cache $host$1$is_args$args;
}
location / {
index index.jsp index.php index.html index.htm;
proxy_pass http://backend;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}
location ~ .*\.(gif|jpg|png|html|htm|css|js|ico|swf|pdf)(.*) {
proxy_pass http://backend;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_cache my-cache;
add_header Nginx-Cache $upstream_cache_status;
proxy_cache_valid 200 304 301 302 8h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1d;
proxy_cache_key $host$uri$is_args$args;
expires 30d;
}
}
}
常用指令说明:
client_max_body_size 10m :允许客户端请求的最大单文件字节数。如果有上传较大文件,请设置它的限制值。
client_body_buffer_size 128k :缓冲区代理缓冲用户端请求的最大字节数
server_tokens off :隐藏nginx的版本号
模块http_proxy:这个模块实现的是nginx作为反向代理服务器的功能,包括缓存功能。
proxy_connect_timeout :nginx跟后端服务器连接超时时间(代理连接超时)
proxy_read_timeout :定义从后端服务器读取响应的超时。此超时是指相邻两次读操作之间的最长时间间隔,而不是整个响应传输完成的最长时间。如果后端服务器在超时时间段内没有传输任何数据,连接将被关闭。
proxy_send_timeout :定义向后端服务器传输请求的超时。此超时是指相邻两次写操作之间的最长时间间隔,而不是整个请求传输完成的最长时间。如果后端服务器在超时时间段内没有接收到任何数据,连接将被关闭。
proxy_buffer_size 4k :设置缓冲区的大小为size。nginx从被代理的服务器读取响应时,使用该缓冲区保存响应的开始部分。这部分通常包含着一个小小的响应头。该缓冲区大小默认等于proxy_buffers指令设置的一块缓冲区的大小,但它也可以被设置得更小。
proxy_buffers 8 4k :为每个连接设置缓冲区的数量为number,每块缓冲区的大小为size。这些缓冲区用于保存从被代理的服务器读取的响应。每块缓冲区默认等于一个内存页的大小。这个值是4K还是8K,取决于平台。
附:查看Linux内存页大小
[root@cong11 ~]# getconf PAGESIZE
4096
或
[root@cong11 ~]# getconf PAGE_SIZE
4096
proxy_busy_buffers_size 64k :高负荷下缓冲大小(默认大小是proxy_buffers指令设置单块缓冲大小的2倍)
proxy_max_temp_file_size :当proxy_buffers放不下后端服务器的响应内容时,会将一部分保存到硬盘的临时文件中,这个值用来设置最大临时文件大小,默认1024M。
proxy_temp_file_write_size 64k :当缓存被代理的服务器响应到临时文件时,这个选项限制每次写临时文件的大小。
模块http_gzip:
gzip on : 开启gzip压缩输出,减少网络传输。
gzip_min_length 1k :设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。建议设置成大于1k的字节数,小于1k可能会越压越大。
gzip_buffers 4 16k :设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。4 16k代表以16k为单位,按照原始数据大小以16k为单位的4倍申请内存。如果没有设置,默认值是申请跟原始数据相同大小的内存空间去存储gzip压缩结果
gzip_http_version 1.1 :用于识别 http 协议的版本,早期的浏览器不支持Gzip压缩,用户就会看到乱码,所以为了支持前期版本加上了这个选项,如果你用了Nginx的反向代理并期望也启用Gzip压缩的话,由于末端通信是 http/1.1,故请设置为 1.1。
gzip_comp_level 6 :gzip压缩比,1压缩比最小处理速度最快,9压缩比最大但处理速度最慢(传输快但比较消耗cpu)
gzip_types :匹配mime类型进行压缩,无论是否指定”text/html”类型总是会被压缩的。设置哪压缩种文本文件可参考conf/mime.types
gzip_proxied any :Nginx作为反向代理的时候启用,根据某些请求和应答来决定是否在对代理请求的应答启用gzip压缩,是否压缩取决于请求头中的“Via”字段,指令中可以同时指定多个不同的参数,意义如下:
off – 关闭所有的代理结果数据的压缩
expired – 启用压缩,如果header头中包含 “Expires” 头信息
no-cache – 启用压缩,如果header头中包含 “Cache-Control:no-cache” 头信息
no-store – 启用压缩,如果header头中包含 “Cache-Control:no-store” 头信息
private – 启用压缩,如果header头中包含 “Cache-Control:private” 头信息
no_last_modified – 启用压缩,如果header头中不包含 “Last-Modified” 头信息
no_etag – 启用压缩 ,如果header头中不包含 “ETag” 头信息
auth – 启用压缩 , 如果header头中包含 “Authorization” 头信息
any – 无条件启用压缩
gzip_vary on :启用应答头"Vary: Accept-Encoding"。和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩。
其实cdn,代理服务器,原理上都是代理服务器。他们一般以url为key值进行缓存。而vary属性的设置,告诉了代理根据url缓存的同时,vary的信息也作为key。比如客户端(浏览器)请求的信息里带上了Accept-Encoding:gzip 则返回压缩副本。如果没有带这个头信息,默认返回非压缩副本。
模块http_stream:
这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡,upstream后接负载均衡器的名字,后端realserver以 host:port options; 方式组织在 {} 中。如果后端被代理的只有一台,也可以直接写在proxy_pass后面。
proxy_pass http://backend 请求转向backend定义的服务器列表,即反向代理,对应upstream负载均衡器。也可以proxy_pass http://ip:port。
proxy_redirect off 指定是否修改被代理服务器返回的响应头中的location头域跟refresh头域数值。参数off表示禁止所有的proxy_redirect指令。
例如:
设置后端服务器“Location”响应头和“Refresh”响应头的替换文本。假设后端服务器返回的响应头是 “Location: http://localhost:8000/two/some/uri/”,那么指令proxy_redirect http://localhost:8000/two/ http://frontend/one/;将把字符串改写为 “Location: http://frontend/one/some/uri/”。
proxy_set_header Host $host; 允许重新定义或者添加发往后端服务器的请求头。
Host的含义是表明请求的主机名,nginx反向代理服务器会向后端真实服务器发送请求,并且请求头中的host字段重写为proxy_pass指令设置的服务器。因为nginx作为反向代理使用,而如果后端真实的服务器设置有类似防盗链或者根据http请求头中的host字段来进行路由或判断功能的话,如果反向代理层的nginx不重写请求头中的host字段,将会导致请求失败。
proxy_set_header X-Forwarded-For $remote_addr; 后端web服务器获取真实的客户端IP。把真实客户端IP写入到请求头X-Forwarded-For,在Nginx Backend输出X-Forwarded-For获取到了真实客户端IP。
X_Forward_For字段表示该条http请求是有谁发起的?如果反向代理服务器不重写该请求头的话,那么后端真实服务器在处理时会认为所有的请求都来自反向代理服务器,如果后端有防攻击策略的话,那么机器就被封掉了。因此,在配置用作反向代理的nginx中一般会增加两条配置,修改http的请求头:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme; 就是为了正确地识别实际用户发出的协议是 http 还是 https。
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; 增加故障转移,如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
[root@nginx ~]# systemctl restart nginx
在后端的两台tomcat服务器上创建可以缓存的类型文件(如html或jpg类型文件)。
[root@tomcat1 ~]# echo "server1 html" > /usr/local/tomcat/webapps/ROOT/index.html
[root@tomcat2 ~]# echo "server2 html" > /usr/local/tomcat/webapps/ROOT/index.html
按F12调用开发工具,选择Network选项,我们可以看到,Response Headers,在这里我们可以看到,我们请求的是否是缓存。
第一次访问 ,可以看到缓存了但未命中。
刷新再次访问,可以看到变成了命中状态
清除缓存:
上述配置的proxy_cache_purge指令用于方便的清除缓存,但必须安装第三方的ngx_cache_purge模块才能使用
使用ngx_cache_purge模块清除缓存(直接删除缓存目录下的文件也算一种办法):
GET方式请求URL,即使用配置文件中的location ~ /purge(/.*)
浏览器访问http://192.168.1.11/purge/your/may/path来清除缓存。
例如:清楚index.html的缓存
在浏览器中输入:192.168.121.10/purge/index.html
缓存清除成功。
备注:
(1)purge是ngx_cache_pure模块指令
(2)your/may/path是要清除的缓存文件URL路径
若只有一台客户端要验证负载均衡,可以先关闭缓存和保持session会话。或者在客户端浏览器中访问不是缓存的类型文件(如index.jsp)
proxy_buffering off; #将缓存关闭
#sticky #注释掉sticky策略
发现每刷新一次就会轮询访问不同的服务器
若要验证健康检查可以先关掉缓存功能
proxy_buffering off;
客户端通过浏览器访问:
客户端不管怎么刷新,显示内容都是“tomcat server1”,说明是由第1台tomcat服务器给客户端提供服务(因为我们采用负载均衡策略是sticky)。
现在模拟tomcat server1宕机。
客户端刷新浏览器页面
可以看到第1台tomcat服务器挂掉后,继续由第2台tomcat服务器给客户端提供服务。整个过程对于客户端来说是透明的,用户是感知不到第1台tomcat服务器挂掉的
如何让后端web服务器(tomcat/apache/nginx)日志获取客户端真实的IP,而不是nginx代理服务器的IP。
nginx代理服务器的配置
修改nginx的配置文件,在server或者location中添加
proxy_set_header X-Forwarded-For $remote_addr;
tomcat作为后端服务器的配置
如果tomcat作为后端web,在tomcat日志中记录客户端的真实ip,tomcat需要做如下修改:
修改server.xml文件,在该文件中
把className="org.apache.catalina.valves.AccessLogValve" directory="logs"块中的pattern参数里的内容修改为上面的红色字体内容,即:
pattern="%{X-FORWARDED-FOR}i %a %l %u %t %r %s %b %D %q %{User-Agent}i" resolveHosts="false"
修改完后的完整配置:
vim /usr/local/tomcat/conf/server.xml
//修改下面的内容,红色部分
prefix="localhost_access_log" suffix=".txt"
pattern="%{X-FORWARDED-FOR}i %a %l %u %t %r %s %b %D %q %{User-Agent}i" resolveHosts="false" />
没有Nginx这一层的时候直接用%a就可以获得客户端IP,现在我们得用%{ X-FORWARDED-FOR }i 来获得真实的IP了。
pattern配置段,用于指定日志的输出格式。日志参数如下:
%a - 远程IP地址
%A - 本地IP地址
%b - 发送的字节数,不包括HTTP头,或“ - ”如果没有发送字节
%B - 发送的字节数,不包括HTTP头
%h - 远程主机名
%H - 请求协议
%l (小写的L)- 远程逻辑从identd的用户名(总是返回' - ')
%m - 请求方法
%p - 本地端口
%q - 查询字符串(在前面加上一个“?”如果它存在,否则是一个空字符串
%r - 第一行的要求
%s - 响应的HTTP状态代码
%S - 用户会话ID
%t - 日期和时间,在通用日志格式
%u - 远程用户身份验证
%U - 请求的URL路径
%v - 本地服务器名
%D - 处理请求的时间(以毫秒为单位)
%T - 处理请求的时间(以秒为单位)
%I (大写的i) - 当前请求的线程名称
此外,您可以指定以下别名来设置为普遍使用的模式之一:
common - %h %l %u %t "%r" %s %b
combined - %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"
重启tomcat服务,客户端访问。查看tomcat的日志
[root@tomcat1 ~]# tail -0f /usr/local/tomcat/logs/localhost_access_log.2022-06-07.txt
其中192.168.121.1是客户端真实Ip,192.168.121.10是nginx代理服务器ip地址
# 定义负载均衡设备的 ip及设备状态
upstream tomcat {
server 192.168.1.11:9090 down;
server 192.168.1.12:8080 weight=2;
server 192.168.1.13:6060;
server 192.168.1.14:7070 backup;
}
在需要使用负载的Server节点下添加
proxy_pass http://tomcat;
upstream 每个设备的状态
down:表示当前的 server 暂时不参与负载 ;
weight:默认为 1,weight 越大,负载的权重就越大;
max_fails:允许请求失败的次数默认为 1,当超过最大次数proxy_next_upstream 模块定义的错误 ;
fail_timeout:max_fails:请求失败后,暂停的时间;
backup:其它所有的非 backup 机器 down 或者忙的时候,请求 backup 机器,所以这台机器压力会最轻。
Nginx的静态处理能力很强,但是动态处理能力不足,因此,在企业中常用动静分离技术。动静分离技术其实是采用代理的方式,在server{}段中加入带正则匹配的location来指定匹配项针对php、jsp的动静分离:静态页面交给Nginx处理,动态页面交给PHP-FPM模块或Apache、tomcat、IIS处理。在Nginx的配置中,是通过location配置段配合正则匹配实现静态与动态页面的不同处理方式。
Nginx是一种轻量级,高性能,多进程的Web服务器,非常适合作为静态资源的服务器使用,而动态的访问操作可以使用稳定的Apache、Tomcat及IIS等来实现,这里就以Nginx作为代理服务器的同时,也使用其作为静态资源的服务器,而动态的访问服务器就以tomcat为例说明。
说明:
1、代理服务器和静态服务器可以为一台服务器,也可以独立部署,这里代理服务器和静态服务器为一台服务器。
2、静态服务器中,存放的资源主要是源代码文件、图片、属性、样式以及其它所有非动态的资源文件。
3、调度规则,即为代理服务器,这里是Nginx的服务器调度规则。
4、动态服务器,其种类比较繁多,可以是Apache、Tomcat、IIS以及其它Web服务器,它们一般分别隶属于一台服务器。
vim /usr/local/nginx/conf/nginx.conf
user www www;
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
error_log logs/error.log;
worker_rlimit_nofile 10240;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'"$upstream_cache_status"';
access_log logs/access.log main;
server_tokens off;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_proxied any;
gzip_min_length 1k;
gzip_buffers 16 8k;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_buffering off;
proxy_temp_path /usr/local/nginx/proxy_temp;
proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2 keys_zone=my-cache:100m max_size=1000m inactive=600m max_size=2g;
#配置负载均衡
upstream tomcat_dynamic_pools { # tomcat动态服务器集群
server 192.168.1.12:8080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.1.13:8080 weight=1 max_fails=2 fail_timeout=10s;
}
upstream static_pools { #静态服务器集群
server 192.168.1.11:808 weight=1 max_fails=2 fail_timeout=10s;
}
#配置nginx静态服务器
server{
listen 808;
server_name www.nihao.com;
location / {
root html;
index index.html index.htm;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|rar|zip|txt|flv|mid|doc|ppt|xls|mp3|wma|html|htm|css|js|ico|swf|pdf)$ {
#所有静态文件直接读取硬盘内容:读取的静态资源存放位置
root html ;
#资源是否进行缓存与缓存时间
expires 30d; #缓存30天
}
}
#配置nginx动静分离
server {
listen 80;
server_name www.nihao.com;
charset utf-8;
location ~ .*\.jsp$ {
proxy_pass http://tomcat_dynamic_pools;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}
location / {
proxy_pass http://static_pools;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_cache my-cache;
add_header Nginx-Cache $upstream_cache_status;
proxy_cache_valid 200 304 301 302 8h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1d;
#proxy_cache_key $host$uri$is_args$args;
expires 30d;
}
}
}
192.168.121.10,访问的是nginx静态服务器的页面
192.168.121.10/index.jsp