Post

Nginx 讲义

一、Nginx是什么?

​ Nginx (engine x) 是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的Web和反向代理服务器。第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。Nginx 是一个很强大的高性能 Web 和反向代理服务器,它具有很多非常优越的特性:在连接高并发的情况下,Nginx 是 Apache 服务不错的替代品。

1、 Nginx (“engine x”) 是一个高性能的 静态HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。

2、 第一个公开版本0.1.0发布于2004年10月4日。

3、 其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名

4、 官方测试nginx能够支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定

5、 2011年6月1日,nginx 1.0.4发布。

6、 事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:新浪、网易、腾讯、阿里、土豆网、唯品会、京东、360、优酷等。

img

二、为什么学习Nginx?

2.1 现实生活中的案例

2.2 web系统架构变迁中遇到的问题

  1. 单体服务架构:

  2. 应用服务集群架构

  3. 微服务架构

2.3 如何解决这些问题?

解决的技术方案如下:

  1. 购买硬件负载均衡服务器,问题是需要花钱,价格不菲。

    img

  2. LVS(OSI 七层模型第四层“传输层“),配置复杂,使用难度高。

  3. Nginx可以有效解决高并发的问题,那么什么是Nginx呢?

三、Nginx作用

  • 搭建虚拟主机

  • 服务的反向代理

  • 在反向代理中配置集群的负载均衡
  • 在反向代理中配置集群的动静分离

​ 代理服务器根据其代理对象的不同,可以分为正向代理服务器与反向代理服务器。这里的“正”与“反”均是站在客户端角度来说的。

3.1 正向代理

​ 正向代理是对客户端的代理。客户端 C 想要从服务端 S 获取资源,但由于某些原因不能直接访问服务端,而是通过另外一台主机 P 向服务端发送请求。当服务端处理完毕请求后,将响应发送给主机 P,主机 P 在接收到来自服务端的响应后,将响应又转给了客户端 C。此时的主机 P,就称为客户端 C 的正向代理服务器。

​ 客户端在使用正向代理服务器时是知道其要访问的目标服务器的地址等信息的。正向代理服务器是为服务用户(客户端)而架设的主机,与服务端无关,对服务器端透明。

img

img

img

3.2 反向代理

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

img

img

3.3 反向代理之负载均衡

img

3.4 反向代理之动静分离

img

四、Nginx下载与安装

4.1 Nginx下载

官网下载Nginx软件https://nginx.org

img

点击右侧的“download”:

img

网址:https://nginx.org/en/download.html

Nginx 官方提供了三个类型的版本:

Mainline Version:主线版,是最新版,但未经过过多的生产测试。

Stable Version:稳定版,生产环境使用版本。

Legacy Version:老版本。

我们需要下载的是 Stable Version。其中又分为两种版本:Linux 版与 Windows 版。开发时这两个版本我们都下载。Linux 版用于生产环境,而 Windows 版用于开发测试,选择需要的版本进行下载。

4.2 Nginx 的源码安装

4.2.1 安装 Nginx依赖

nginx是C语言开发,建议在linux上运行,本视频使用CentOS7.9作为安装环境。

1.gcc

安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc。

1
yum install -y gcc  make  automake

2.pcre

PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 Perl 兼容的正则表达式库。nginx的http模块使用Pcre来解析正则表达式,所以需要在linux上安装Pcre库。

1
yum install -y pcre pcre-devel

注:pcre-devel是使用pcre开发的一个二次开发库。nginx也需要此库。

3.zlib

zlib库提供了很多种压缩和解压缩的方式,nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库。

1
yum install -y zlib zlib-devel

4.Openssl

OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。

nginx不仅支持http协议,还支持https(即在ssl协议上传输http),所以需要在linux安装openssl库。

1
yum install -y openssl openssl-devel

5.统一安装依赖环境命令:

1
yum -y install gcc make automake pcre-devel zlib zlib-devel openssl openssl-devel

4.2.2 安装 Nginx

1.创建存放源文件的文件夹

首先在目录/opt下创建apps目录,用于存放源文件以及解压后的文件

2.上传Nginx到步骤1创建的目录下

3.解压 Nginx

1
2
3
4
5
6
[root@node1 apps]# pwd
/opt/apps
[root@node1 apps]# ls
nginx-1.20.1.tar.gz
[root@node1 apps]# tar -zxvf nginx-1.20.1.tar.gz
[root@node1 apps]# cd  nginx-1.20.1

进入到 Nginx 解压包目录/opt/apps/nginx-1.20.1 目录中,查看 Nginx 的目录。

其中各个目录中存放的文件作用为:

auto:存放 Nginx 自动安装的相关文件

conf:存放 Nginx 服务器配置文件

configure:命令,用于对即将安装的软件的配置,完成 makefile 编译文件的生成

contrib:存放由其他机构贡献的文档材料

html:存放 Nginx 欢迎页面

man:manual,手册,存放 Nginx 帮助文档

src:存放 Nginx 源码

4.生成 makefile

在 Nginx 解压目录下运行 make 命令,用于完成编译。但此时会给出提示:没有指定目标,并且没有发现编译文件 makefile。

1
2
[root@node1 nginx-1.20.1]# make
make: *** 没有指明目标并且找不到 makefile。 停止。

编译命令 make 需要根据编译文件 makefile 进行编译,所以在编译之前需要先生成编译文件 makefile。使用 configure 命令可以生成该文件。那么,configure 命令需要配置些什么参数呢?使用–help 可以查看到可以使用的参数说明。这些参数可以分为三类:

第一类:基本信息的配置。

–prefix:Nginx 安装目录。注意,安装目录与解压目录不一样

–sbin-path:Nginx 命令文件

–modules-path:Nginx 模块存放路径

–conf-prefix:Nginx 配置文件存放路径

–pid-path:Nginx 的进程 id 文件

–error-log-path:错误日志文件

–http-log-path:http访问日志文件

第二类:默认没有安装,可以指定安装的模块,使用–with 开头。Nginx 的高扩展性就体现在这里。

–with_http_ssl_module:https 访问协议需要安装 Http 安全连接协议模块 SSL(Secure SocketsLayer,安全套接层)。注意,在执行过 configure 命令后并不会立即生成安装目录,也不会马上开始安装指定的模块,而仅仅是将命令中指定的参数及默认配置写入到即将要生成的 Makefile文件中。

第三类:默认已经安装,可以指定卸载的模块,使用–without 开头。

下面是简单配置的命令执行。命令中每一行的最后添加了反斜杠\表示当前命令并未结束,回车不会执行该命令。执行成功后,会给出配置报告。

配置成功后,再次查看 Nginx 解压目录,发现其中多出了一个文件 Makefile。后面的编译就是依靠该文件进行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@node1 nginx-1.20.1]# mkdir -p /var/temp/nginx/client
[root@node1 nginx-1.20.1]# pwd
/opt/apps/nginx-1.20.1
[root@node1 nginx-1.20.1]# ./configure \
--prefix=/usr/local/nginx \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--with-http_ssl_module \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/temp/nginx/client \
--http-proxy-temp-path=/var/temp/nginx/proxy \
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi

注意: /var/temp/nginx/client目录需要手动创建

5.编译安装

这是两个命令,make 为编译命令,make install 为安装命令,可以分别执行。这里使用&&将两个命令连接执行,会在前面命令执行成功的前提下才会执行第二个命令。

1
make && make install

4.3 Nginx目录介绍

1
2
3
4
5
6
7
8
#安装目录由--prefix=/usr/local/nginx
[root@node1 ~]# cd /usr/local/nginx/
[root@node1 nginx]# ll
总用量 0
drwxr-xr-x 2 root root 333 8月  27 15:37 conf
drwxr-xr-x 2 root root  40 8月  27 15:37 html
drwxr-xr-x 2 root root   6 8月  27 15:37 logs
drwxr-xr-x 2 root root  19 8月  27 15:37 sbin

4.3.1 conf目录

Nginx所有配置文件的目录,极其重要。在该目录中包含一个nginx.conf配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@node1 nginx]# ll conf/
总用量 68
-rw-r--r-- 1 root root 1077 8月  27 15:37 fastcgi.conf
-rw-r--r-- 1 root root 1077 8月  27 15:37 fastcgi.conf.default
-rw-r--r-- 1 root root 1007 8月  27 15:37 fastcgi_params
-rw-r--r-- 1 root root 1007 8月  27 15:37 fastcgi_params.default
-rw-r--r-- 1 root root 2837 8月  27 15:37 koi-utf
-rw-r--r-- 1 root root 2223 8月  27 15:37 koi-win
-rw-r--r-- 1 root root 5231 8月  27 15:37 mime.types
-rw-r--r-- 1 root root 5231 8月  27 15:37 mime.types.default
-rw-r--r-- 1 root root 2656 8月  27 15:37 nginx.conf
-rw-r--r-- 1 root root 2656 8月  27 15:37 nginx.conf.default
-rw-r--r-- 1 root root  636 8月  27 15:37 scgi_params
-rw-r--r-- 1 root root  636 8月  27 15:37 scgi_params.default
-rw-r--r-- 1 root root  664 8月  27 15:37 uwsgi_params
-rw-r--r-- 1 root root  664 8月  27 15:37 uwsgi_params.default
-rw-r--r-- 1 root root 3610 8月  27 15:37 win-utf

