nginx反向代理


一、Nginx反向代理

简而言之就是正向代理代理的对象是客户端,反向代理代理的是服务端,这是两者之间最大的区别。

Nginx即可以实现正向代理,也可以实现反向代理。

image-20210918230637643

1、正向代理(了解)

我们先来通过一个小案例演示下Nginx正向代理的简单应用。

先提需求:

(1)服务端的设置:

http {
  log_format main 'client send request=>clientIp=$remote_addr serverIp=>$host';
    server{
        listen 80;
        server_name    localhost;
        access_log logs/access.log main;
        location {
            root html;
            index index.html index.htm;
        }
    }
}

(2)使用客户端访问服务端,打开日志查看结果

client send request=>clientIp=192.168.200.1 serverIp=>192.168.200.133

(3)代理服务器设置:

server {

        listen  82;
        resolver 8.8.8.8;
        location /{
                proxy_pass http://$host$request_uri;
        }
    }

(4)查看代理服务器的IP(192.168.200.146)和Nginx配置监听的端口(82)

(5)在客户端配置代理服务器

(6)设置完成后,再次通过浏览器访问服务端

client send request=>clientIp=192.168.200.146 serverIp=>192.168.200.133

通过对比,上下两次的日志记录,会发现虽然我们是客户端访问服务端,但是如何使用了代理,那么服务端能看到的只是代理发送过去的请求,这样的化,就使用Nginx实现了正向代理的设置。

2、反向代理指令

Nginx反向代理模块的指令是由ngx_http_proxy_module模块进行解析,该模块在安装Nginx的时候已经自己加装到Nginx中了,接下来我们把反向代理中的常用指令一一介绍下:

proxy_pass
proxy_set_header
proxy_redirect

proxy_pass

该指令用来设置被代理服务器地址,可以是主机名称、IP地址加端口号形式。

语法 proxy_pass URL;
默认值
位置 location

URL:为要设置的被代理服务器地址,包含传输协议(http,https://)、主机名称或IP地址加端口号、URI等要素。

举例:

proxy_pass http://www.baidu.com;
location /server{}
proxy_pass http://192.168.200.146;
    http://192.168.200.146/server/index.html
proxy_pass http://192.168.200.146/;
    http://192.168.200.146/index.html

加不加/区别

大家在编写proxy_pass的时候,后面的值要不要加”/“?

接下来通过例子来说明刚才我们提到的问题:

server {
    listen 80;
    server_name localhost;
    location /{
        #proxy_pass http://192.168.200.146;
        proxy_pass http://192.168.200.146/;
    }
}
当客户端访问 http://localhost/index.html,效果是一样的
server{
    listen 80;
    server_name localhost;
    location /server{
        #proxy_pass http://192.168.200.146;
        proxy_pass http://192.168.200.146/;
    }
}
当客户端访问 http://localhost/server/index.html
这个时候,第一个proxy_pass就变成了http://localhost/server/index.html
第二个proxy_pass就变成了http://localhost/index.html效果就不一样了。

proxy_set_header

该指令可以更改Nginx服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给代理的服务器

语法 proxy_set_header field value;
默认值 proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
位置 http、server、location

需要注意的是,如果想要看到结果,必须在被代理的服务器上来获取添加的头信息。

被代理服务器: [192.168.200.146]

server {
        listen  8080;
        server_name localhost;
        default_type text/plain;
        return 200 $http_username;
}

代理服务器: [192.168.200.133]

server {
        listen  8080;
        server_name localhost;
        location /server {
                proxy_pass http://192.168.200.146:8080/;
                proxy_set_header username TOM;
        }
    }

访问测试

proxy_redirect

该指令是用来重置头信息中的”Location”和”Refresh”的值。

语法 proxy_redirect redirect replacement;
proxy_redirect default;
proxy_redirect off;
默认值 proxy_redirect default;
位置 http、server、location

》为什么要用该指令?

服务端[192.168.200.146]

server {
    listen  8081;
    server_name localhost;
    if (!-f $request_filename){
        return 302 http://192.168.200.146;
    }
}

代理服务端[192.168.200.133]

server {
    listen  8081;
    server_name localhost;
    location / {
        proxy_pass http://192.168.200.146:8081/;
        proxy_redirect http://192.168.200.146 http://192.168.200.133;
    }
}

》该指令的几组选项

proxy_redirect redirect replacement;

redirect:目标,Location的值
replacement:要替换的值

proxy_redirect default;

default;
将location块的uri变量作为replacement,
将proxy_pass变量作为redirect进行替换

proxy_redirect off;

关闭proxy_redirect的功能

3、反向代理实战

1581883378672

服务器1,2,3存在两种情况

第一种情况: 三台服务器的内容不一样。
第二种情况: 三台服务器的内容是一样。(见本文负载均衡)
  1. 如果服务器1、服务器2和服务器3的内容不一样,那我们可以根据用户请求来分发到不同的服务器。
代理服务器
server {
        listen          8082;
        server_name     localhost;
        location /server1 {
                proxy_pass http://192.168.200.146:9001/;
        }
        location /server2 {
                proxy_pass http://192.168.200.146:9002/;
        }
        location /server3 {
                proxy_pass http://192.168.200.146:9003/;
        }
}

服务端
server1
server {
        listen          9001;
        server_name     localhost;
        default_type text/html;
        return 200 '192.168.200.146:9001'
}
server2
server {
        listen          9002;
        server_name     localhost;
        default_type text/html;
        return 200 '192.168.200.146:9002'
}
server3
server {
        listen          9003;
        server_name     localhost;
        default_type text/html;
        return 200 '192.168.200.146:9003'
}

4、http转https

关于web服务器的安全是比较大的一个话题,里面所涉及的内容很多,Nginx反向代理是通过安全隔离来提升web服务器的安全

什么是安全隔离?

通过代理分开了客户端到应用程序服务器端的连接,实现了安全措施。在反向代理之前设置防火墙,仅留一个入口供代理服务器访问。

1589908851340

使用SSL对流量加密

http加密的说法就是将我们常用的http请求转变成https请求,那么这两个之间的区别简单的来说两个都是HTTP协议,只不过https是身披SSL外壳的http.

HTTPS是一种通过计算机网络进行安全通信的传输协议。它经由HTTP进行通信,利用SSL/TLS建立全通信,加密数据包,确保数据的安全性。

SSL(Secure Sockets Layer)安全套接层

TLS(Transport Layer Security)传输层安全

上述这两个是为网络通信提供安全及数据完整性的一种安全协议,TLS和SSL在传输层和应用层对网络连接进行加密。

总结来说为什么要使用https:

http协议是明文传输数据,存在安全问题,而https是加密传输,相当于http+ssl,并且可以防止流量劫持。

Nginx要想使用SSL,需要满足一个条件即需要添加一个模块--with-http_ssl_module,而该模块在编译的过程中又需要OpenSSL的支持,这个我们之前已经准备好了。

(1)添加SSL的支持

完成 --with-http_ssl_module模块的增量添加

》将原有/usr/local/nginx/sbin/nginx进行备份
》拷贝nginx之前的配置信息
》在nginx的安装源码进行配置指定对应模块  ./configure --with-http_ssl_module
》通过make模板进行编译
》将objs下面的nginx移动到/usr/local/nginx/sbin下
》在源码目录下执行  make upgrade进行升级,这个可以实现不停机添加新模块的功能

Nginx的SSL相关指令

因为刚才我们介绍过该模块的指令都是通过ngx_http_ssl_module模块来解析的。

ssl:该指令用来在指定的服务器开启HTTPS,可以使用 listen 443 ssl,后面这种方式更通用些。

语法 ssl on | off;
默认值 ssl off;
位置 http、server
server{
    listen 443 ssl;
}

ssl_certificate:为当前这个虚拟主机指定一个带有PEM格式证书的证书。

语法 ssl_certificate file;
默认值
位置 http、server

ssl_certificate_key:该指令用来指定PEM secret key文件的路径

语法 ssl_ceritificate_key file;
默认值
位置 http、server

ssl_session_cache:该指令用来配置用于SSL会话的缓存

语法 ssl_sesion_cache off|none|[builtin[:size]] [shared:name:size]
默认值 ssl_session_cache none;
位置 http、server

off:禁用会话缓存,客户端不得重复使用会话

none:禁止使用会话缓存,客户端可以重复使用,但是并没有在缓存中存储会话参数

builtin:内置OpenSSL缓存,仅在一个工作进程中使用。

shared:所有工作进程之间共享缓存,缓存的相关信息用name和size来指定

ssl_session_timeout:开启SSL会话功能后,设置客户端能够反复使用储存在缓存中的会话参数时间。

语法 ssl_session_timeout time;
默认值 ssl_session_timeout 5m;
位置 http、server

ssl_ciphers:指出允许的密码,密码指定为OpenSSL支持的格式

语法 ssl_ciphers ciphers;
默认值 ssl_ciphers HIGH:!aNULL:!MD5;
位置 http、server

可以使用openssl ciphers查看openssl支持的格式。

ssl_prefer_server_ciphers:该指令指定是否服务器密码优先客户端密码

语法 ssl_perfer_server_ciphers on|off;
默认值 ssl_perfer_server_ciphers off;
位置 http、server

(2)生成证书

方式一:使用阿里云/腾讯云等第三方服务进行购买。

方式二:使用openssl生成证书

先要确认当前系统是否有安装openssl

openssl version

安装下面的命令进行生成

mkdir /root/cert
cd /root/cert
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

(3)开启SSL实例

server {
    listen       443 ssl;
    server_name  localhost;

    ssl_certificate      server.cert;
    ssl_certificate_key  server.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;
    }
}

5、反向代理调优

反向代理值Buffer和Cache

Buffer翻译过来是”缓冲”,Cache翻译过来是”缓存”。

相同点:
两种方式都是用来提供IO吞吐效率,都是用来提升Nginx代理的性能。
不同点:
缓冲主要用来解决不同设备之间数据传递速度不一致导致的性能低的问题,缓冲中的数据一旦此次操作完成后,就可以删除。
缓存主要是备份,将被代理服务器的数据缓存一份到代理服务器,这样的话,客户端再次获取相同数据的时候,就只需要从代理服务器上获取,效率较高,缓存中的数据可以重复使用,只有满足特定条件才会删除.

proxy_buffering

》proxy_buffering :该指令用来开启或者关闭代理服务器的缓冲区;

语法 proxy_buffering on|off;
默认值 proxy_buffering on;
位置 http、server、location

proxy_buffers

》proxy_buffers:该指令用来指定单个连接从代理服务器读取响应的缓存区的个数和大小。

语法 proxy_buffers number size;
默认值 proxy_buffers 8 4k | 8K;(与系统平台有关)
位置 http、server、location

number:缓冲区的个数

size:每个缓冲区的大小,缓冲区的总大小就是number*size

proxy_buffer_size

》proxy_buffer_size:该指令用来设置从被代理服务器获取的第一部分响应数据的大小。保持与proxy_buffers中的size一致即可,当然也可以更小。

语法 proxy_buffer_size size;
默认值 proxy_buffer_size 4k | 8k;(与系统平台有关)
位置 http、server、location

proxy_busy_buffers_size

》proxy_busy_buffers_size:该指令用来限制同时处于BUSY状态的缓冲总大小。

语法 proxy_busy_buffers_size size;
默认值 proxy_busy_buffers_size 8k|16K;
位置 http、server、location

proxy_temp_path

》proxy_temp_path:当缓冲区存满后,仍未被Nginx服务器完全接受,响应数据就会被临时存放在磁盘文件上,该指令设置文件路径

语法 proxy_temp_path path;
默认值 proxy_temp_path proxy_temp;
位置 http、server、location

注意path最多设置三层。

proxy_temp_file_write_size

》proxy_temp_file_write_size:该指令用来设置磁盘上缓冲文件的大小。

语法 proxy_temp_file_write_size size;
默认值 proxy_temp_file_write_size 8K|16K;
位置 http、server、location

通用网站的配置

proxy_buffering on;
proxy_buffer_size 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

根据项目的具体内容进行相应的调节。

二、Nginx负载均衡

1、常见处理方式

(1)用户手动选择

这种方式比较原始,只要实现的方式就是在网站主页上面提供不同线路、不同服务器链接方式,让用户来选择自己访问的具体服务器,来实现负载均衡。

如,在网页下载东西的时候会有多个下载按钮,通用网络下载、电信网络下载、连通网络下载等。

(2)DNS轮询

域名系统(服务)协议(DNS)是一种分布式网络目录服务,主要用于域名与 IP 地址的相互转换。

大多域名注册商都支持对同一个主机名添加多条A记录,这就是DNS轮询,DNS服务器将解析请求按照A记录的顺序,随机分配到不同的IP上,这样就能完成简单的负载均衡。DNS轮询的成本非常低,在一些不重要的服务器,被经常使用。

如下是我们为某一个域名添加的IP地址,用2台服务器来做负载均衡。

1590064506355