4.3.2 html目录

Nginx的默认站点目录。

1
2
3
4
[root@node1 nginx]# ll html/
总用量 8
-rw-r--r-- 1 root root 494 8月  27 15:37 50x.html #错误提示页面
-rw-r--r-- 1 root root 612 8月  27 15:37 index.html #访问nginx时的首页

4.3.3 logs目录

存放Nginx的日志文件。 access.log error.log

1
2
3
4
5
6
7
8
#刚安装完nginx,从未启动过的话logs目录下什么都没有,只有启动nginx后,才会出现以下三个文件
[root@node1 nginx]# ll logs/
总用量 4
-rw-r--r-- 1 root root 0 8月  27 16:29 access.log #记录正常访问的日志
-rw-r--r-- 1 root root 0 8月  27 16:29 error.log #错误日志
-rw-r--r-- 1 root root 6 8月  27 16:29 nginx.pid #nginx进程id
[root@node1 nginx]# cat logs/nginx.pid 
24514 #当前启动nginx的master进程的id

4.3.4 sbin目录

Nginx命令的目录,如Nginx的启动命令。

1
2
3
4
5
6
7
[root@node1 nginx]# ll sbin/
总用量 5884
-rwxr-xr-x 1 root root 6023208 8月  27 15:37 nginx #启动关闭等操作的脚本
[root@node1 nginx]# ./sbin/nginx #启动nginx
[root@node1 nginx]# ps aux|grep nginx #查看nginx的进程
root      24514  0.0  0.1  45996  1136 ?        Ss   16:29   0:00 nginx: master process ./sbin/nginx
nobody    24515  0.0  0.1  46444  1876 ?        S    16:29   0:00 nginx: worker process

4.4 Nginx启动与关闭

4.4.1 Nginx启动

1.关闭防火墙命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
#关闭防火墙,系统重启后还会启动
[root@node1 ~]# systemctl stop firewalld  
[root@node1 ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)

#禁用防火墙,系统重启后
[root@node1 ~]# systemctl disable firewalld
[root@node1 ~]# systemctl list-unit-files |grep firewalld
firewalld.service                           disabled 

2.启动Nginx:运行sbin目录下的nginx命令即可。

1
2
3
4
5
6
7
8
[root@node1 ~]# cd /usr/local/nginx/sbin/
[root@node1 sbin]# ls
nginx
[root@node1 sbin]# ./nginx 
[root@node1 sbin]# ps aux|grep nginx
root      46423  0.0  0.0  40884   800 ?        Ss   16:13   0:00 nginx: master process ./nginx
nobody    46424  0.0  0.5  73964  4244 ?        S    16:13   0:00 nginx: worker process
root      46426  0.0  0.1  12344  1152 pts/4    S+   16:13   0:00 grep --color=auto nginx

3.测试:https://192.168.20.101

4.4.2 关闭Nginx

1.立即停止服务

这种方法比较强硬,无论进程是否在工作,都直接停止进程。

1
2
3
[root@node1 sbin]# ./nginx -s stop
[root@node1 sbin]# ps aux|grep nginx
root      25496  0.0  0.0 112824   980 pts/0    S+   16:44   0:00 grep --color=auto nginx

2.从容停止服务

这种方法较stop相比就比较温和一些了,需要进程完成当前工作后再停止。

1
2
3
4
5
6
7
8
[root@node1 sbin]# ./nginx 
[root@node1 sbin]# ps aux|grep nginx 
root      25482  0.0  0.1  45996  1132 ?        Ss   16:44   0:00 nginx: master process ./nginx
nobody    25483  0.0  0.1  46444  1872 ?        S    16:44   0:00 nginx: worker process
root      25496  0.0  0.0 112824   980 pts/0    S+   16:44   0:00 grep --color=auto nginx
[root@node1 sbin]# ./nginx -s quit
[root@node1 sbin]# ps aux|grep nginx
root      25496  0.0  0.0 112824   980 pts/0    S+   16:44   0:00 grep --color=auto nginx

3.killall 方法杀死进程

直接杀死进程,在上面无效的情况下使用,态度强硬,简单粗暴!

1
2
3
4
5
6
7
8
[root@node1 sbin]# ./nginx 
[root@node1 sbin]# ps aux|grep nginx 
root      25482  0.0  0.1  45996  1132 ?        Ss   16:44   0:00 nginx: master process ./nginx
nobody    25483  0.0  0.1  46444  1872 ?        S    16:44   0:00 nginx: worker process
root      25496  0.0  0.0 112824   980 pts/0    S+   16:44   0:00 grep --color=auto nginx
[root@node1 sbin]# killall nginx 
[root@node1 sbin]# ps aux|grep nginx 
root      25574  0.0  0.0 112824   984 pts/0    S+   16:46   0:00 grep --color=auto nginx

4.4.3 设置开机自启动

1.进到系统服务添加路径:

1
[root@node1 sbin]# cd /usr/lib/systemd/system/ 

2.建立服务文件nginx.service

注意nginx 的安装路径保持一样:  /usr/local/nginx/

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@node1 system]# vim nginx.service
[Unit]
Description=nginx - high performance web server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop

[Install]
WantedBy=multi-user.target

[Unit]服务的说明

Description:服务的简单描述 After:依赖,仅当依赖的服务启动之后再启动自定义的服务单元

[Service]服务运行参数的设置 Type=forking是后台运行的形式 ExecStart为服务的具体运行命令 ExecReload为重启命令 ExecStop为停止命令 注意:启动、重启、停止命令全部要求使用绝对路径

[Install]服务安装的相关设置,可设置为多用户

3.添加执行权限

以755的权限保存在目录:  /usr/lib/systemd/system

1
[root@node1 system]# chmod +x nginx.service 

4.设置开机自启动

可在任意目录下执行

1
2
3
[root@node1 system]# systemctl enable nginx  
[root@node1 system]# systemctl list-unit-files |grep nginx
nginx.service                               enabled

5.其他命令 以下以nginx 为例

1
2
3
4
5
启动nginx服务:  systemctl start nginx
停止开机自启动:  systemctl disable nginx
查看服务当前状态:  systemctl status nginx
重新启动服务:   systemctl restart nginx
查看所有已启动的服务: systemctl list-units --type=service 

4.5 Nginx配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#全局块
# 指定可以运行nginx服务的用户和用户组,只能在全局块配置
#user  nobody;
#nginx进程,一般数值为cpu核数
worker_processes  1;
#错误日志存放目录
#error_log  logs/error.log; #     warn  error   
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#进程pid存放位置
#pid        logs/nginx.pid;

#event块
#工作模式及连接数上限
events {
    #单个后台worker process进程的最大并发链接数
    worker_connections  1024;
}

#http块
#http块是Nginx服务器配置中的重要部分,代理、缓存和日志定义等绝大多数的功能
#和第三方模块的配置都可以放在这个模块中。
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"';
    #nginx访问日志
    #access_log  logs/access.log  main;
    #开启高效传输模式   
    sendfile        on;
    #激活tcp_nopush参数可以允许把httpresponse header和文件的开始放在一个文件里发布, 积极的作用是减少网络报文段的数量
    #tcp_nopush     on;
    #连接超时时间,单位是秒
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #开启gzip压缩功能
    #gzip  on;
    
#server块
#server块和“虚拟主机”的概念有密切联系。
    server {
        #监听端口
        listen       80;
        server_name  localhost;
        #编码识别
        #charset koi8-r;
        #日志格式及日志存放路径 /usr/local/nginx/
        #access_log  logs/host.access.log  main;

        location / {
            #站点根目录,即网站程序存放目录 /usr/local/nginx/html
            root   html;
            #首页排序
            index  index.html index.htm;
        }
        #错误页面
        #error_page  404              /404.html;
        # 将服务器错误页面重定向到静态页面/50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html { #/usr/local/nginx/html/50x.html
            root   html;
        }        

       
        #代理PHP脚本到Apache上监听127.0.0.1:80
        #location ~ \.php$ {
        #    proxy_pass   https://127.0.0.1;
        #}

   
        #将PHP脚本传递到正在监听127.0.0.1:9000的FastCGI服务器
        #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;
        #}

        #如果Apache的文档根目录与nginx的根目录一致,则拒绝访问.htaccess文件
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    #另一个虚拟主机,混合使用IP、名称和基于端口的配置
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    # HTTPS server
    #
    #server { # https
    #    listen       443 ssl;
    #    server_name  localhost;
    #    服务的证书
    #    ssl_certificate      cert.pem;
    #    服务端key
    #    ssl_certificate_key  cert.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实战

5.1 配置虚拟主机

5.1.1 虚拟主机介绍

​ 虚拟主机是一种特殊的软硬件技术,它可以将网络上的每一台计算机分成多个虚拟主机,每个虚拟主机可以独立对外提供www服务,这样就可以实现一台主机对外提供多个web服务,每个虚拟主机之间是独立的,互不影响的。

​ 虚拟主机技术是互联网服务器采用的节省服务器硬件成本的技术,虚拟主机技术主要应用于HTTP(Hypertext Transfer Protocol,超文本传输协议)服务,将一台服务器的某项或者全部服务内容逻辑划分为多个服务单位,对外表现为多个服务器,从而充分利用服务器硬件资源。