我们发现使用DNS来实现轮询,不需要投入过多的成本,虽然DNS轮询成本低廉,但是DNS负载均衡存在明显的缺点。

  • 可靠性低

假设一个域名DNS轮询多台服务器,如果其中的一台服务器发生故障,那么所有的访问该服务器的请求将不会有所回应,即使你将该服务器的IP从DNS中去掉,但是由于各大宽带接入商将众多的DNS存放在缓存中,以节省访问时间,导致DNS不会实时更新。所以DNS轮流上一定程度上解决了负载均衡问题,但是却存在可靠性不高的缺点。

  • 负载均衡不均衡

DNS负载均衡采用的是简单的轮询负载算法,不能区分服务器的差异,不能反映服务器的当前运行状态,不能做到为性能好的服务器多分配请求,另外本地计算机也会缓存已经解析的域名到IP地址的映射,这也会导致使用该DNS服务器的用户在一定时间内访问的是同一台Web服务器,从而引发Web服务器减的负载不均衡。

负载不均衡则会导致某几台服务器负荷很低,而另外几台服务器负荷确很高,处理请求的速度慢,配置高的服务器分配到的请求少,而配置低的服务器分配到的请求多。

(3)四/七层负载均衡

介绍四/七层负载均衡之前,我们先了解一个概念,OSI(open system interconnection),叫开放式系统互联模型,这个是由国际标准化组织ISO指定的一个不基于具体机型、操作系统或公司的网络体系结构。该模型将网络通信的工作分为七层。

1584693830966

应用层:为应用程序提供网络服务。

表示层:对数据进行格式化、编码、加密、压缩等操作。

会话层:建立、维护、管理会话连接。

传输层:建立、维护、管理端到端的连接,常见的有TCP/UDP。

网络层:IP寻址和路由选择

数据链路层:控制网络层与物理层之间的通信。

物理层:比特流传输。

所谓四层负载均衡指的是OSI七层模型中的传输层,主要是基于IP+PORT的负载均衡

实现四层负载均衡的方式:
硬件:F5 BIG-IP、Radware等
软件:LVS、Nginx、Hayproxy等

所谓的七层负载均衡指的是在应用层,主要是基于虚拟的URL或主机IP的负载均衡

实现七层负载均衡的方式:
软件:Nginx、Hayproxy等

四层和七层负载均衡的区别

四层负载均衡数据包是在底层就进行了分发,而七层负载均衡数据包则在最顶端进行分发,所以四层负载均衡的效率比七层负载均衡的要高。
四层负载均衡不识别域名,而七层负载均衡识别域名。

处理四层和七层负载以为其实还有二层、三层负载均衡,二层是在数据链路层基于mac地址来实现负载均衡,三层是在网络层一般采用虚拟IP地址的方式实现负载均衡。

实际环境采用的模式

四层负载(LVS)+七层负载(Nginx)

2、七层负载均衡

Nginx要实现七层负载均衡需要用到proxy_pass代理模块配置。Nginx默认安装支持这个模块,我们不需要再做任何处理。Nginx的负载均衡是在Nginx的反向代理基础上把用户的请求根据指定的算法分发到一组【upstream虚拟服务池】。

upstream指令

该指令是用来定义一组服务器,它们可以是监听不同端口的服务器,并且也可以是同时监听TCP和Unix socket的服务器。服务器可以指定不同的权重,默认为1。

语法 upstream name {…}
默认值
位置 http
server指令

该指令用来指定后端服务器的名称和一些参数,可以使用域名、IP、端口或者unix socket

语法 server name [paramerters]
默认值
位置 upstream
实现流程

1590248160635

服务端设置

server {
    listen   9001;
    server_name localhost;
    default_type text/html;
    location /{
        return 200 '<h1>192.168.200.146:9001</h1>';
    }
}
server {
    listen   9002;
    server_name localhost;
    default_type text/html;
    location /{
        return 200 '<h1>192.168.200.146:9002</h1>';
    }
}
server {
    listen   9003;
    server_name localhost;
    default_type text/html;
    location /{
        return 200 '<h1>192.168.200.146:9003</h1>';
    }
}

负载均衡器设置

upstream backend{
    server 192.168.200.146:9091;
    server 192.168.200.146:9092;
    server 192.168.200.146:9093;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

负载均衡状态

代理服务器在负责均衡调度中的状态有以下几个:

状态 概述
down 当前的server暂时不参与负载均衡
backup 预留的备份服务器
max_fails 允许请求失败的次数
fail_timeout 经过max_fails失败后, 服务暂停时间
max_conns 限制最大的接收连接数
down

down:将该服务器标记为永久不可用,那么该代理服务器将不参与负载均衡。

upstream backend{
    server 192.168.200.146:9001 down;
    server 192.168.200.146:9002
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

该状态一般会对需要停机维护的服务器进行设置。

backup

backup:将该服务器标记为备份服务器,当主服务器不可用时,将用来传递请求。

upstream backend{
    server 192.168.200.146:9001 down;
    server 192.168.200.146:9002 backup;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

此时需要将9094端口的访问禁止掉来模拟下唯一能对外提供访问的服务宕机以后,backup的备份服务器就要开始对外提供服务,此时为了测试验证,我们需要使用防火墙来进行拦截。

介绍一个工具firewall-cmd,该工具是Linux提供的专门用来操作firewall的。

查询防火墙中指定的端口是否开放

firewall-cmd --query-port=9001/tcp

如何开放一个指定的端口

firewall-cmd --permanent --add-port=9002/tcp

批量添加开发端口

firewall-cmd --permanent --add-port=9001-9003/tcp

如何移除一个指定的端口

firewall-cmd --permanent --remove-port=9003/tcp

重新加载

firewall-cmd --reload

其中

​ –permanent表示设置为持久

​ –add-port表示添加指定端口

​ –remove-port表示移除指定端口

max_conns

max_conns=number:用来设置代理服务器同时活动链接的最大数量,默认为0,表示不限制,使用该配置可以根据后端服务器处理请求的并发量来进行设置,防止后端服务器被压垮。

max_fails和fail_timeout

max_fails=number:设置允许请求代理服务器失败的次数,默认为1。

fail_timeout=time:设置经过max_fails失败后,服务暂停的时间,默认是10秒。

upstream backend{
    server 192.168.200.133:9001 down;
    server 192.168.200.133:9002 backup;
    server 192.168.200.133:9003 max_fails=3 fail_timeout=15;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

负载均衡策略

介绍完Nginx负载均衡的相关指令后,我们已经能实现将用户的请求分发到不同的服务器上,那么除了采用默认的分配方式以外,我们还能采用什么样的负载算法?

Nginx的upstream支持如下六种方式的分配算法,分别是:

算法名称 说明
轮询 默认方式
weight 权重方式
ip_hash 依据ip分配方式
least_conn 依据最少连接方式
url_hash 依据URL分配方式
fair 依据响应时间方式
轮询

是upstream模块负载均衡默认的策略。每个请求会按时间顺序逐个分配到不同的后端服务器。轮询不需要额外的配置。

upstream backend{
    server 192.168.200.146:9001 weight=1;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}
weight加权[加权轮询]

weight=number:用来设置服务器的权重,默认为1,权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的,所有此策略比较适合服务器的硬件配置差别比较大的情况。

upstream backend{
    server 192.168.200.146:9001 weight=10;
    server 192.168.200.146:9002 weight=5;
    server 192.168.200.146:9003 weight=3;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}
ip_hash

当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某一个IP的用户在后端Web服务器A上登录后,在访问该站点的其他URL,能保证其访问的还是后端web服务器A。

语法 ip_hash;
默认值
位置 upstream
upstream backend{
    ip_hash;
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

需要额外多说一点的是使用ip_hash指令无法保证后端服务器的负载均衡,可能导致有些后端服务器接收到的请求多,有些后端服务器接收的请求少,而且设置后端服务器权重等方法将不起作用。

1591706748677

least_conn

最少连接,把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。

upstream backend{
    least_conn;
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。

1591809623736

url_hash

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。

upstream backend{
    hash &request_uri;
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

访问如下地址:

http://192.168.200.133:8083/a
http://192.168.200.133:8083/b
http://192.168.200.133:8083/c

1591812222306

fair

fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。那么如何使用第三方模块的fair负载均衡策略。

upstream backend{
    fair;
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}

但是如何直接使用会报错,因为fair属于第三方模块实现的负载均衡。需要添加nginx-upstream-fair,如何添加对应的模块:

  1. 下载nginx-upstream-fair模块
下载地址为:
    https://github.com/gnosek/nginx-upstream-fair
  1. 将下载的文件上传到服务器并进行解压缩
unzip nginx-upstream-fair-master.zip
  1. 重命名资源
mv nginx-upstream-fair-master fair
  1. 使用./configure命令将资源添加到Nginx模块中
./configure --add-module=/root/fair
  1. 编译
make

编译可能会出现如下错误,ngx_http_upstream_srv_conf_t结构中缺少default_port

解决方案:

在Nginx的源码中 src/http/ngx_http_upstream.h,找到ngx_http_upstream_srv_conf_s,在模块中添加添加default_port属性

in_port_t       default_port

然后再进行make.

  1. 更新Nginx

​ 6.1 将sbin目录下的nginx进行备份

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold

​ 6.2 将安装目录下的objs中的nginx拷贝到sbin目录

cd objs
cp nginx /usr/local/nginx/sbin

​ 6.3 更新Nginx

cd ../
make upgrade
  1. 编译测试使用Nginx

上面介绍了Nginx常用的负载均衡的策略,有人说是5种,是把轮询和加权轮询归为一种,也有人说是6种。那么在咱们以后的开发中到底使用哪种,这个需要根据实际项目的应用场景来决定的。

负载均衡案例

案例一:对所有请求实现一般轮询规则的负载均衡
upstream backend{
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}
案例二:对所有请求实现加权轮询规则的负载均衡
upstream backend{
    server 192.168.200.146:9001 weight=7;
    server 192.168.200.146:9002 weight=5;
    server 192.168.200.146:9003 weight=3;
}
server {
    listen 8083;
    server_name localhost;
    location /{
        proxy_pass http://backend;
    }
}
案例三:对特定资源实现负载均衡
upstream videobackend{
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
}
upstream filebackend{
    server 192.168.200.146:9003;
    server 192.168.200.146:9004;
}
server {
    listen 8084;
    server_name localhost;
    location /video/ {
        proxy_pass http://videobackend;
    }
    location /file/ {
        proxy_pass http://filebackend;
    }
}
案例四:对不同域名实现负载均衡
upstream itcastbackend{
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
}
upstream itheimabackend{
    server 192.168.200.146:9003;
    server 192.168.200.146:9004;
}
server {
    listen    8085;
    server_name www.itcast.cn;
    location / {
        proxy_pass http://itcastbackend;
    }
}
server {
    listen    8086;
    server_name www.itheima.cn;
    location / {
        proxy_pass http://itheimabackend;
    }
}
案例五:实现带有URL重写的负载均衡
upstream backend{
    server 192.168.200.146:9001;
    server 192.168.200.146:9002;
    server 192.168.200.146:9003;
}
server {
    listen    80;
    server_name localhost;
    location /file/ {
        rewrite ^(/file/.*) /server/$1 last;
    }
    location / {
        proxy_pass http://backend;
    }
}

3、四层负载均衡

Nginx在1.9之后,增加了一个stream模块,用来实现四层协议的转发、代理、负载均衡等。stream模块的用法跟http的用法类似,允许我们配置一组TCP或者UDP等协议的监听,然后通过proxy_pass来转发我们的请求,通过upstream添加多个后端服务,实现负载均衡。

四层协议负载均衡的实现,一般都会用到LVS、HAProxy、F5等,要么很贵要么配置很麻烦,而Nginx的配置相对来说更简单,更能快速完成工作。

添加stream模块的支持

Nginx默认是没有编译这个模块的,需要使用到stream模块,那么需要在编译的时候加上--with-stream

完成添加--with-stream的实现步骤:

》将原有/usr/local/nginx/sbin/nginx进行备份
》拷贝nginx之前的配置信息
》在nginx的安装源码进行配置指定对应模块  ./configure --with-stream
》通过make模板进行编译
》将objs下面的nginx移动到/usr/local/nginx/sbin下
》在源码目录下执行  make upgrade进行升级,这个可以实现不停机添加新模块的功能

Nginx四层负载均衡的指令

stream指令

该指令提供在其中指定流服务器指令的配置文件上下文。和http指令同级。

语法 stream { … }
默认值
位置 main
upstream指令

该指令和http的upstream指令是类似的。

四层负载均衡的案例

需求分析

1591897178807

实现步骤

(1)准备Redis服务器,在一条服务器上准备三个Redis,端口分别是6379,6378

1.上传redis的安装包,redis-4.0.14.tar.gz

2.将安装包进行解压缩

tar -zxf redis-4.0.14.tar.gz

3.进入redis的安装包

cd redis-4.0.14

4.使用make和install进行编译和安装

make PREFIX=/usr/local/redis/redis01 install

5.拷贝redis配置文件redis.conf到/usr/local/redis/redis01/bin目录中

cp redis.conf    /usr/local/redis/redis01/bin

6.修改redis.conf配置文件

port  6379      #redis的端口
daemonize yes   #后台启动redis

7.将redis01复制一份为redis02

cd /usr/local/redis
cp -r redis01 redis02

8.将redis02文件文件夹中的redis.conf进行修改

port  6378      #redis的端口
daemonize yes   #后台启动redis

9.分别启动,即可获取两个Redis.并查看

ps -ef | grep redis

使用Nginx将请求分发到不同的Redis服务器上。

(2)准备Tomcat服务器.

1.上传tomcat的安装包,apache-tomcat-8.5.56.tar.gz

2.将安装包进行解压缩

tar -zxf apache-tomcat-8.5.56.tar.gz

3.进入tomcat的bin目录

cd apache-tomcat-8.5.56/bin
./startup

nginx.conf配置

stream {
        upstream redisbackend {
                server 192.168.200.146:6379;
                server 192.168.200.146:6378;
        }
        upstream tomcatbackend {
                server 192.168.200.146:8080;
        }
        server {
                listen  81;
                proxy_pass redisbackend;
        }
        server {
                listen    82;
                proxy_pass tomcatbackend;
        }
}

访问测试。

三、Nginx缓存集成

缓存就是数据交换的缓冲区(称作:Cache),当用户要获取数据的时候,会先从缓存中去查询获取数据,如果缓存中有就会直接返回给用户,如果缓存中没有,则会发请求从服务器重新查询数据,将数据返回给用户的同时将数据放入缓存,下次用户就会直接从缓存中获取数据。

Nginx作为web服务器,Nginx作为Web缓存服务器,它介于客户端和应用服务器之间,当用户通过浏览器访问一个URL时,web缓存服务器会去应用服务器获取要展示给用户的内容,将内容缓存到自己的服务器上,当下一次请求到来时,如果访问的是同一个URL,web缓存服务器就会直接将之前缓存的内容返回给客户端,而不是向应用服务器再次发送请求。web缓存降低了应用服务器、数据库的负载,减少了网络延迟,提高了用户访问的响应速度,增强了用户的体验。

Nginx是从0.7.48版开始提供缓存功能。Nginx是基于Proxy Store来实现的,其原理是把URL及相关组合当做Key,在使用MD5算法对Key进行哈希,得到硬盘上对应的哈希目录路径,从而将缓存内容保存在该目录中。它可以支持任意URL连接,同时也支持404/301/302这样的非200状态码。Nginx即可以支持对指定URL或者状态码设置过期时间,也可以使用purge命令来手动清除指定URL的缓存。

1、相关指令

Nginx的web缓存服务主要是使用ngx_http_proxy_module模块相关指令集来完成,接下来我们把常用的指令来进行介绍下。

proxy_cache_path

该指定用于设置缓存文件的存放路径

语法 proxy_cache_path path [levels=number]
keys_zone=zone_name:zone_size [inactive=time][max_size=size];
默认值
位置 http

path:缓存路径地址,如:

/usr/local/proxy_cache

levels: 指定该缓存空间对应的目录,最多可以设置3层,每层取值为1|2如 :

levels=1:2   缓存空间有两层目录,第一次是1个字母,第二次是2个字母
举例说明:
itheima[key]通过MD5加密以后的值为 43c8233266edce38c2c9af0694e2107d
levels=1:2   最终的存储路径为/usr/local/proxy_cache/d/07
levels=2:1:2 最终的存储路径为/usr/local/proxy_cache/7d/0/21
levels=2:2:2 最终的存储路径为??/usr/local/proxy_cache/7d/10/e2

keys_zone:用来为这个缓存区设置名称和指定大小,如:

keys_zone=itcast:200m  缓存区的名称是itcast,大小为200M,1M大概能存储8000个keys

inactive:指定缓存的数据多次时间未被访问就将被删除,如:

inactive=1d   缓存数据在1天内没有被访问就会被删除

max_size:设置最大缓存空间,如果缓存空间存满,默认会覆盖缓存时间最长的资源,如:

max_size=20g

配置实例:

http{
    proxy_cache_path /usr/local/proxy_cache keys_zone=itcast:200m  levels=1:2:1 inactive=1d max_size=20g;
}

proxy_cache

该指令用来开启或关闭代理缓存,如果是开启则自定使用哪个缓存区来进行缓存。

语法 proxy_cache zone_name|off;
默认值 proxy_cache off;
位置 http、server、location

zone_name:指定使用缓存区的名称

proxy_cache_key

该指令用来设置web缓存的key值,Nginx会根据key值MD5哈希存缓存。

语法 proxy_cache_key key;
默认值 proxy_cache_key $scheme$proxy_host$request_uri;
位置 http、server、location

proxy_cache_valid

该指令用来对不同返回状态码的URL设置不同的缓存时间

语法 proxy_cache_valid [code …] time;
默认值
位置 http、server、location

如:

proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
为200和302的响应URL设置10分钟缓存,为404的响应URL设置1分钟缓存
proxy_cache_valid any 1m;
对所有响应状态码的URL都设置1分钟缓存

proxy_cache_min_uses

该指令用来设置资源被访问多少次后被缓存

语法 proxy_cache_min_uses number;
默认值 proxy_cache_min_uses 1;
位置 http、server、location

proxy_cache_methods

该指令用户设置缓存哪些HTTP方法

语法 proxy_cache_methods GET|HEAD|POST;
默认值 proxy_cache_methods GET HEAD;
位置 http、server、location

默认缓存HTTP的GET和HEAD方法,不缓存POST方法。

2、案例

http{
    proxy_cache_path /usr/local/proxy_cache levels=2:1 keys_zone=itcast:200m inactive=1d max_size=20g;
    upstream backend{
        server 192.168.200.146:8080;
    }
    server {
        listen       8080;
        server_name  localhost;
        location / {
            proxy_cache itcast;
            proxy_cache_key itheima;
            proxy_cache_min_uses 5;
            proxy_cache_valid 200 5d;
            proxy_cache_valid 404 30s;
            proxy_cache_valid any 1m;
            add_header nginx-cache "$upstream_cache_status";
            proxy_pass http://backend/js/;
        }
    }
}

3、缓存的清除

方式一:删除对应的缓存目录

rm -rf /usr/local/proxy_cache/......

方式二:使用第三方扩展模块

ngx_cache_purge

(1)下载ngx_cache_purge模块对应的资源包,并上传到服务器上。

ngx_cache_purge-2.3.tar.gz

(2)对资源文件进行解压缩

tar -zxf ngx_cache_purge-2.3.tar.gz

(3)修改文件夹名称,方便后期配置

mv ngx_cache_purge-2.3 purge

(4)查询Nginx的配置参数

nginx -V

(5)进入Nginx的安装目录,使用./configure进行参数配置

./configure --add-module=/root/nginx/module/purge

(6)使用make进行编译

make

(7)将nginx安装目录的nginx二级制可执行文件备份

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold

(8)将编译后的objs中的nginx拷贝到nginx的sbin目录下

cp objs/nginx /usr/local/nginx/sbin

(9)使用make进行升级

make upgrade

(10)在nginx配置文件中进行如下配置

server{
    location ~/purge(/.*) {
        proxy_cache_purge itcast itheima;
    }
}

4、设置资源不缓存

前面咱们已经完成了Nginx作为web缓存服务器的使用。但是我们得思考一个问题就是不是所有的数据都适合进行缓存。比如说对于一些经常发生变化的数据。如果进行缓存的话,就很容易出现用户访问到的数据不是服务器真实的数据。所以对于这些资源我们在缓存的过程中就需要进行过滤,不进行缓存。

Nginx也提供了这块的功能设置,需要使用到如下两个指令

proxy_no_cache

该指令是用来定义不将数据进行缓存的条件。

语法 proxy_no_cache string …;
默认值
位置 http、server、location

配置实例

proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;

proxy_cache_bypass

该指令是用来设置不从缓存中获取数据的条件。

语法 proxy_cache_bypass string …;
默认值
位置 http、server、location

配置实例

proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;

上述两个指令都有一个指定的条件,这个条件可以是多个,并且多个条件中至少有一个不为空且不等于”0”,则条件满足成立。上面给的配置实例是从官方网站获取的,里面使用到了三个变量,分别是$cookie_nocache、$arg_nocache、$arg_comment

这三个参数分别代表的含义是:

$cookie_nocache
指的是当前请求的cookie中键的名称为nocache对应的值
$arg_nocache和$arg_comment
指的是当前请求的参数中属性名为nocache和comment对应的属性值

案例演示下:

log_format params $cookie_nocache | $arg_nocache | $arg_comment;
server{
    listen    8081;
    server_name localhost;
    location /{
        access_log logs/access_params.log params;
        add_header Set-Cookie 'nocache=999';
        root html;
        index index.html;
    }
}

案例实现

设置不缓存资源的配置方案

server{
    listen    8080;
    server_name localhost;
    location / {
        if ($request_uri ~ /.*\.js$){
           set $nocache 1;
        }
        proxy_no_cache $nocache $cookie_nocache $arg_nocache $arg_comment;
        proxy_cache_bypass $nocache $cookie_nocache $arg_nocache $arg_comment;
    }
}

四、集群搭建

1、环境准备

1.准备Tomcat环境,并在Tomcat上部署一个web项目
2.准备Nginx环境,使用Nginx接收请求,并把请求分发到Tomat上
upstream webservice {
    server 192.168.200.146:8080;
}
server{
    listen        80;
    server_name localhost;
    location /demo {
        proxy_pass http://webservice;
    }
}

明明直接通过tomcat就能访问,为什么还需要多加一个nginx,这样不是反而是系统的复杂度变高了么?
那接下来从两个方面分析下这个问题,

第一个使用Nginx实现动静分离

第二个使用Nginx搭建Tomcat的集群

2、动静分离

什么是动静分离?

动:后台应用程序的业务处理

静:网站的静态资源(html,javaScript,css,images等文件)

分离:将两者进行分开部署访问,提供用户进行访问。举例说明就是以后所有和静态资源相关的内容都交给Nginx来部署访问,非静态内容则交个类似于Tomcat的服务器来部署访问。

为什么要动静分离?

​ 前面我们介绍过Nginx在处理静态资源的时候,效率是非常高的,而且Nginx的并发访问量也是名列前茅,而Tomcat则相对比较弱一些,所以把静态资源交个Nginx后,可以减轻Tomcat服务器的访问压力并提高静态资源的访问速度。

​ 动静分离以后,降低了动态资源和静态资源的耦合度。如动态资源宕机了也不影响静态资源的展示。

如何实现动静分离?

实现动静分离的方式很多,比如静态资源可以部署到CDN、Nginx等服务器上,动态资源可以部署到Tomcat,weblogic或者websphere上。本文只使用Nginx+Tomcat来实现动静分离。

假如某个时间点,由于某个原因导致Tomcat后的服务器宕机了,我们再次访问Nginx,会得到如下效果,用户还是能看到页面,只是缺失了访问次数的统计,这就是前后端耦合度降低的效果,并且整个请求只和后的服务器交互了一次,js和images都直接从Nginx返回,提供了效率,降低了后的服务器的压力。

配置Nginx的静态资源与动态资源的访问

upstream webservice{
   server 192.168.200.146:8080;
}
server {
        listen       80;
        server_name  localhost;

        #动态资源
        location /demo {
                proxy_pass http://webservice;
        }
        #静态资源
        location ~/.*\.(png|jpg|gif|js){
                root html/web;
                gzip on;
        }

        location / {
            root   html/web;
            index  index.html index.htm;
        }
}

3、部署tomcat集群

那么问题来了,如果Tomcat的真的宕机了,整个系统就会不完整,所以如何解决上述问题,一台服务器容易宕机,那就多搭建几台Tomcat服务器,这样的话就提升了后的服务器的可用性。这也就是我们常说的集群,搭建Tomcat的集群需要用到了Nginx的反向代理和赋值均衡的知识

在Nginx对应的配置文件中添加如下内容:

upstream webservice{
        server 192.168.200.146:8080;
        server 192.168.200.146:8180;
        server 192.168.200.146:8280;
    }

好了,完成了上述环境的部署,我们已经解决了Tomcat的高可用性,一台服务器宕机,还有其他两条对外提供服务,同时也可以实现后台服务器的不间断更新。但是新问题出现了,上述环境中,如果是Nginx宕机了呢,那么整套系统都将服务对外提供服务了,这个如何解决?

4、高可用解决方案

用于防止nginx宕机

需要两台以上的Nginx服务器对外提供服务,这样的话就可以解决其中一台宕机了,另外一台还能对外提供服务,但是如果是两台Nginx服务器的话,会有两个IP地址,用户该访问哪台服务器,用户怎么知道哪台是好的,哪台是宕机了的?

Keepalived

使用Keepalived来解决,Keepalived 软件由 C 编写的,最初是专为 LVS 负载均衡软件设计的,Keepalived 软件主要是通过 VRRP 协议实现高可用功能。

VRRP介绍

VRRP(Virtual Route Redundancy Protocol)协议,翻译过来为虚拟路由冗余协议。VRRP协议将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP,而在路由器组内部,如果实际拥有这个对外IP的路由器如果工作正常的话就是MASTER,MASTER实现针对虚拟路由器IP的各种网络功能。其他设备不拥有该虚拟IP,状态为BACKUP,处了接收MASTER的VRRP状态通告信息以外,不执行对外的网络功能。当主机失效时,BACKUP将接管原先MASTER的网络功能。

从上面的介绍信息获取到的内容就是VRRP是一种协议,那这个协议是用来干什么的?

1.选择协议

VRRP可以把一个虚拟路由器的责任动态分配到局域网上的 VRRP 路由器中的一台。其中的虚拟路由即Virtual路由是由VRRP路由群组创建的一个不真实存在的路由,这个虚拟路由也是有对应的IP地址。而且VRRP路由1和VRRP路由2之间会有竞争选择,通过选择会产生一个Master路由和一个Backup路由。

2.路由容错协议

Master路由和Backup路由之间会有一个心跳检测,Master会定时告知Backup自己的状态,如果在指定的时间内,Backup没有接收到这个通知内容,Backup就会替代Master成为新的Master。Master路由有一个特权就是虚拟路由和后端服务器都是通过Master进行数据传递交互的,而备份节点则会直接丢弃这些请求和数据,不做处理,只是去监听Master的状态

用了Keepalived后,解决方案如下:

1604495442179

环境搭建

环境准备

VIP IP 主机名 主/从
192.168.200.133 keepalived1 Master
192.168.200.222
192.168.200.122 keepalived2 Backup

keepalived的安装

步骤1:从官方网站下载keepalived,官网地址https://keepalived.org/
步骤2:将下载的资源上传到服务器
    keepalived-2.0.20.tar.gz
步骤3:创建keepalived目录,方便管理资源
    mkdir keepalived
步骤4:将压缩文件进行解压缩,解压缩到指定的目录
    tar -zxf keepalived-2.0.20.tar.gz -C keepalived/
步骤5:对keepalived进行配置,编译和安装
    cd keepalived/keepalived-2.0.20
    ./configure --sysconf=/etc --prefix=/usr/local
    make && make install

安装完成后,有两个文件需要我们认识下,一个是 /etc/keepalived/keepalived.conf(keepalived的系统配置文件,我们主要操作的就是该文件),一个是/usr/local/sbin目录下的keepalived,是系统配置脚本,用来启动和关闭keepalived

Keepalived配置文件

打开keepalived.conf配置文件

这里面会分三部,第一部分是global全局配置、第二部分是vrrp相关配置、第三部分是LVS相关配置。
本次课程主要是使用keepalived实现高可用部署,没有用到LVS,所以我们重点关注的是前两部分

global全局部分:
global_defs {
   #通知邮件,当keepalived发送切换时需要发email给具体的邮箱地址
   notification_email {
     tom@itcast.cn
     jerry@itcast.cn
   }
   #设置发件人的邮箱信息
   notification_email_from zhaomin@itcast.cn
   #指定smpt服务地址
   smtp_server 192.168.200.1
   #指定smpt服务连接超时时间
   smtp_connect_timeout 30
   #运行keepalived服务器的一个标识,可以用作发送邮件的主题信息
   router_id LVS_DEVEL

   #默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的master路由器,则不执行检查(跳过检查)
   vrrp_skip_check_adv_addr
   #严格遵守VRRP协议。
   vrrp_strict
   #在一个接口发送的两个免费ARP之间的延迟。可以精确到毫秒级。默认是0
   vrrp_garp_interval 0
   #在一个网卡上每组na消息之间的延迟时间,默认为0
   vrrp_gna_interval 0
}
VRRP部分,该部分可以包含以下四个子模块
1. vrrp_script
2. vrrp_sync_group
3. garp_group
4. vrrp_instance
我们会用到第一个和第四个,
#设置keepalived实例的相关信息,VI_1为VRRP实例名称
vrrp_instance VI_1 {
    state MASTER          #有两个值可选MASTER主 BACKUP备
    interface ens33        #vrrp实例绑定的接口,用于发送VRRP包[当前服务器使用的网卡名称]
    virtual_router_id 51#指定VRRP实例ID,范围是0-255
    priority 100        #指定优先级,优先级高的将成为MASTER
    advert_int 1        #指定发送VRRP通告的间隔,单位是秒
    authentication {    #vrrp之间通信的认证信息
        auth_type PASS    #指定认证方式。PASS简单密码认证(推荐)
        auth_pass 1111    #指定认证使用的密码,最多8位
    }
    virtual_ipaddress { #虚拟IP地址设置虚拟IP地址,供用户访问使用,可设置多个,一行一个
        192.168.200.222
    }
}

配置内容如下:

服务器1

global_defs {
   notification_email {
        tom@itcast.cn
        jerry@itcast.cn
   }
   notification_email_from zhaomin@itcast.cn
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id keepalived1
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.222
    }
}

服务器2

! Configuration File for keepalived

global_defs {
   notification_email {
        tom@itcast.cn
        jerry@itcast.cn
   }
   notification_email_from zhaomin@itcast.cn
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id keepalived2
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.222
    }
}

访问测试

  1. 启动keepalived之前,咱们先使用命令 ip a,查看192.168.200.133和192.168.200.122这两台服务器的IP情况。

1604599529242

  1. 分别启动两台服务器的keepalived
cd /usr/local/sbin
./keepalived

再次通过 ip a查看ip

1604599616821

  1. 当把192.168.200.133服务器上的keepalived关闭后,再次查看ip

1604599709822

通过上述的测试,我们会发现,虚拟IP(VIP)会在MASTER节点上,当MASTER节点上的keepalived出问题以后,因为BACKUP无法收到MASTER发出的VRRP状态通过信息,就会直接升为MASTER。VIP也会”漂移”到新的MASTER。

上面测试和Nginx有什么关系?

我们把192.168.200.133服务器的keepalived再次启动下,由于它的优先级高于服务器192.168.200.122的,所有它会再次成为MASTER,VIP也会”漂移”过去,然后我们再次通过浏览器访问:

http://192.168.200.222/

1604600079149

如果把192.168.200.133服务器的keepalived关闭掉,再次访问相同的地址

1604600145318

效果实现了以后, 我们会发现要想让vip进行切换,就必须要把服务器上的keepalived进行关闭,而什么时候关闭keepalived呢?应该是在keepalived所在服务器的nginx出现问题后,把keepalived关闭掉,就可以让VIP执行另外一台服务器,但是现在这所有的操作都是通过手动来完成的,我们如何能让系统自动判断当前服务器的nginx是否正确启动,如果没有,要能让VIP自动进行”漂移”,这个问题该如何解决?

keepalived之vrrp_script

keepalived只能做到对网络故障和keepalived本身的监控,即当出现网络故障或者keepalived本身出现问题时,进行切换。但是这些还不够,我们还需要监控keepalived所在服务器上的其他业务,比如Nginx,如果Nginx出现异常了,仅仅keepalived保持正常,是无法完成系统的正常工作的,因此需要根据业务进程的运行状态决定是否需要进行主备切换,这个时候,我们可以通过编写脚本对业务进程进行检测监控。

实现步骤:

  1. 在keepalived配置文件中添加对应的配置像
vrrp_script 脚本名称
{
    script "脚本位置"
    interval 3 #执行时间间隔
    weight -20 #动态调整vrrp_instance的优先级
}
  1. 编写脚本

ck_nginx.sh

#!/bin/bash
num=`ps -C nginx --no-header | wc -l`
if [ $num -eq 0 ];then
 /usr/local/nginx/sbin/nginx
 sleep 2
 if [ `ps -C nginx --no-header | wc -l` -eq 0 ]; then
  killall keepalived
 fi
fi

Linux ps命令用于显示当前进程 (process) 的状态。

-C(command) :指定命令的所有进程

–no-header 排除标题

  1. 为脚本文件设置权限
chmod 755 ck_nginx.sh
  1. 将脚本添加到
vrrp_script ck_nginx {
   script "/etc/keepalived/ck_nginx.sh" #执行脚本的位置
   interval 2        #执行脚本的周期,秒为单位
   weight -20        #权重的计算方式
}
vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 10
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.111
    }
    track_script {
      ck_nginx
    }
}
  1. 如果效果没有出来,可以使用 tail -f /var/log/messages查看日志信息,找对应的错误信息。
  2. 测试

问题思考:

通常如果master服务死掉后backup会变成master,但是当master服务又好了的时候 master此时会抢占VIP,这样就会发生两次切换对业务繁忙的网站来说是不好的。所以我们要在配置文件加入 nopreempt 非抢占,但是这个参数只能用于state 为backup,故我们在用HA的时候最好master 和backup的state都设置成backup 让其通过priority来竞争。

五、制作下载站点

首先我们先要清楚什么是下载站点?

我们先来看一个网站http://nginx.org/download/这个我们刚开始学习Nginx的时候给大家看过这样的网站,该网站主要就是用来提供用户来下载相关资源的网站,就叫做下载网站。

如何制作一个下载站点:

nginx使用的是模块ngx_http_autoindex_module来实现的,该模块处理以斜杠(“/“)结尾的请求,并生成目录列表。

nginx编译的时候会自动加载该模块,但是该模块默认是关闭的,我们需要使用下来指令来完成对应的配置

(1)autoindex:启用或禁用目录列表输出

语法 autoindex on|off;
默认值 autoindex off;
位置 http、server、location

(2)autoindex_exact_size:对应HTLM格式,指定是否在目录列表展示文件的详细大小

默认为on,显示出文件的确切大小,单位是bytes。
改为off后,显示出文件的大概大小,单位是kB或者MB或者GB

语法 autoindex_exact_size on|off;
默认值 autoindex_exact_size on;
位置 http、server、location

(3)autoindex_format:设置目录列表的格式

语法 autoindex_format html|xml|json|jsonp;
默认值 autoindex_format html;
位置 http、server、location

注意:该指令在1.7.9及以后版本中出现

(4)autoindex_localtime:对应HTML格式,是否在目录列表上显示时间。

默认为off,显示的文件时间为GMT时间。
改为on后,显示的文件时间为文件的服务器时间

语法 autoindex_localtime on | off;
默认值 autoindex_localtime off;
位置 http、server、location

配置方式如下:

location /download{
    root /usr/local;
    autoindex on;
    autoindex_exact_size on;
    autoindex_format html;
    autoindex_localtime on;
}

XML/JSON格式[一般不用这两种方式]

六、用户认证模块

对应系统资源的访问,我们往往需要限制谁能访问,谁不能访问。这块就是我们通常所说的认证部分,认证需要做的就是根据用户输入的用户名和密码来判定用户是否为合法用户,如果是则放行访问,如果不是则拒绝访问。

Nginx对应用户认证这块是通过ngx_http_auth_basic_module模块来实现的,它允许通过使用”HTTP基本身份验证”协议验证用户名和密码来限制对资源的访问。默认情况下nginx是已经安装了该模块,如果不需要则使用–without-http_auth_basic_module。

该模块的指令比较简单,

(1)auth_basic:使用“ HTTP基本认证”协议启用用户名和密码的验证

语法 auth_basic string|off;
默认值 auth_basic off;
位置 http,server,location,limit_except

开启后,服务端会返回401,指定的字符串会返回到客户端,给用户以提示信息,但是不同的浏览器对内容的展示不一致。

(2)auth_basic_user_file:指定用户名和密码所在文件

语法 auth_basic_user_file file;
默认值
位置 http,server,location,limit_except

指定文件路径,该文件中的用户名和密码的设置,密码需要进行加密。可以采用工具自动生成

实现步骤:

1.nginx.conf添加如下内容

location /download{
    root /usr/local;
    autoindex on;
    autoindex_exact_size on;
    autoindex_format html;
    autoindex_localtime on;
    auth_basic 'please input your auth';
    auth_basic_user_file htpasswd;
}

2.我们需要使用htpasswd工具生成

yum install -y httpd-tools
htpasswd -c /usr/local/nginx/conf/htpasswd username //创建一个新文件记录用户名和密码
htpasswd -b /usr/local/nginx/conf/htpasswd username password //在指定文件新增一个用户名和密码
htpasswd -D /usr/local/nginx/conf/htpasswd username //从指定文件删除一个用户信息
htpasswd -v /usr/local/nginx/conf/htpasswd username //验证用户名和密码是否正确

上述方式虽然能实现用户名和密码的验证,但是大家也看到了,所有的用户名和密码信息都记录在文件里面,如果用户量过大的话,这种方式就显得有点麻烦了,这时候我们就得通过后台业务代码来进行用户权限的校验了。


  目录