img

Nginx支持三种类型的虚拟主机配置

  1. 基于IP的虚拟主机

  2. 基于端口的虚拟主机

  3. 基于域名的虚拟主机

5.1.2 基于IP的虚拟主机配置方式

需求 一台Linux服务器绑定两个ip:192.168.20.101、192.168.20.99 访问不同的ip请求不同的html目录,即: 访问https://192.168.20.101将访问“html101”目录下的html网页 访问https://192.168.20.99将访问“html99”目录下的html网页

Linux绑定多IP Linux操作系统允许绑定多IP。是在一块物理网卡上可以绑定多个lP地址。这样就能够在使用单一网卡的同一个服务器上运行多个基于IP的虚拟主机。但是在绑定多IP时需要将动态的IP分配方式修改为静态的指定IP。

将动态IP修改为静态IP

1
2
3
4
5
6
7
8
9
10
11
[root@node1 ~]# cd /etc/sysconfig/network-scripts
[root@node1 network-scripts]# ls
ifcfg-ens33
[root@node1 network-scripts]# vim ifcfg-ens33 
BOOTPROTO="static"
IPADDR0=192.168.20.101
IPADDR1=192.168.20.99
[root@node1 network-scripts]# service network restart  # centos6、7重启网卡
[root@node1 ~]# systemctl restart network #centos7重启网卡
[root@node0 network-scripts]#reboot  #各种发行版都是可以的
#CentOS8重启网卡 nmcli c reload ens33

修改Nginx的配置文件完成基于IP的虚拟主机配置

Nginx的配置文件nginx.conf

如上述配置文件所示,主要由6个部分组成:

main:用于进行nginx全局信息的配置

events:用于nginx工作模式的配置

http:用于进行http协议信息的一些配置

server:用于进行服务器访问信息的配置

location:用于进行访问路由的配置

upstream:用于进行负载均衡的配置

修改配置nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@node1 network-scripts]# vim /usr/local/nginx/conf/nginx.conf
#一个Server就是一个虚拟主机
    server {
        listen       80;
	#为虚拟机指定IP或者是域名
        server_name  192.168.20.101;
	#主要配置路由访问信息
        location / {
	    #用于指定访问根目录时,访问虚拟主机的web目录
            root   html101;
	    #在不指定访问具体资源时,默认的展示资源的列表
            index  index.html index.htm;
        }   
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    #一个Server就是一个虚拟主机
    server {
        listen       80;
	    #为虚拟机指定IP或者是域名
        server_name  192.168.20.99;
	    #主要配置路由访问信息
        location / {
	    #用于指定访问根目录时,访问虚拟主机的web目录
            root   html99;
	    #在不指定访问具体资源时,默认的展示资源的列表
            index  index.html index.htm;
        }  
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

准备需要的目录和html页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@node1 conf]# cd ../
[root@node1 nginx]# ls
conf  html  logs  sbin  scgi_temp
[root@node1 nginx]# cp -r html/ html101
[root@node1 nginx]# ls
conf  html  html101  logs  sbin  scgi_temp
[root@node1 nginx]# vim html101/index.html 
......
<body>
<h1>Welcome to nginx 192.168.20.101!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@node1 nginx]# cp -r html101 html99
[root@node1 nginx]# vim html99/index.html 
<h1>Welcome to nginx 192.168.20.101!</h1>
#改为
<h1>Welcome to nginx 192.168.20.99!</h1>
[root@node1 nginx]# 

重启Nginx服务:

1
[root@node1 html]# systemctl restart nginx

测试:

访问https://192.168.20.101将访问“html101”目录下的html网页

1627887347391

访问https://192.168.20.99将访问“html99”目录下的html网页

1627887401600

5.1.3 基于端口的虚拟主机配置方式

需求

Nginx对提供8888与9999两个端口的监听服务

请求8888端口则访问html8888目录下的index.html

请求9999端口则访问html9999目录下的index.html

还原IP地址为192.168.20.101:

1
2
3
4
5
6
7
8
vim /etc/sysconfig/network-scripts/ifcfg-ens33
#将:
IPADDR0=192.168.20.101
IPADDR1=192.168.20.99
#改为
IPADDR=192.168.20.101
#重启网络服务
systemctl restart network

修改Nginx的配置文件完成基于端口的虚拟主机配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#一个Server就是一个虚拟主机 基于端口
server {
    listen       8888;
	#为虚拟机指定IP或者是域名
    server_name  192.168.20.101;
	#主要配置路由访问信息
    location / {
    #用于指定访问根目录时,访问虚拟主机的web目录
        root   html8888;
    #在不指定访问具体资源时,默认的展示资源的列表
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}
#一个Server就是一个虚拟主机
server {
    listen       9999;
	#为虚拟机指定IP或者是域名
    server_name  192.168.20.101;

	#主要配置路由访问信息
    location / {
		#用于指定访问根目录时,访问虚拟主机的web目录
        root   html9999;
		#在不指定访问具体资源时,默认的展示资源的列表
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

准备需要的目录和html页面:

1
2
3
4
5
6
[root@node1 nginx]# cp -r html101/ html8888
[root@node1 nginx]# cp -r html101/ html9999
[root@node1 nginx]# vim html9999/index.html 
<h1>Welcome to nginx 192.168.20.101:9999!</h1>
[root@node1 nginx]# vim html8888/index.html
<h1>Welcome to nginx 192.168.20.101:8888!</h1>

重启Nginx服务

1
[root@node1 html]# systemctl restart nginx

测试:

请求https://192.168.20.101:8888则访问html8888目录下的index.html

1627895731458

请求https://192.168.20.101:9999则访问html9999目录下的index.html

1627895580583

5.1.4 基于域名的虚拟主机配置方式

需求

两个域名指向同一个nginx服务器,用户访问不同的域名时显示不同的内容。

域名规划:

1, www.bjsxt.cn

2, www.baizhan.cn

修改windows的hosts文件配置域名与ip的映射

文件路径:C:\Windows\System32\drivers\etc\hosts

1
192.168.20.101 node1 www.bjsxt.cn www.baizhan.cn

修改nginx.conf配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
    listen       80;
	#为虚拟机指定IP或者是域名
    server_name  www.bjsxt.cn;
	#主要配置路由访问信息
    location / {
    #用于指定访问根目录时,访问虚拟主机的web目录
        root   bjsxt;
    #在不指定访问具体资源时,默认的展示资源的列表
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}
#一个Server就是一个虚拟主机
server {
    listen       80;
#为虚拟机指定IP或者是域名
    server_name  www.baizhan.cn;
#主要配置路由访问信息
    location / {
    #用于指定访问根目录时,访问虚拟主机的web目录
        root   baizhan;
    #在不指定访问具体资源时,默认的展示资源的列表
        index  index.html index.htm;
    } 
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

准备需要的目录和html页面:

1
2
3
4
5
6
7
8
[root@node1 nginx]# cp -r html101/ bjsxt
[root@node1 nginx]# cp -r html101/ baizhan
[root@node1 nginx]# vim bjsxt/index.html 
<h1>Welcome to nginx bjsxt!</h1>
<p><em>Thank you for using bjsxt.</em></p>
[root@node1 nginx]# vim baizhan/index.html
<h1>Welcome to baizhan!</h1>
<p><em>Thank you for using baizhan.</em></p>

重启Nginx服务

1
2
3
4
[root@node1 html]# systemctl stop nginx
[root@node1 html]# systemctl start nginx
#或者
[root@node1 html]# systemctl restart nginx

测试:

请求www.bjsxt.cn则访问bjsxt目录下的index.html

1627896146880

请求www.baizhan.cn则访问baizhan目录下的index.html

1627896213315

5.2 配置服务的反向代理

5.2.1 需求

安装两个Tomcat服务,通过nginx反向代理。

本案例中使用两台虚拟机演示。

Nginx安装在192.168.20.101环境中

Tomcat安装到192.168.20.102环境中。端口为8080与9090img

5.2.2 安装服务环境

  1. 上传JDK和Tomcat软件安装包

  2. 安装JDK

    1
    2
    3
    
    [root@node2 apps]# ls
    apache-tomcat-8.5.61.tar.gz  jdk-8u221-linux-x64.rpm 
    [root@node2 apps]# rpm -ivh jdk-8u221-linux-x64.rpm
    
  3. 配置JDK环境变量

    先查找jdk安装在哪个目录下面:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    [root@node2 apps]# find / -name java #搜索java安装在了什么目录下
    /etc/pki/ca-trust/extracted/java
    /etc/pki/java
    /etc/alternatives/java
    /var/lib/alternatives/java
    /usr/bin/java
    /usr/share/bash-completion/completions/java
    /usr/java
    /usr/java/jdk1.8.0_221-amd64/bin/java  #安装后目录在/usr/java/
    /usr/java/jdk1.8.0_221-amd64/jre/bin/java
    [root@node2 apps]# ll /usr/java/
    总用量 0
    lrwxrwxrwx. 1 root root  16 8月   2 20:13 default -> /usr/java/latest
    drwxr-xr-x. 8 root root 258 8月   2 20:13 jdk1.8.0_221-amd64
    lrwxrwxrwx. 1 root root  28 8月   2 20:13 latest -> /usr/java/jdk1.8.0_221-amd64
    

    配置环境变量:

    1
    2
    3
    
    [root@node2 apps]# vim /etc/profile
    export JAVA_HOME=/usr/java/default
    export PATH=$PATH:$JAVA_HOME/bin
    

    然配置的环境变量生效:

    1
    
    [root@node2 apps]# source /etc/profile
    

    测试安装配置是否正确:

    1
    2
    3
    4
    5
    6
    
    [root@node2 apps]# java -version
    java version "1.8.0_221"
    Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
    Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
    [root@node2 apps]# jps  #查看运行的java进程
    7701 Jps  #说明配置成功了
    
  4. 安装并配置tomcat

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    # 解压安装包
    [root@node2 apps]# tar -zxvf apache-tomcat-8.5.61.tar.gz -C /opt/
    [root@node2 apps]# cd /opt/
    [root@node2 opt]# ls
    apache-tomcat-8.5.61  apps
    [root@node2 opt]# mv apache-tomcat-8.5.61/ tomcat1
    [root@node2 opt]# cd tomcat1/bin/
    #启动tomcat
    [root@node2 bin]# ./startup.sh  
    

    访问https://192.168.20.102:8080/进行测试,出现如下图,说明jdk和tomcat可以正常使用:

    1627907520362

    修改index.jsp主页:

    1
    2
    3
    4
    
    [root@node2 bin]# vim ../webapps/ROOT/index.jsp
    <body>
       192.168.20.102:8080
    </body> 
    

    1627908632008

  5. 关闭tomcat1,并将tomcat1复制一份

1
2
3
4
5
6
7
  [root@node2 bin]# ./shutdown.sh
  [root@node2 bin]# cd /opt/
  [root@node2 opt]# ls
  apps  tomcat1
  [root@node2 opt]# cp -r tomcat1/ tomcat2
  [root@node2 opt]# ls
  apps  tomcat1  tomcat2
  1. 修改tomcat2的index.jsp主页

    1
    2
    3
    4
    
    [root@node2 opt]# vim tomcat2/webapps/ROOT/index.jsp
    <body>
       192.168.20.102:9090
    </body> 
    
  2. 修改tomcat2的端口号8080改为9090

    1
    2
    3
    4
    5
    6
    
    [root@node2 opt]# vim tomcat2/conf/server.xml
    <Server port="9095" shutdown="SHUTDOWN"> #8005改为9095,不改的话同时启动两个tomcat抛出异常
    ......
    <Connector port="9090" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
    
  3. 启动tomcat2,并测试:

    1
    2
    
    [root@node2 opt]# cd tomcat2/bin/
    [root@node2 bin]# ./startup.sh 
    

    1628234864852

5.2.3配置Nginx实现服务的反向代理

修改nginx.xml配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  0;
    upstream tomcat.server1{
	    server 192.168.20.102:8080;
    }
    upstream tomcat.server2{
	    server 192.168.20.102:9090;
    }  
    server {
        listen       80;
	    #为虚拟机指定IP或者是域名
        server_name  www.tomcat1.com;
	    #主要配置路由访问信息
        location / {
	        #用于指定访问根目录时,访问虚拟主机的web目录
            proxy_pass  https://tomcat.server1;
	        #在不指定访问具体资源时,默认的展示资源的列表
            index  index.html index.htm;
        }     
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    #一个Server就是一个虚拟主机
    server {
        listen       80;
	    #为虚拟机指定IP或者是域名
        server_name  www.tomcat2.com;
	    #主要配置路由访问信息
        location / {
	        #用于指定访问根目录时,访问虚拟主机的web目录
            proxy_pass  https://tomcat.server2;
	        #在不指定访问具体资源时,默认的展示资源的列表
            index  index.html index.htm;
        }     
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
   }
}

修改window下的hosts文件:

1
192.168.20.101 node1 www.bjsxt.cn www.baizhan.cn  www.tomcat1.com www.tomcat2.com

分别访问:www.tomcat1.com www.tomcat2.com进行测试

1628234776726

5.3 配置服务的负载均衡

5.3.1 什么是负载均衡

负载均衡,英文名称为Load Balance,是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。对于 Web 工程中的负载均衡,就是将相同的 Web 应用部署到多个不同的 Web 服务器上,形成多个 Web 应用服务器。当请求到来时,由负载均衡服务器负责将请求按照事先设定好的比例向 Web 应用服务器进行分发,从而增加系统的整体吞吐量。

​ 负载均衡可以通过硬件负载均衡器实现,也可通过负载均衡软件实现。

(1 ) 硬件负载均衡

硬件负载均衡器的性能稳定,且有生产厂商作为专业的服务团队。但其成本很高,一台硬件负载均衡器的价格一般都在十几万到几十万,甚至上百万。知名的负载均衡器有 F5、Array、深信服、梭子鱼等。

img

(2 ) 软件负载均衡

软件负载均衡成本几乎为零,基本都是开源软件。例如:LVS、HAProxy、Nginx 等。

5.3.2 Nginx负载均衡策略

1.轮询(默认)

每个请求按时间的先后顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

2.指定权重

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。权重值越大被访问的几率就越大。

1
2
3
4
upstream backserver { 
	server 192.168.20.101; 
	server 192.168.20.102 weight=2; 
}

3.IP绑定 ip_hash

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。

1
2
3
4
5
upstream backserver { 
    ip_hash; 
    server 192.168.20.101; 
    server 192.168.20.102; 
}

5.3.3 实现负载均衡配置

1.需求

该机群包含一台 Nginx 服务器,两个 Web服务器(一台虚拟机node2上通过两个端口启动两个tomcat)。

修改nginx.conf文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#自定义日志格式
log_format  myfmt  '$remote_addr - $remote_user [$time_local] "$request" ';
upstream rss{
	server 192.168.20.102:8080;
	server 192.168.20.102:9090 weight=2; 
}
server {
   listen  80;
   server_name www.bjsxt.cn;
   #为server指定使用myfmt日志格式以及将日志保存logs/myfmt.log文件中
   access_log   logs/myfmt.log  myfmt;
   location / {
	   proxy_pass https://rss/;

   }
}	

重启nginx,请求测试:https://www.bjsxt.cn,发现已经实现了负载均衡。规律为一次8080两次9090。

​ 中小企业一般使用该方式,优点是配置简单,缺点是如果添加新的后台服务,需要修改Nginx配置文件并且还需重启Nginx。

​ 如果后台服务变动比较频繁,而且不希望重启Nginx,可以使用Http动态负载均衡,后续课程会讲到。

5.4 Location配置(重点)

参考:

https://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_core_module.html

语法location [ = | ~ | ~* | ^~ ] uri { … }location @name { … }
默认值-
上下文server, location

让我们用一个例子解释上面的说法:

www.bjsxt.cn/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location = / {
   [ configuration A ]
}
location / {
   [ configuration B ]
} 
location /documents/ {
   [ configuration C ]
}
location ^~ / {
   [ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ { 
   [ configuration E ] 
} 

请求“/”匹配配置A,

请求“/index.html”匹配配置B,

请求“/documents/document.html”匹配配置C,

请求“/1.gif”匹配配置D,

请求“/documents/1.jpg”匹配配置E。

img

img

img

img

  1. 修改nginx.conf配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    server {
       listen  80;
       server_name www.bjsxt.cn;
       access_log   logs/myfmt.log  myfmt;
       location / {
           root /mnt;
           autoindex on;
       }
       location /aabb {
          proxy_pass https://192.168.20.102:8080/;#带上/访问该url对应的首页,
    	  #不带/ 访问https://192.168.20.102:8080/aabb
       }
    }
    
  2. 重新启动nginx

    1
    
    [root@node1 html]# systemctl restart nginx
    
  3. 访问测试

    1628063825230

    1628063894844

    扩展演示:proxy_pass https://192.168.20.102:8080/; 去掉 / 添加文件aabb

  4. 修改nginx配置文件

    1
    2
    3
    
    location /baidu {
       proxy_pass https://www.baidu.com/;
    }
    
  5. 重启Nginx

    1
    
    [root@node0 html]# systemctl restart nginx
    
  6. 访问www.bjsxt.cn/baidu进行测试,直接跳转到www.baidu.com首页。虽然访问到了百度,但是却是通过重定向的方式,以后发生的事情和我们的服务器就没有半毛钱关系了。优化配置nginx.conf:

    1
    2
    
    #尽量在服务器端跳转,不要在客户端跳转
    proxy_pass https://www.baidu.com/;
    
  7. 重启nginx,再次测试,地址栏没有重定向,但是当我们查询(比如:ssd)时出现404

    1628244336538

  8. 修改Nginx配置文件,然后重启

    1
    2
    3
    4
    5
    
    location ~* /s.* {
        proxy_pass https://www.baidu.com;
    }
       
    [root@node0 html]# systemctl restart nginx
    

    1628244478325

5.5 配置动静分离

5.5.1 动静分离需求分析

img

Nginx动静分离简单来说就是把动态和静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求和静态请求分开,可以理解成使用Nginx处理静态请求,Tomcat处理动态请求。

动静分离从目前实现方式大致分为两种:

一是纯粹的把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。

二是动态和静态文件混合在一起发布,通过nginx分开。通过location指定不同的后缀名实现不同的请求转发。

5.5.2 动静分离具体实现

1.index.jsp修改

tomcat1

1
2
3
4
[root@node2 ~]# vim /opt/tomcat1/webapps/ROOT/index.jsp 
<link rel="stylesheet" type="text/css" href="/css/index.css">
<img src="/image/logo.jpg" ><br/>
<font class="myfont">from 192.168.20.102:8080 </font>

tomcat2

1
2
3
4
[root@node2 ~]# vim /opt/tomcat2/webapps/ROOT/index.jsp 
<link rel="stylesheet" type="text/css" href="/css/index.css">
<img src="/image/logo.jpg" ><br/>
<font class="myfont">from 192.168.20.102:9090 </font>

2.从node1克隆node5,启动node5,并修改主机名和ip地址

1
2
3
4
5
[root@node5 ~]#vim /etc/hostname
node5
[root@node5 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
IPADDR=192.168.20.105
[root@node2 ~]# reboot

重启虚拟机后,XShell中配置连接,并使用XShell连接node5,接收并保存 秘钥。

2.在node5服务器上创建目录 /data/image和/data/css,然后将logo.jpg和index.css上传到对应的目录

1
2
3
4
5
6
7
8
9
10
11
12
[root@node5 ~]# mkdir -p /data/image  /data/css
[root@node5 ~]# cd /data
[root@node5 data]# ls
css  image
#上传logo.jpg到image目录下,上传index.css到css目录
[root@node5 data]# ls -R ./
./:
css  image
./css:
index.css
./image:
logo.jpg

3.并修改node5服务器上的nginx.conf配置文件,并重启nginx

1
2
3
4
5
6
7
8
9
10
11
12
[root@node5 ~]# vim /usr/local/nginx/conf/nginx.conf
server {
   listen  80;
   server_name 192.168.20.105;
   location /image {
	   root /data;
   }
   location /css {
	   root /data;
   }
}
[root@node5 ~]# systemctl restart nginx

4.修改node1服务器上的nginx.conf配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
   listen  80;
   server_name www.bjsxt.cn;
   location / {
       proxy_pass https://rss/;
   }
   location /image/ {
       proxy_pass https://192.168.20.105;
   }
   location /css/ {
       proxy_pass https://192.168.20.105;
   }
}

5.然后重新加载nginx,浏览器测试https://www.bjsxt.cn

1628301841695

1628301779513

5.6 Http动态负载均衡

5.6.1 什么是动态负载均衡

在使用的过程中,提供服务的服务器需要添加新的节点时,需要添加新的server配置,然后还需要重启Nginx。

1
2
3
4
5
upstream rss{
   server 192.168.20.102:8080;
   server 192.168.20.102:9090 weight=2;
   #添加新的server配置,然后还需要重启Nginx
}	

传统的负载均衡,如果Upstream参数发生变化,每次都需要重新加载nginx.conf文件,因此扩展性不是很高,所以我们可以采用动态负载均衡,实现Upstream可配置化、动态化,无需人工重新加载nginx.conf,这类似分布式的配置中心。

img

注册中心存放IP地址和端口号,IP区分主机、port区别进程。

5.6.2 常用服务注册与发现框架

​ 常见服务发现框架 Consul、Eureka、 ZooKeeper、Etcd ,ZooKeeper是这种类型的项目中历史最悠久的之一,它起源于Hadoop。它非常成熟、可靠,被许多大公司(YouTube、eBay、雅虎等)使用。

​ Consul是一款开源的分布式服务注册与发现系统,通过HTTP API可以使得服务注册、发现实现起来非常简单,它支持如下特性:

  1. 服务注册:服务实现者可以通过HTTP API或DNS方式,将服务注册到Consul。
  2. 服务发现:服务消费者可以通过HTTP API或DNS方式,从Consul获取服务的IP和PORT。
  3. 故障检测:支持如TCP、HTTP等方式的健康检查机制,从而当服务有故障时自动摘除。
  4. K/V存储:使用K/V存储实现动态配置中心,其使用HTTP长轮询实现变更触发和配置更改。
  5. 多数据中心:支持多数据中心,可以按照数据中心注册和发现服务,即支持只消费本地机房服务,使用多数据中心集群还可以避免单数据中心的单点故障。
  6. Raft算法:Consul使用Raft算法实现集群数据一致性。

5.6.3 动态负载均衡实现方案

  1. Consul+Consul-template 每次发现配置更改需要raload nginx,重启Nginx。

  2. Consul+OpenResty 实现无需raload动态负载均衡 (lua语言,配置文件放字典里面,每隔时间读取)

  3. Consul+upsync+Nginx 实现无需raload动态负载均衡 (原理同上) 搭建ConsulServer专门存放负载均衡注册配置信息

    nginx间隔时间动态获取最新的ConsulServer配置信息

    img

5.6.4 Consul环境搭建

注意:一定要使用ningx 1.9以上版本!

img

  1. 下载consul_0.7.5_linux_amd64.zip

    1
    2
    
    [root@node1 ~]# cd /opt/apps/
    [root@node1 apps]# wget https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip
    

    或者使用提供的软件上传即可。

  2. 安装unzip

    1
    
    [root@node1 apps]# yum install unzip -y
    
  3. 解压consul_0.7.5_linux_amd64.zip,并将解压文件移动到/opt目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    [root@node1 apps]# unzip consul_0.7.5_linux_amd64.zip
    Archive:  consul_0.7.5_linux_amd64.zip
      inflating: consul                  
    [root@node1 apps]# mv consul /opt/
    [root@node1 apps]# cd /opt/
    [root@node1 opt]# ll
    总用量 35160
    drwxr-xr-x. 3 root root       89 8月   3 17:25 apps
    -rwxr-xr-x. 1 root root 36003713 2月  15 2017 consul
    
  4. 测试consul是否可以正常使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    [root@node1 opt]# ./consul
    usage: consul [--version] [--help] <command> [<args>]
    Available commands are:
        agent          Runs a Consul agent
        configtest     Validate config file
        event          Fire a new event
        exec           Executes a command on Consul nodes
        force-leave    Forces a member of the cluster to enter the "left" state
        info           Provides debugging information for operators
        join           Tell Consul agent to join cluster
        keygen         Generates a new encryption key
        keyring        Manages gossip layer encryption keys
        kv             Interact with the key-value store
        leave          Gracefully leaves the Consul cluster and shuts down
        lock           Execute a command holding a lock
        maint          Controls node or service maintenance mode
        members        Lists the members of a Consul cluster
        monitor        Stream logs from a Consul agent
        operator       Provides cluster-level tools for Consul operators
        reload         Triggers the agent to reload configuration files
        rtt            Estimates network round trip time between nodes
        snapshot       Saves, restores and inspects snapshots of Consul server state
        version        Prints the Consul version
        watch          Watch for changes in Consul
    

    说明可以正常使用。

  5. 启动consul

    1
    
    [root@node1 opt]# ./consul agent -dev -ui -node=consul-dev -client=192.168.20.101
    
  6. 访问测试:https://192.168.20.101:8500/ui/#/dc1/services

    1627996022277

  7. 使用PostMan

    注册接口:https://192.168.20.101:8500/v1/catalog/register

    1627996579757

    参数1

    1
    
    {"Datacenter": "dc1","Node":"tomcat", "Address":"192.168.20.102","Service": {"Id" :"192.168.20.102:8080", "Service": "toov5","tags": ["dev"], "Port": 8080}}
    

    参数2

    1
    
    {"Datacenter": "dc1", "Node":"tomcat", "Address":"192.168.20.102","Service": {"Id" :"192.168.20.102:9090", "Service": "toov5","tags": ["dev"], "Port": 9090}}       
    

    ​ Datacenter指定数据中心,Address指定服务IP,Service.Id指定服务唯一标识,Service.Service指定服务分组,Service.tags指定服务标签(如开发环境、测试环境、生产环境等),Service.Port指定服务端口。

  8. 输入参数1,点击“Send”按钮,显示结果true表示提交成功。

    1627996650283

    检查服务是否被注册上:

    1627996886816

  9. 输入参数2,点击“Send”按钮,显示结果true表示提交成功,然后检查。同上。

    1627997285333

5.6.5 nginx-upsync-module简介

img

​ Upsync是新浪微博开源的基于Nginx实现动态配置的第三方模块。Nginx-Upsync-Module的功能是拉取Consul的后端server的列表,并动态更新Nginx的路由信息。此模块不依赖于任何第三方模块。Consul作为Nginx的DB,利用Consul的KV服务,每个Nginx Work进程独立的去拉取各个upstream的配置,并更新各自的路由。

作用:nginx动态获取最新upstream信息

5.6.6 nginx-upsync-module安装

  1. 下载nginx-upsync-module

    1
    2
    
    [root@node0 apps]# wget https://github.com/weibocom/nginx-upsync-module/archive/master.zip
       
    
  2. 解压安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    [root@node0 apps]# unzip master.zip
    [root@node0 apps]# ls
    ...    nginx-upsync-module-master    master.zip 
    [root@node0 local]# mkdir /opt/upsync
    [root@node0 apps]# mv nginx-upsync-module-master /opt/upsync
    [root@node0 apps]# cd ../upsync
    [root@node0 upsync]# ls
    nginx-upsync-module-master
       
    

5.6.7 重新配置安装Nginx

需要做配置,包括分组之类的,创建目录,有些插件是需要存放在这些目录的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#先关闭和禁用Nginx服务,安装好后再启动
[root@node1 ~]# systemctl stop nginx
[root@node0 opt]# systemctl disable nginx
#添加用户组nginx
[root@node0 opt]# groupadd nginx
#添加用户nginx(用户组指定为刚刚创建的用户组nginx,并且设置为伪用户)
[root@node0 opt]# useradd -g nginx -s /sbin/nologin nginx
#查看刚刚添加的用户的信息
[root@node1 ~]# id nginx
uid=1004(nginx) gid=10001(nginx)=10001(nginx)
#先删除之前创建的,然后再重新创建
[root@node0 opt]# rm -rf /var/temp/nginx/
[root@node0 opt]# mkdir -p /var/temp/nginx/client/
# 先将之前安装nginx打包备份,然后删除/usr/local/nginx,最后创建/usr/local/nginx目录
[root@node0 opt]# cd /usr/local
[root@node0 local]# tar -zcvf nginx_backup_upsync_pre.tar.gz nginx/
[root@node0 local]# rm -rf nginx
[root@node0 local]# mkdir /usr/local/nginx 

​ Nginx重新解压

1
2
3
[root@node0 local]# cd /opt/apps
[root@node0 apps]# rm -rf nginx-1.20.1
[root@node0 apps]# tar -zxvf nginx-1.20.1.tar.gz

Nginx重新配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@node0 apps]# cd nginx-1.20.1
[root@node0 nginx-1.20.1]#./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-http_realip_module \
--http-client-body-temp-path=/var/temp/nginx/client/ \
--http-proxy-temp-path=/var/temp/nginx/proxy/ \
--http-fastcgi-temp-path=/var/temp/nginx/fcgi/ \
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
--http-scgi-temp-path=/var/temp/nginx/scgi \
--with-pcre \
--add-module=/opt/upsync/nginx-upsync-module-master  #一定是upsync的解压目录

编译与安装:

1
make&&make install

启动Nginx服务

1
2
3
4
#启用Nginx服务,以后便可以实现开机启动
[root@node0 ~]# systemctl enable nginx
#启动Nginx服务,立即生效
[root@node0 ~]# systemctl start nginx

访问https://192.168.20.101/显示Nginx欢迎页,说明重新安装成功了。

下面开始配置Nginx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#动态去consul 获取注册的真实反向代理地址
upstream toov5{
    #自己虚拟出的 作为监听用的 端口号 固定死的
    server 127.0.0.1:11111;
    #连接consul server动态获取upstream配置负载均衡信息
    #使用192.168.20.101:8500 原生的 他自己虚拟出来的 不要乱改!读取的是toov5 这个分组的!!!
    upsync 192.168.20.101:8500/v1/kv/upstreams/toov5 
    #配置从consul拉取上游服务器配置的超时时间
    upsync_timeout=6m
    #配置从consul拉取上游服务器配置的间隔时间0.5秒
    upsync_interval=500ms 
    #指定使用consul配置服务器
    upsync_type=consul 
    #配置nginx在启动时是否强制依赖配置服务器,如果配置为on,则拉取配置失败时nginx启动同样失败。
    strong_dependency=off;
    #动态拉取consulServer相关负载均衡配置信息持久化到硬盘上的指定文件中
    upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf;
}
server {
    listen 80;
    server_name localhost;
    location / {
        #配置反向代理
        proxy_pass https://toov5;
        index index.html index.htm;
    }
}

创建upsync_dump_path

1
mkdir /usr/local/nginx/conf/servers/

upsync_dump_path指定从consul拉取的上游服务器后持久化到的位置,这样即使consul服务器出问题了,本地还有一个备份。

然后启动consul :

1
[root@node0 opt]# ./consul agent -dev -ui -node=consul-dev -client=192.168.20.101

重启Nginx

1
[root@node0 conf]# systemctl restart nginx

如果现在访问Nginx,出现502提示。

然后开始做动态负载均衡了!添加nginx Upstream服务开始:

1.使用linux命令方式发送put请求 添加这个 192.168.20.102:8080 到上游服务

1
2
3
curl -X PUT https://192.168.20.101:8500/v1/kv/upstreams/toov5/192.168.20.102:8080
#执行后如显示如下结果,表示成功。
true

2、 使用postman方式

1628044030169

然后图形化界面: https://192.168.20.101:8500/ui/#/dc1/kv/upstreams/toov5/192.168.20.102:8080/edit

1628043859347

启动192.168.20.102上的tomcat1

1
2
3
4
[root@node2 ~]# vim /opt/tomcat1/webapps/ROOT/index.jsp 
from 192.168.20.102:8080
[root@node2 ~]# cd /opt/tomcat1/bin/
[root@node2 bin]# ./startup.sh 

浏览器中请求https://192.168.20.101/进行测试,无论刷新多少次,都是如下界面。这是因为只有tomcat1这一个服务。

1628044203363

启动192.168.20.102上的tomcat2

1
2
3
4
[root@node2 ~]# vim /opt/tomcat1/webapps/ROOT/index.jsp 
from 192.168.20.102:9090
[root@node2 ~]# cd /opt/tomcat2/bin/
[root@node2 bin]# ./startup.sh 

使用linux命令方式发送put请求 添加这个 192.168.20.102:9090到上游服务

1
2
3
curl -X PUT https://192.168.20.101:8500/v1/kv/upstreams/toov5/192.168.20.102:9090
#执行后如显示如下结果,表示成功。
true

img

浏览器中请求https://192.168.20.101/进行测试,刷新浏览器,发现在两个服务之间来回切换了。

假如https://192.168.20.102:9090对应的服务性能是https://192.168.20.102:8080对应服务性能的2倍,可以做如下修改:

1
{"weight":2, "max_fails":2, "fail_timeout":10, "down":0} 

1628431523892

修改后再次测试,便可以实现如下切换了:两次9090,一次8080。

六、Nginx限流

6.1 生活中的 “限流”?

限流在生活中亦无处不在,下面例举:

  1. 博物馆:限制每天参观总人数以保护文物
  2. 高铁安检:有若干安检口,旅客依次排队,工作人员根据安检快慢决定是否放人进去。遇到节假日,可以增加安检口来提高处理能力(横向拓展),同时增加排队等待区长度(缓存待处理任务)。
  3. 办理银行业务:所有人先领号,各窗口叫号处理。每个窗口处理速度根据客户具体业务而定,所有人排队等待叫号即可。若快下班时,告知客户明日再来(拒绝流量)。
  4. 水坝泄洪:水坝可以通过闸门控制泄洪速度(控制处理速度)。

以上”限流”例子,可以让服务提供者稳定的服务客户。

6.2 为什么需要限流?

系统设计时一般会预估负载,当系统暴露在公网中时,恶意攻击或正常突发流量等都可能导致系统被压垮,而限流就是保护措施之一。限流即控制流量,Nginx 的二种限流设置,一是控制速率,二是控制并发连接数.

6.3 如何限流之控制速率

正常限流

ngx_http_limit_req_module 模块提供限制请求处理速率能力,使用了漏桶算法(leaky bucket)。下面例子使用 nginx limit_req_zone 和 limit_req 两个指令,限制单个IP的请求处理速率。

在 nginx.conf http 中添加限流配置,格式:limit_req_zone key zone rate

1
2
3
http {
	limit_req_zone $binary_remote_addr zone=myRateLimit:10m rate=10r/s;
}

配置 server,使用 limit_req 指令应用限流。

1
2
3
4
5
6
server {
   location / {
       limit_req zone=myRateLimit;
       proxy_pass https://my_upstream;
   }
}

key :定义限流对象,binary_remote_addr 是一种key,表示基于 remote_addr(客户端IP) 来做限流,binary_ 的目的是压缩内存占用量。

zone:定义共享内存区来存储访问信息, myRateLimit:10m 表示一个大小为10M,名字为myRateLimit的内存区域。1M能存储16000 IP地址的访问信息,10M可以存储16W IP地址访问信息。

rate 用于设置最大访问速率,rate=10r/s 表示每秒最多处理10个请求。Nginx 实际上以毫秒为粒度来跟踪请求信息,因此 10r/s 实际上是限制:每100毫秒处理一个请求。这意味着,自上一个请求处理完后,若后续100毫秒内又有请求到达,将拒绝处理该请求。

处理突发流量

上面例子限制 10r/s,如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,可以结合 burst 参数使用来解决该问题。

1
2
3
4
5
6
server {
    location / {
        limit_req zone=myRateLimit burst=20;
        proxy_pass https://my_upstream;
    }
}

burst 译为突发、爆发,表示在超过设定的处理速率后能额外处理的请求数。当 rate=10r/s 时,将1s拆成10份,即每100ms可处理1个请求。

此处,**burst=20 **,若同时有21个请求到达,Nginx 会处理第一个请求,剩余20个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于21,将拒绝处理多余的请求,直接返回503.

不过,单独使用 burst 参数并不实用。假设 burst=50 ,rate依然为10r/s,排队中的50个请求虽然每100ms会处理一个,但第50个请求却需要等待 50 * 100ms即 5s,这么长的处理时间自然难以接受。因此,burst 往往结合 nodelay 一起使用。

1
2
3
4
5
6
server {
    location / {
        limit_req zone=myRateLimit burst=20 nodelay;
        proxy_pass https://my_upstream;
    }
}

​ nodelay 针对的是 burst 参数,burst=20 nodelay 表示这20个请求立马处理,不能延迟,相当于特事特办。不过,即使这20个突发请求立马处理结束,后续来了请求也不会立马处理。burst=20 相当于缓存队列中占了20个坑,即使请求被处理了,这20个位置这只能按 100ms一个来释放。

​ 这就达到了速率稳定,但突然流量也能正常处理的效果。

6.4 如何限流之限制连接数

ngx_http_limit_conn_module 提供了限制连接数的能力,利用 limit_conn_zone 和 limit_conn 两个指令即可。下面是 Nginx 官方例子:

1
2
3
4
5
6
7
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
    ...
    limit_conn perip 10;
    limit_conn perserver 100;
}

limit_conn perip 10 作用的key 是 $binary_remote_addr,表示限制单个IP同时最多能持有10个连接。

limit_conn perserver 100 作用的key是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数。

需要注意的是:只有当 request header 被后端server处理后,这个连接才进行计数。

6.5 设置白名单

限流主要针对外部访问,内网访问相对安全,可以不做限流,通过设置白名单即可。利用 Nginx ngx_http_geo_module 和 ngx_http_map_module 两个工具模块即可搞定。

在 nginx.conf 的 http 部分中配置白名单:

1
2
3
4
5
6
7
8
9
10
11
geo $limit {
    default 1;
    39.100.243.125 0;
    192.168.0.0/24 0;
    172.20.0.35 0;
}
map limit limit_key {
    0 "";
    1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=myRateLimit:10m rate=10r/s;

geo 对于白名单(子网或IP都可以) 将返回0,其他IP将返回1。

map 将limit转换为 limit_key,如果是 $limit 是0(白名单),则返回空字符串;如果是1,则返回客户端实际IP。

limit_req_zone 限流的key不再使用 binary_remote_addr,而是limit_key 来动态获取值。如果是白名单,limit_req_zone 的限流key则为空字符串,将不会限流;若不是白名单,将会对客户端真实IP进行限流。

拓展;除限流外,ngx_http_core_module 还提供了限制数据传输速度的能力(即常说的下载速度)。例如:

1
2
3
4
5
location /flv/ {
    flv;
    limit_rate_after 20m;
    limit_rate       100k;
}

这个限制是针对每个请求的,表示客户端下载前20M时不限速,后续限制100kB/s。

七、Nginx原理

7.1 Master-Worker模式

  1. Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程。

  2. Master接收来自外界的信号,向各worker进程发送信号,每个进程都有可能来处理这个连接。

  3. Master进程能监控Worker进程的运行状态,当 worker 进程退出后(异常情况下),会自动启动新的 worker 进程。

1
2
3
4
5
[root@node1 ~]# ps aux|grep nginx
root      14132  0.0  0.1  53284  1164 ?        Ss   20:15   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nginx     14133  0.0  0.6  57836  6644 ?        S    20:15   0:00 nginx: worker process
[root@node1 ~]# pstree -p
├─nginx(14132)───nginx(14133) #master进程是work进程的父进程

7.2 accept_mutex

​ 由于所有子进程都继承了父进程的sockfd,那么当连接进来时,所有子进程都将收到通知并“争着”与它建立连接,这就叫“惊群现象”。大量的进程被激活又挂起,只有一个进程可以accept() 到这个连接,这当然会消耗系统资源。Nginx 提供了一个accept_mutex加在accept上的一把共享锁。即每个worker进程在执行accept之前都需要先获取锁,获取不到就放弃执行accept()。有了这把锁之后,同一时刻,就只会有一个进程去accpet(),这样就不会有惊群问题了。

​ 当一个worker进程在accept()这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,完成一个完整的请求。一个请求,完全由worker进程来处理,而且只能在一个worker进程中处理。

7.3 为什么使用进程不使用线程?

1、节省锁带来的开销。每个worker进程都是独立的进程,不共享资源,不需要加锁。同时在编程以及问题查上时,也会方便很多。

2、独立进程,减少风险。采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快重新启动新的worker进程。当然,worker进程的也能发生意外退出。

7.4 如何处理并发请求?

​ 每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回。那么,这个处理的worker不会这么傻等着,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是他就休息去了。此时,如果再有request 进来,他就可以很快再按这种方式处理。而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。由于web server的工作性质决定了每个request的大部份生命都是在网络传输中,实际上花费在server机器上的时间片不多,这就是几个进程就能解决高并发的秘密所在。

八、Nginx调优

8.1 worker_processes 的设置

​ 打开 nginx.conf 配置文件,可以看到 worker_processes 的默认值为 1。

img

​ worker_processes,工作进程,用于指定 Nginx 的工作进程数量。该值应该设置为多少合适呢?其数值一般设置为 CPU 内核数量,或内核数量的整数倍。注意,现代的 CPU 一般都是多核的,即一块 CPU 中包含多个内核。若当前系统具有 2 块 CPU,而每块 CPU 中包含 2 个内核,那么,worker_processes 的值一般可以设置为 4 或 8。当然,也可以设置为 2。

​ 不过需要注意,该值不仅仅取决于 CPU 内核数量,还与硬盘数量及负载均衡模式相关。在不确定时可以指定其值为 auto。

8.2 worker_cpu_affinity 的设置

​ 为了进一步提高系统性能,我们会将 worker 进程与具体的内核进行绑定。该绑定操作是通过 worker_cpu_affinity 属性进行设置的。affinity,密切关系。不过,若指定 worker_processes 的值为 auto,则无法设置 worker_cpu_affinity。

​ 该设置是通过二进制进行的。每个内核使用一个二进制位表示,0 代表内核关闭,1 代表内核开启。也就是说,有几个内核,就需要使用几个二进制位。下面通过几个例子来增进对 worker_processes 与 worker_cpu_affinity 的理解。

img

1
2
worker_processes     4;
worker_cpu_affinity 0001 0010 0100 1000; 

九、keepalived实现Nginx高可用

9.1 为什么要学习Keepalived?

1628068586470

升级架构:

1628068702133

9.2 Keepalived概述

  keepalived是集群管理中保证集群高可用的服务软件。Keepalived的作用是检测服务器的状态,如果有一台服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

Keepalived 原理:

VRRP协议(虚拟路由冗余协议) - Virtual Router Redundancy Protocol

IP漂移

img

keepalived工作在TCP/IP协议栈的IP层,TCP层,及应用层,工作原理基于VRRP协议。

  网络层:Keepalived会定期向服务器群中的服务器发送一个ICMP的数据包,(既我们平时用的ping程序),如果发现某台服务的IP地址没有激活,Keepalived便报告这台服务器失效,并将它从服务器集群中剔除。

  传输层:Keepalived以TCP端口的状态来决定服务器工作正常与否,如web server的服务端口一般是80,如果Keepalived检测到80端口没有启动,则Keepalived将把这台服务器从服务器集群中剔除。

  应用层:只要针对应用上的一些探测方式,如URL的get请求,或者对nginx脚本检测等;可以根据用户自定义添加脚本针对特定的服务进行状态检测,当检测结果与用户设定不一致,则把这台服务器从服务器群中剔除。

9.3 VRRP协议的工作原理

img

  VRRP(Virtual Router Redundancy Protocol)虚拟路由冗余协议是一种容错的主备模式的协议,当网络设备发生故障时,可以不影响主机之间通信情况下进行设备切换,并且相对用户时切换过程时透明的。

​ 一个VRRP路由器有唯一的标识:VRID,范围为0—255。该路由器对外表现为唯一的虚拟MAC地址,地址的格式为00-00-5E-00-01-[VRID]。

​ 同一台路由器可以加入多个备份组,在不同备份组中有不同的优先级,使得该路由器可以在一个备份组中作为主用路由器,在其他的备份组中作为备用路由器。

​ 提供了两种安全认证措施:明文认证和IP头认证。

9.4 VRRP选举机制

  • 虚拟IP拥有者:如果某台路由器的IP地址与虚拟路由器的VIP地址一致,那么这台就会被选为主路由器。

  • 优先级较高者,如果没有虚拟IP拥有者,优先级数值大的路由器会被选举出,优先级范围0~255。

  • IP地址较大者,如果优先级一样高,IP地址数值大的路由器会被选举出。

​ 192.168.20.101 192.168.20.105 MASTER

‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬

9.5 安装前准备

规划:node1和node5作为负载均衡服务器,node2上的tomcat1和tomcat2还是RS服务器。

修改node2的tomcat1和tomcat2上的index.jps,去掉样式和图片,去掉动静分离的干扰。

tomcat1的index.jsp

1
from 192.168.20.102:8080 tomcat1

tomcat2上的index.jsp

1
from 192.168.20.102:9090 tomcat2

9.6 安装步骤

  1. 修改node1上的nginx.conf文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
upstream rss {
    server 192.168.20.102:8080;
    server 192.168.20.102:9090;
}
server { # check_nginx.sh脚本执行时使用
    listen       80;
    server_name  localhost;
    location / {
        root html;
    }
}
server {
    listen       80;
    server_name 192.168.20.200; 
    location / {
        proxy_pass https://rss/;
    }
}
  1. 备份node3的配置文件nginx.conf,将node1上的配置文件远程拷贝到node5上。
1
2
[root@node1 ~]# cd /usr/local/nginx/conf/
[root@node1 conf]# scp nginx.conf 192.168.20.105:`pwd`
  1. 在node1的/home/目录下编写check_nginx.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
#通过访问check.html页面来检查nginx是否宕机
url="https://127.0.0.1/check.html"
code=`curl -s -o /dev/null -w %{http_code} $url`
#通过判断相应编码是否是200来确定nginx宕机
if [ $code -ne 200 ];then
  sleep 1
  code=`curl -s -o /dev/null -w %{http_code} $url`
  if [ $code -ne 200 ];then
    #确定nginx是宕机,关闭本机的keepalived
    systemctl stop keepalived
  fi
fi
  1. 添加权限:chmod +x /home/check_nginx.sh

  2. 然后将node1上的/home/check_nginx.sh拷贝到node5上

1
scp /home/check_nginx.sh node5:/home
  1. 在node1上的/usr/local/nginx/html目录创建一个check.html
1
2
3
[root@node1 home]# cd /usr/local/nginx/html
[root@node1 html]# vim check.html
check nginx
  1. 然后将node1上的/usr/local/nginx/html/check.html拷贝到node3上相同目录下
1
[root@node1 html]# scp check_nginx.sh 192.168.20.105:/home/
  1. 分别在node1和node5上的/usr/local/nginx/html目录下创建一个check.html

    1
    2
    3
    4
    5
    
    [root@node1 home]# cd /usr/local/nginx/html/
    [root@node1 html]# pwd
    /usr/local/nginx/html
    [root@node1 html]# vim check.html
    check nginx
    
  2. 分别在node1上和node5上测试check_nginx.sh是否可以正确的检查出nginx是否宕机:

1
2
3
4
5
[root@node1 ~]# sh -x /home/check_nginx.sh 
+ url=https://127.0.0.1/check.html
++ curl -s -o /dev/null -w '%{http_code}' https://127.0.0.1/check.html
+ code=200
+ '[' 200 -ne 200 ']'

以上提示表示nginx正常提供服务。

1
2
3
4
5
[root@nginx1 ~]# sh -x /home/check_nginx.sh
+ url=https://127.0.0.1/check.html
++ curl -s -o /dev/null -w '%{http_code}' https://127.0.0.1/check.html
+ code=404  或 502 或 ...   非200的值
+ '[' 502 -ne 200 ']'

以上提示表示nginx已经宕机了。

  1. 在node1和node5上通过yum安装keepalived
1
2
[root@node1 ~]# yum install keepalived -y
[root@node5 ~]# yum install keepalived -y
  1. node1上配置/etc/keepalived/keepalived.conf文件如下

如果某项不记得如何配置,可以新开一个终端,通过man keepalived.conf命令进行查看配置说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
global_defs {
   #配置接收邮件的邮箱地址,指定keepalived在发生切换时需要发送email到的邮箱地址,一行一个
   notification_email {
     gtjin@bjsxt.com
   }
   notification_email_from keepmanager@126.com #指定发件人
   smtp_server 192.168.20.1 #指定邮件smtp服务器的地址
   smtp_connect_timeout 30 #指定smtp连接的超时时间
   router_id node1 #运行keepalived机器的一个标识
}
#手动定义一个检查机制
vrrp_script chk_nginx {
    script "/home/check_nginx.sh"
    interval 2#每隔2秒检查一次
    weight -20
}
vrrp_instance VI_1 {
    #指定实例的初始化状态,两台路由器都启动后,马上会发生竞选。priority优先级高的被选为Master
    #这里的MASTER并不能代表当前实例一直未MASTER
    state MASTER
    interface ens33 #实例绑定的网卡设备
    virtual_router_id 101#VRID的标记(0-255)
    priority 100#优先级 该值高的实例优先竞选为MASTER,低的为BACKUP
    advert_int 1 #检查间隔,默认为1s
    #认证的设置
    authentication {
        auth_type PASS#认证的方式 PASS 或AH
        auth_pass 1111 # 认证的密码
    }
    #指定虚拟ip地址,也是VIP
    virtual_ipaddress {
        192.168.20.200/24 dev ens33 label ens33:3
    }
    track_script {
        chk_nginx #调用上面定义好检测
    }
}

3.将配置文件远程拷贝到node5上一份

1
2
3
 [root@node1 ~]# scp /etc/keepalived/keepalived.conf root@192.168.20.105:/etc/keepalived/
root@192.168.20.105's password: 
keepalived.conf                                                                                   100% 1434   926.0KB/s   00:00 

4.去node5上修改keepalived.conf文件

1
2
3
4
5
6
7
8
9
router_id node5
....
vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 105
	priority 90
	……
}

5.node1上启动keepalived

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@node1 keepalived]# systemctl start keepalived
[root@node1 keepalived]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
   Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; vendor preset: disabled)
   Active: active (running) since Wed 2021-09-01 18:10:50 CST; 26s ago
  Process: 14753 ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 14754 (keepalived)
    Tasks: 2 (limit: 4911)
   Memory: 5.4M
   CGroup: /system.slice/keepalived.service
           ├─14754 /usr/sbin/keepalived -D
           └─14755 /usr/sbin/keepalived -D

8月 04 18:10:54 node0 Keepalived_vrrp[14755]: Sending gratuitous ARP on ens33 for 192.168.20.200

6.node1上检查

1
2
3
4
5
6
[root@node1 keepalived]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
       ......
ens33:3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.20.200  netmask 255.255.255.0  broadcast 0.0.0.0
        ether 00:0c:29:01:4c:80  txqueuelen 1000  (Ethernet)

浏览器访问测试:https://192.168.20.200,并不断刷新,网页显示结果在8080和9090之间切换。

1628072355812

1628072410890

7.node5上启动keepalived

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@node5 keepalived]# systemctl start keepalived
[root@node5 keepalived]# systemctl status keepalived
● keepalived.service - LVS and VRRP High Availability Monitor
   Loaded: loaded (/usr/lib/systemd/system/keepalived.service; disabled; vendor preset: disabled)
   Active: active (running) since 三 2021-09-01 12:19:18 CST; 6s ago
  Process: 9666 ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 9667 (keepalived)
   CGroup: /system.slice/keepalived.service
           ├─9667 /usr/sbin/keepalived -D
           ├─9668 /usr/sbin/keepalived -D
           └─9669 /usr/sbin/keepalived -D

9月 01 12:19:18 node5 Keepalived_vrrp[9669]: VRRP_Script(chk_nginx) succeeded
9月 01 12:19:21 node5 Keepalived_vrrp[9669]: VRRP_Instance(VI_1) Transition to MASTER STATE
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: VRRP_Instance(VI_1) Entering MASTER STATE
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: VRRP_Instance(VI_1) setting protocol VIPs.
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: Sending gratuitous ARP on ens33 for 192.168.20.200
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: VRRP_Instance(VI_1) Sending/queueing gratuitous ARPs on ens33 for 192.168.20.200
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: Sending gratuitous ARP on ens33 for 192.168.20.200
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: Sending gratuitous ARP on ens33 for 192.168.20.200
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: Sending gratuitous ARP on ens33 for 192.168.20.200
9月 01 12:19:22 node5 Keepalived_vrrp[9669]: Sending gratuitous ARP on ens33 for 192.168.20.200

8.node5上检查,没有启动ens:3的网卡 ??? 为何也有?

1
2
[root@node5 keepalived]# ifconfig
……

9.将node1上的nginx down掉并测试

1
2
[root@node1 keepalived]# systemctl stop nginx 
[root@node1 keepalived]# ifconfig

node5上查看,

1
[root@node5 keepalived]# ifconfig

10.将node1上的nginx和keepalived起来并测试

1
2
[root@node1 keepalived]# systemctl  start nginx
[root@node1 keepalived]# systemctl  start keepalived 

node1上查看,

1
2
[root@node1 keepalived]# ifconfig
[root@node1 ~]# ps aux |grep keepalived

关闭Nginx的时候,keepalived不能被关闭,出现如下错误提示(/var/log/messages):

1
2
Aug  9 12:46:02 node3 setroubleshoot[34963]: failed to retrieve rpm info for /home/check_nginx.sh
Aug  9 12:46:02 node3 setroubleshoot[34963]: SELinux is preventing keepalived from getattr access on the file /home/check_nginx.sh. For complete SELinux messages run: sealert -l e024cc7f-9ba2-41fd-acb1-6c0e12ed25f9

检查SELinux子系统是否启动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@node5 ~]# getenforce 
Enforcing #表示正在启用
[root@node5 ~]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing  #在启用
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      31

临时关闭SELinux:

1
2
3
[root@node5 ~]# setenforce 0
[root@node5 ~]# getenforce 
Permissive #说明临时关闭成功

重启系统后,临时关闭将失效。所以需要再次进行永久关闭:

1
2
[root@node5 ~]# vim /etc/selinux/config
SELINUX=disabled  #默认值是enforcing

重启keepalived,再次查看/var/log/messages,不再出现之前bug。

This post is licensed under CC BY 4.0 by the author.