前言 : Nginx 应用核心概念

Nginx是一个http服务器,是一个使用c语言开发的高性能的http服务器及反向代理服务器。Nginx是一款高性能的http服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试Nginx能够支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。本文将为大家详细介绍关于Nginx的原理以及在应用场景下的相关解析

「什么是Nginx:」

  • Nginx是一个基于HTTP的反向代理服务器,也是一个基IMAP/POP3/SMTP服务邮件服务器

  • 反向代理服务器:现在我们A需要访问的目标B服务器的10.0.0.10,我要访问这个B服务器上的资源,现在如果使用了Nginx之后,我可以通过Nginx服务器从而达到访问10.0.0.10这个服务器的目的
    1.jpg

  • IMAP/POP/SMTP:这三个是邮件的传输协议

  • 邮件服务器:发送邮件 接收邮件

  • Web服务器:本身是一个Web服务器的软件,类似于Tomcat这种Web服务的软件

「Nginx能干什么:」

  • 可以作为Web服务器
  • 可以作为邮件服务器
  • 可以作为反向代理的服务器
  • 动静分离(就是将动态资源和静态资源分隔开)
  • 可以实现负载均衡

代理服务器

代理服务器是在服务器和客户端之间假设的一层服务器,代理将接收客户端的请求并将它转发给服务器,然后将服务端的响应转发给客户端。

不管是正向代理还是反向代理,实现的都是上面的功能。
2.jpg

正向代理

  • 正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
  • 正向代理是为我们服务的,即为客户端服务的,客户端可以根据正向代理访问到它本身无法访问到的服务器资源。
  • 正向代理对我们是透明的,对服务端是非透明的,即服务端并不知道自己收到的是来自代理的访问还是来自真实客户端的访问。

反向代理

  • 反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
  • 反向代理是为服务端服务的,反向代理可以帮助服务器接收来自客户端的请求,帮助服务器做请求转发,负载均衡等。
  • 反向代理对服务端是透明的,对我们是非透明的,即我们并不知道自己访问的是代理服务器,而服务器知道反向代理在为他服务。
  • 反向代理的优势:
  • 隐藏真实服务器;
  • 负载均衡便于横向扩充后端动态服务;
  • 动静分离,提升系统健壮性;

那么“动静分离”是什么?负载均衡又是什么?

动静分离

动静分离是指在 web 服务器架构中,将静态页面与动态页面或者静态内容接口和动态内容接口分开不同系统访问的架构设计方法,进而提示整个服务的访问性和可维护性。

3.jpg

一般来说,都需要将动态资源和静态资源分开,由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上。如果请求的是静态资源,直接到静态资源目录获取资源,如果是动态资源的请求,则利用反向代理的原理,把请求转发给对应后台应用去处理,从而实现动静分离。

使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。

负载均衡

一般情况下,客户端发送多个请求到服务器,服务器处理请求,其中一部分可能要操作一些资源比如数据库、静态资源等,服务器处理完毕后,再将结果返回给客户端。

这种模式对于早期的系统来说,功能要求不复杂,且并发请求相对较少的情况下还能胜任,成本也低。随着信息数量不断增长,访问量和数据量飞速增长,以及系统业务复杂度持续增加,这种做法已无法满足要求,并发量特别大时,服务器容易崩。

很明显这是由于服务器性能的瓶颈造成的问题,除了堆机器之外,最重要的做法就是负载均衡。

请求爆发式增长的情况下,单个机器性能再强劲也无法满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,可以使用多个服务器,然后将请求分发到各个服务器上,将负载分发到不同的服务器,这就是负载均衡,核心是「分摊压力」。Nginx 实现负载均衡,一般来说指的是将请求转发给服务器集群。

举个具体的例子,晚高峰乘坐地铁的时候,入站口经常会有地铁工作人员大喇叭“请走 B 口, B 口人少车空……”,这个工作人员的作用就是负载均衡。

4.jpg

Nginx 实现负载均衡的策略:

  • 轮询策略:默认情况下采用的策略,将所有客户端请求轮询分配给服务端。这种策略是可以正常工作的,但是如果其中某一台服务器压力太大,出现延迟,会影响所有分配在这台服务器下的用户。
  • 最小连接数策略:将请求优先分配给压力较小的服务器,它可以平衡每个队列的长度,并避免向压力大的服务器添加更多的请求。
  • 最快响应时间策略:优先分配给响应时间最短的服务器。
  • 客户端 IP 绑定策略:来自同一个 IP 的请求永远只分配一台服务器,有效解决了动态网页存在的 session 共享问题。

系统环境 CentOS 7.9.2009

一、 nginx安装部署

1.1 yum安装nginx

# 配置eple源
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# 安装nginx
yum install -y nginx

1.2 源码编译安装nginx

1.2.1 安装依赖

[root@node1 ~]# yum install -y gcc gcc-c++  glibc glibc-devel  zlib zlib-devel pcre pcre-devel openssl  openssl-devel autoconf automake make
GCC库(用来编译下载下来的 nginx 源码)

GCC 是 Linux 下最主要的编译工具,GCC 不仅功能非常强大,结构也非常灵活。它可以通过不同的前端模块来支持各种语言,如 Java、Fortran、Pascal、Modula-3 和 Ada。

PCRE库( rewrite 模块需要 pcre 库)

PCRE 支持正则表达式。如果我们在配置文件 nginx.conf 中使用了正则表达式,那么在编译 Nginx 时就必须把PCRE库编译进 Nginx,因为 Nginx 的 HTTP 模块需要靠它来解析正则表达式。另外,pcre-devel 是使用PCRE做二次开发时所需要的开发库,包括头文件等,这也是编译 Nginx 所必须使用的。

ZLIB库( gzip 模块需要 zlib 库)
zlib 提供了很多压缩和解方式,用于对 HTTP 包的内容做 gzip 格式的压缩,如果我们在 nginx.conf 中配置了 gzip on,并指定对于某些类型(content-type)的HTTP响应使用 gzip 来进行压缩以减少网络传输量,则在编译时就必须把 zlib 编译进 Nginx。zlib-devel 是二次开发所需要的库。

OpenSSL库(SSL功能需要 openssl 库)
openssl 是一个安全套接字层密码库,如果服务器不只是要支持 HTTP,还需要在更安全的 SSL 协议上传输 HTTP,那么需要拥有 OpenSSL。另外,如果我们想使用 MD5、SHA1 等散列函数,那么也需要安装它。

1.2.2 下载源码包

下载地址:http://nginx.org/en/download.html

[root@node1 ~]# wget http://nginx.org/download/nginx-1.19.9.tar.gz
[root@node1 ~]# tar -xf nginx-1.19.9.tar.gz      # 解压
[root@node1 ~]# cd  nginx-1.19.9                 # 进入解压文件夹
[root@localhost nginx-1.19.9]# mkdir /usr/local/nginx  # 创建安装目录

1.2.3 根据参数生成Makefile

[root@localhost nginx-1.19.9]# ./configure --prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module  \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module

# ./configure --help 查看帮助信息

–prefix=/usr/local/nginx 指定安装路径

# 自定义参数编译与yum install -y nignx 完全相同
[root@localhost nginx-1.19.9]# ./configure --prefix=/usr/share/nginx 
 --sbin-path=/usr/sbin/nginx 
 --modules-path=/usr/lib64/nginx/modules 
 --conf-path=/etc/nginx/nginx.conf 
 --error-log-path=/var/log/nginx/error.log 
 --http-log-path=/var/log/nginx/access.log 
 --http-client-body-temp-path=/var/lib/nginx/tmp/client_body 
 --http-proxy-temp-path=/var/lib/nginx/tmp/proxy 
 --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi
 --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi 
 --http-scgi-temp-path=/var/lib/nginx/tmp/scgi
 --pid-path=/run/nginx.pid
 --lock-path=/run/lock/subsys/nginx 
 --user=nginx --group=nginx 
 --with-compat --with-debug 
 --with-file-aio 
 --with-google_perftools_module 
 --with-http_addition_module 
 --with-http_auth_request_module
 --with-http_dav_module 
 --with-http_degradation_module 
 --with-http_flv_module 
 --with-http_gunzip_module 
 --with-http_gzip_static_module 
 --with-http_image_filter_module=dynamic 
 --with-http_mp4_module
 --with-http_perl_module=dynamic 
 --with-http_random_index_module 
 --with-http_realip_module 
 --with-http_secure_link_module 
 --with-http_slice_module 
 --with-http_ssl_module 
 --with-http_stub_status_module 
 --with-http_sub_module 
 --with-http_v2_module 
 --with-http_xslt_module=dynamic 
 --with-mail=dynamic 
 --with-mail_ssl_module 
 --with-pcre 
 --with-pcre-jit 
 --with-stream   # tcp负载均衡模块
 --with-stream_ssl_module 
 --with-stream_ssl_preread_module 
 --with-threads --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' \
 --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E'

1.2.4 编译安装

[root@localhost nginx-1.19.9]# make  && make install
[root@localhost nginx-1.19.9]# useradd nginx -s /sbin/nologin -u 2000  # 创建nginx用户
[root@localhost nginx-1.19.9]# chown nginx:nginx -R /usr/local/nginx/

1.2.5 验证版本及编译参数

[root@localhost nginx-1.19.9]# /usr/local/nginx/sbin/nginx -V
nginx version: nginx/1.19.9
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module

1.2.6 创建nginx自启动脚本

[root@node1 nginx-1.19.9]# vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /usr/local/nginx/logs/nginx.pid)"
# ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/sh -c "/bin/kill -s TERM $(/bin/cat /usr/local/nginx/logs/nginx.pid)"
# ExecStop=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true

[Install]
WantedBy=multi-user.target

[Unit]服务的说明

Description:描述服务

After:描述服务类别

[Service]服务运行参数的设置

Type=forking是后台运行的形式

ExecStart为服务的具体运行命令

ExecReload为重启命令

ExecStop为停止命令

PrivateTmp=True表示给服务分配独立的临时空间

注意:[Service]的启动、重启、停止命令全部要求使用绝对路径

[Install]运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3

保存退出。

systemctl daemon-reload //重新加载配置文件

systemctl enable nginx // 加入开机启动

systemctl disable nginx // 禁止开启启动

以服务的方式启动:

pkill nginx // 杀死nginx进程

systemctl start nginx

启动/停止/重启/查看:

systemctl start nginx  启动服务

systemctl stop nginx  停止服务

systemctl restart nginx  重启服务

systemctl status nginx 查看服务当前状态

systemctl list-units --type=service 查看所有已启动的服务

1.2.7 验证自启动脚本

[root@node1 nginx-1.19.9]# systemctl daemon-reload
[root@node1 nginx-1.19.9]# systemctl start nginx
[root@node1 nginx-1.19.9]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.

[root@node1 nginx-1.19.9]# systemctl status nginx
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since 四 2021-04-01 17:02:02 CST; 4s ago
     Docs: http://nginx.org/en/docs/
  Process: 52326 ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf (code=exited, status=0/SUCCESS)
 Main PID: 52327 (nginx)
   CGroup: /system.slice/nginx.service
           ├─52327 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.co...
           └─52328 nginx: worker process

4月 01 17:02:02 localhost.localdomain systemd[1]: Starting nginx - high performance web server...
4月 01 17:02:02 localhost.localdomain systemd[1]: Started nginx - high performance web server.

1.3 使用docker部署nginx

# 方式一
docker run --name=nginx -p 80:80 -d nginx:1.19.9

# 方式二  挂载本地目录到容器
docker run --name=nginx -p 80:80 \ 
-v /opt/nginx/conf:/etc/nginx \      # 提前准备好配置文件,否则无法启动容器
-v /opt/nginx/log:/var/log/nginx \ 
-v /opt/nginx/lib/:var/lib/nginx \
-v /opt/nginx/html:/usr/share/nginx/html  -d  nginx:1.19.9
# 使用docker-compose部署nginx
# vim nginx1.19.9.yaml
version: "3.5"
services:
  nginx:
    image: nginx:1.19.9
    container_name: nginx
    hostname: nginx
    ports:
    - "80:80"
    volumes:
    - "/opt/nginx/conf:/etc/nginx"     # 提前准备好配置文件,否则无法启动容器
    - "/opt/nginx/log:/var/log/nginx"
    - "/opt/nginx/lib/:var/lib/nginx"
    - "/opt/nginx/html:/usr/share/nginx/html"
    networks:
    - nginx_net

networks:
  nginx_net:
docker-compose -f nginx1.19.9.yaml up -d   # 启动容器
docker-compose -f nginx1.19.9.yaml down    # 删除容器

二、nginx功能及使用

2.1 nginx常用命令

# 启动nginx
nginx   # 初次启动,再次使用会报错,端口被占用
nginx -help  # 帮助命令
nginx -s stop # 停止nginx
nginx -s reload  # 重载nginx配置文件--热更新配置

[root@localhost conf]# nginx -help
nginx version: nginx/1.19.9
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
             [-e filename] [-c filename] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/share/nginx/)
  -e filename   : set error log file (default: /var/log/nginx/error.log)
  -c filename   : set configuration file (default: /etc/nginx/nginx.conf)
  -g directives : set global directives out of configuration file

我们的操作指令,比如./nginx、./nginx -s reload、./nginx -t等等,都是由master进程接收,但并非由master进程执行。而是master进程接收到这些指令之后,逐个发送给所有的worker进程,由它们去执行。

每一个worker进程,可以有很多连接,处理多个用户请求。

5.jpg

2.2 nginx配置文件详解

# 定义Nginx运行的用户和用户组
# user nobady nobady;
# nginx进程数,建议设置为等于CPU总核心数,默认为1。
worker_processes 8;
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /usr/local/nginx/logs/error.log info;
#进程pid文件,指定nginx进程运行文件存放地址
pid /usr/local/nginx/logs/nginx.pid;
# 指定进程可以打开的最大描述符:数目
# 工作模式与连接数上限
# 这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致。
# 现在在linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535。
#这是因为nginx调度时分配请求到进程并不是那么的均衡,所以假如填写10240,总并发量达到3-4 万时就有进程可能超过10240了,这时会返回502错误。
worker_rlimit_nofile 65535;

events
{
 #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll]; epoll模型
 #是Linux 2.6以上版本内核中的高性能网络I/O模型,linux建议epoll,如果跑在FreeBSD上面,就用kqueue模型。
 #补充说明:
 #与apache相类,nginx针对不同的操作系统,有不同的事件模型
 #A)标准事件模型
 #Select、poll属于标准事件模型,如果当前系统不存在更有效的方法,nginx会选择select或poll
 #B)高效事件模型
 #Kqueue:使用于FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X.使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。
 #Epoll:使用于Linux内核2.6版本及以后的系统。
 #/dev/poll:使用于Solaris 7 11/99+,HP/UX 11.22+ (eventport),IRIX6.5.15+ 和 Tru64 UNIX 5.1A+。
 #Eventport:使用于Solaris 10。 为了防止出现内核崩溃的问题, 有必要安装安全补丁。
 use epoll;
 #单个进程最大连接数(最大连接数=连接数*进程数)
 #根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行。每个进程允许的最多连接数,理论上每台nginx服务器的最大连接数为。
 worker_connections 65535;
 #keepalive超时时间,默认是60s,切记这个参数也不能设置过大!否则会导致许多无效的http连接占据着nginx的连接数,终nginx崩溃!
 keepalive_timeout 60;
 #客户端请求头部的缓冲区大小。这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。
 #分页大小可以用命令getconf PAGESIZE 取得。
 #[root@web001 ~]# getconf PAGESIZE
 #4096
 #但也有client_header_buffer_size超过4k的情况,但是client_header_buffer_size该值必须设置为“系统分页大小”的整倍数。
 client_header_buffer_size 4k;
 #这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。
 open_file_cache max=65535 inactive=60s;
 #这个是指多长时间检查一次缓存的有效信息。
 #语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了何时需要检查open_file_cache中缓存项目的有效信息.
 open_file_cache_valid 60s;
 #open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive时间内一次没被使用,它将被移除。
 #语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如果使用更大的值,文件描述符在cache中总是打开状态.
 open_file_cache_min_uses 1;
#语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.
 open_file_cache_errors on;
}

#设定http服务器,利用它的反向代理功能提供负载均衡支持
http
{
 #文件扩展名与文件类型映射表
 include mime.types;
 #默认文件类型
 default_type application/octet-stream;
 #默认编码
 #charset utf-8;
 #服务器名字的hash表大小
 #保存服务器名字的hash表是由指令server_names_hash_max_size 和server_names_hash_bucket_size所控制的。参数hash bucket size总是等于hash表的大小,并且是一路处理器缓存大小的倍数。在减少了在内存中的存取次数后,使在处理器中加速查找hash表键值成为可能。如果hash bucket size等于一路处理器缓存的大小,那么在查找键的时候,最坏的情况下在内存中查找的次数为2。第一次是确定存储单元的地址,第二次是在存储单元中查找键 值。因此,如果Nginx给出需要增大hash max size 或 hash bucket size的提示,那么首要的是增大前一个参数的大小.
 server_names_hash_bucket_size 128;
 #客户端请求头部的缓冲区大小。这个可以根据你的系统分页大小来设置,一般一个请求的头部大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。
 client_header_buffer_size 32k;
 #客户请求头缓冲大小。nginx默认会用client_header_buffer_size这个buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取。
 large_client_header_buffers 4 64k;
 #设定通过nginx上传文件的大小
 client_max_body_size 8m;
 #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
 #sendfile指令指定 nginx 是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度,降低系统uptime。
 sendfile on;
 #开启目录列表访问,合适下载服务器,默认关闭。
 autoindex on;
 #此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用,告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送。就是说数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞
 tcp_nopush on;
#告诉nginx不要缓存数据,而是一段一段的发送--当需要及时发送数据时,就应该给应用设置这个属性,这样发送一小块数据信息时就不能立即得到返回值
 tcp_nodelay on;
 #长连接超时时间,单位是秒
 keepalive_timeout 120;
 #FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
 #这个指令为FastCGI缓存指定一个路径,目录结构等级,关键字区域存储时间和非活动删除时间
 fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2
 keys_zone=TEST:10m inactive=5m;
 #指定连接到后端FastCGI的超时时间
 fastcgi_connect_timeout 300;
 #向FastCGI传送请求的超时时间,这个值是指已经完成两次握手后向FastCGI传送请求的超时时间
 fastcgi_send_timeout 300;
 #接收FastCGI应答的超时时间,这个值是指已经完成两次握手后接收FastCGI应答的超时时间
 fastcgi_read_timeout 300;
 #指定读取FastCGI应答第一部分 需要用多大的缓冲区,这里可以设置为fastcgi_buffers指令指定的缓冲区大小,上面的指令指定它将使用1个 16k的缓冲区去读取应答的第一部分,即应答头,其实这个应答头一般情况下都很小(不会超过1k),但是你如果在fastcgi_buffers指令中指定了缓冲区的大小,那么它也会分配一个fastcgi_buffers指定的缓冲区大小去缓存
 fastcgi_buffer_size 64k;
 #指定本地需要用多少和多大的缓冲区来 缓冲FastCGI的应答,如上所示,如果一个php脚本所产生的页面大小为256k,则会为其分配16个16k的缓冲区来缓存,如果大于256k,增大 于256k的部分会缓存到fastcgi_temp指定的路径中, 当然这对服务器负载来说是不明智的方案,因为内存中处理数据速度要快于硬盘,通常这个值 的设置应该选择一个你的站点中的php脚本所产生的页面大小的中间值,比如你的站点大部分脚本所产生的页面大小为 256k就可以把这个值设置为16 16k,或者464k 或者64 4k,但很显然,后两种并不是好的设置方法,因为如果产生的页面只有32k,如果用464k它会分配1个64k的缓冲区去缓存,而如果使用64 4k它会分配8个4k的缓冲区去缓存,而如果使用16 16k则它会分配2个16k去缓存页面,这样看起来似乎更加合理•
 fastcgi_buffers 4 64k;
 #这个指令我也不知道是做什么用,只知道默认值是fastcgi_buffers的两倍
 fastcgi_busy_buffers_size 128k;
 #在写入fastcgi_temp_path时将用多大的数据块,默认值是fastcgi_buffers的两倍
 fastcgi_temp_file_write_size 128k;
 #开启FastCGI缓存并且为其制定一个名称。个人感觉开启缓存非常有用,可以有效降低CPU负载,并且防止502错误。但是这个缓存会引起很多问题,因为它缓存的是动态页面。具体使用还需根据自己的需求
 fastcgi_cache TEST
 #为指定的应答代码指定缓存时间,如上例中将200,302应答缓存一小时,301应答缓存1天,其他为1分钟
 fastcgi_cache_valid 200 302 1h;
 fastcgi_cache_valid 301 1d;
 fastcgi_cache_valid any 1m;
 #缓存在fastcgi_cache_path指令inactive参数值时间内的最少使用次数,如上例,如果在5分钟内某文件1次也没有被使用,那么这个文件将被移除
 fastcgi_cache_min_uses 1;
 #gzip模块设置
 #开启压缩 
gzip  on;  
 # 设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。默认值是0,不管页面多大都压缩。建议设置成大于2k的字节数,小于2k可能会越压越大。
gzip_min_length 2k; 
 # 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。 例如 4 4k 代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存。 4 8k 代表以8k为单位,按照原始数据大小以8k为单位的4倍申请内存。 
 # 如果没有设置,默认值是申请跟原始数据相同大小的内存空间去存储gzip压缩结果。 
 gzip_buffers 4 16k; 
 #压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间 
 gzip_comp_level 5; 
 # 默认值: gzip_types text/html (默认不对js/css文件进行压缩) 
 # 压缩类型,匹配MIME类型进行压缩 
 # 不能用通配符 text/* 
 # (无论是否指定)text/html默认已经压缩  
 # 设置哪压缩种文本文件可参考 conf/mime.types 
 gzip_types text/plain application/x-
 javascript text/css application/xml;
 # 值为1.0和1.1 代表是否压缩http协议1.0,选择1.0则1.0和1.1都可以压缩 
 gzip_http_version 1.0  
 # IE6及以下禁止压缩 
 gzip_disable "MSIE [1-6]\.";  
 # 默认值:off 
 # Nginx作为反向代理的时候启用,开启或者关闭后端服务器返回的结果,匹配的前提是后端服务器必须要返回包含"Via"的 header头。 
 # 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_proxied expired no-cache no-store private auth; 
 # 给CDN和代理服务器使用,针对相同url,可以根据头信息返回压缩和非压缩副本 
 gzip_vary on; 
 #开启限制IP连接数的时候需要使用
 #limit_zone crawler $binary_remote_addr 10m;
 #负载均衡配置
 upstream www.xx.com {

   #upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
   server 10.0.0.20:80 weight=3;
   server 10.0.0.21:80 weight=2;
   server 10.0.0.22:80 weight=3;
   #nginx的upstream目前支持4种方式的分配
   #1、轮询(默认)
   #每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
   #2、weight
   #指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
   #例如:
#upstream bakend {
   #  server 10.0.0.20 weight=10;
   #  server 10.0.0.21 weight=10;
   #}
   #2、ip_hash
   #每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
   #例如:
   #upstream bakend {
   #  ip_hash;
   #  server 10.0.0.20;
   #  server 10.0.0.21:80;
   #}
   #3、fair(第三方)
   #按后端服务器的响应时间来分配请求,响应时间短的优先分配。
   #upstream backend {
   #  server server1;
   #  server server2;
   #  fair;
   #}
   #4、url_hash(第三方)
   #按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
   #例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
   #upstream backend {
   #  server squid1:3128;
   #  server squid2:3128;
   #  hash $request_uri;
   #  hash_method crc32;
   #}
   #tips:
   #upstream bakend{#定义负载均衡设备的Ip及设备状态}{
   #  ip_hash;
   #  server 127.0.0.1:9090 down;
   #  server 127.0.0.1:8080 weight=2;
   #  server 127.0.0.1:6060;
   #  server 127.0.0.1:7070 backup;
   #}
   #在需要使用负载均衡的server中增加 proxy_pass http://bakend/;
   #每个设备的状态设置为:
   #1.down表示单前的server暂时不参与负载
   #2.weight为weight越大,负载的权重就越大。
   #3.max_fails:允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream模块定义的错误
   #4.fail_timeout:max_fails次失败后,暂停的时间。
   #5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。
   #nginx支持同时设置多组的负载均衡,用来给不用的server来使用。
   #client_body_in_file_only设置为On 可以讲client post过来的数据记录到文件中用来做debug
   #client_body_temp_path设置记录文件的目录 可以设置最多3层目录
   #location对URL进行匹配.可以进行重定向或者进行新的代理 负载均衡
 }
#虚拟主机的配置
 server
 {
   #监听端口
   listen 80;
   #域名可以有多个,用空格隔开
   server_name www.xx.com xx.com;
   index index.html index.htm index.php;
   root /data/www/xx;
   #对******进行负载均衡
   location ~ .*.(php|php5)?$
   {
     fastcgi_pass 127.0.0.1:9000;
     fastcgi_index index.php;
     include fastcgi.conf;
   }

   #图片缓存时间设置
   location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
   {
     expires 10d;
   }

   #JS和CSS缓存时间设置
   location ~ .*.(js|css)?$
   {
     expires 1h;
   }

   #日志格式设定
   #$remote_addr与$http_x_forwarded_for用以记录客户端的ip地址;
   #$remote_user:用来记录客户端用户名称;
   #$time_local: 用来记录访问时间与时区;
   #$request: 用来记录请求的url与http协议;
   #$status: 用来记录请求状态;成功是200,
   #$body_bytes_sent :记录发送给客户端文件主体内容大小;
   #$http_referer:用来记录从那个页面链接访问过来的;
   #$http_user_agent:记录客户浏览器的相关信息;
   #通常web服务器放在反向代理的后面,这样就不能获取到客户的IP地址了,通过$remote_add拿到的IP地址是反向代理服务器的iP地址。
   #反向代理服务器在转发请求的http头信息中,可以增加x_forwarded_for信息,用以记录原有客户端的IP地址和原来客户端的请求的服务器地址。
   log_format access '$remote_addr - $remote_user [$time_local]
   "$request" '
   '$status $body_bytes_sent "$http_referer" '
   '"$http_user_agent" $http_x_forwarded_for';

   #定义本虚拟主机的访问日志
   access_log /usr/local/nginx/logs/host.access.log main;
   access_log /usr/local/nginx/logs/host.access.404.log log404;

   #对 "/" 启用反向代理
   location / {
     proxy_pass http://127.0.0.1:88;
     proxy_redirect off;
     proxy_set_header X-Real-IP $remote_addr;

     #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

     #以下是一些反向代理的配置,可选。
     proxy_set_header Host $host;
     #允许客户端请求的最大单文件字节数
     client_max_body_size 10m;
     #缓冲区代理缓冲用户端请求的最大字节数,
     #如果把它设置为比较大的数值,例如256k,那么,无论使用firefox还是IE浏览器,来提交任意小于256k的图片,都很正常。如果注释该指令,使用默认的client_body_buffer_size设置,也就是操作系统页面大小的两倍,8k或者16k,问题就出现了。
     #无论使用firefox4.0还是IE8.0,提交一个比较大,200k左右的图片,都返回
     500 Internal Server Error错误
     client_body_buffer_size 128k;
     #表示使nginx阻止HTTP应答代码为400或者更高的应答。
     proxy_intercept_errors on;
     #后端服务器连接的超时时间_发起握手等候响应超时时间
     #nginx跟后端服务器连接超时时间(代理连接超时)
     proxy_connect_timeout 90;
     #后端服务器数据回传时间(代理发送超时)
     #后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据
     proxy_send_timeout 90;
     #连接成功后,后端服务器响应时间(代理接收超时)
     #连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)
     proxy_read_timeout 90;
     #设置代理服务器(nginx)保存用户头信息的缓冲区大小
     #设置从被代理服务器读取的第一部分应答的缓冲区大小,通常情况下这部分应答中包含一个小的应答头,默认情况下这个值的大小为指令proxy_buffers中指定的一个缓冲区的大小,不过可以将其设置为更小
     proxy_buffer_size 4k;
     #proxy_buffers缓冲区,网页平均在32k以下的设置
     #设置用于读取应答(来自被代理服务器)的缓冲区数目和大小,默认情况也为分页大小,根据操作系统的不同可能是4k或者8k
     proxy_buffers 4 32k;
     #高负荷下缓冲大小(proxy_buffers*2)
     proxy_busy_buffers_size 64k;
     #设置在写入proxy_temp_path时数据的大小,预防一个工作进程在传递文件时阻塞太长
     #设定缓存文件夹大小,大于这个值,将从upstream服务器传
     proxy_temp_file_write_size 64k;
   }


   #设定查看Nginx状态的地址
    location /NginxStatus {
     stub_status on;
     access_log on;
     auth_basic "NginxStatus";
     auth_basic_user_file confpasswd;
     #htpasswd文件的内容可以用apache提供的htpasswd工具来产生。
   }

   #本地动静分离反向代理配置
   #所有jsp的页面均交由tomcat或resin处理
   location ~ .(jsp|jspx|do)?$ {
     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_pass http://127.0.0.1:8080;
   }

   #所有静态文件由nginx直接读取不经过tomcat或resin
   location ~ .*.
  (htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|
   pdf|xls|mp3|wma)$
   {
     expires 15d;
   }

   location ~ .*.(js|css)?$
   {
     expires 1h;
   }
 }
}

配置文件思维导图:

6.jpg

7.jpg

main:最外层称之为main,进行全局配置,也将main称之为容器。

event:配置Nginx的工作模式以及连接数,它也被称之为指令块。

http:http模块相关的配置,它可以用来导入其他的文件,包括mine.types文件、*.conf文件等等,同时它还包含很多其他的配置。

http {
    ##
    # Basic Settings
    ##

    sendfile on; #开启高效文件传输模式,on异步,off同步,如果图片显示不正常把这个改成off,如果是以下载为主的应用,可以设置为同步。

    tcp_nopush on; # 开启优化tcp传输,仅在sendFile开启时生效。
    tcp_nodelay on; # tcp不延迟发送,即关闭tcp协议nagle算法、关闭tcp发送缓存,对于数据实时性高的应用开启,对于吞吐量高的应用关闭。

    keepalive_timeout 65; # TCP连接最长保持时间,单位s。
    types_hash_max_size 2048; # types_hash_max_size越大,就会消耗更多的内存,但散列key的冲突率会降低,检索速度就更快。types_hash_max_size越小,消耗的内存就越小,但散列key的冲突率可能上升。

    # server_tokens off; 错误页面的标签上是否表示Nginx的版本。
    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off; 重定向时是否将服务器名写入head。

    include /usr/local/nginx/conf/mime.types;
    default_type application/octet-stream; # 指定mime.types文件中没有记述到的后缀名的处理方法。

    ##
    # SSL Settings
    ##

    #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    #ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log; # 连接日志
    error_log /var/log/nginx/error.log; # 错误日志

    ##
    # Gzip Settings
    ##

    gzip on; # 开启压缩传输,降低网络IO,但是提高CPU占用。
    gzip_disable "MSIE [1-6]\."; # IE6及以下禁用压缩
    gzip_vary on; # 给CDN和代理服务器使用,针对相同url,可以根据头信息返回压缩和非压缩副本
    gzip_proxied any; 
    gzip_comp_level 6; # 压缩级别
    gzip_buffers 16 8k; # 压缩时缓存的大小,如果不设置,默认是申请跟原始数据相同大小的内存空间去存储gzip压缩结果,这里的缓存大小是16 * 8k。
    gzip_http_version 1.1; # http1.1以上支持压缩
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 对这些类型的资源进行压缩
    gzip_min_length 2k # 超过2k的资源才进行压缩,建议设置为2k,小于2k浪费CPU,并且还可能越压越大。

    ##
    # Virtual Host Configs
    ##

    include /usr/local/nginx/conf/conf.d/*.conf; # 这个文件只配置virtual host 虚拟主机
    #include /etc/nginx/sites-enabled/*;
}

upstream:用于配置集群即内网服务器,负载均衡的规则由它指定。

upstream frontwebserver {
    server 127.0.0.1:8050       weight=1 down;
    server 127.0.0.1:8060       weight=1;
    server 127.0.0.1:8060       weight=1 backup;
    # down:表示当前的server暂时不参与负载。
    # weight:默认为1,weight越大,负载的权重就越大。 
    # backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。
}

server:虚拟主机,虚拟主机用于监听指定套接字下的请求,Nginx可以配置很多个虚拟主机(server),并且每个虚拟主机(server)通过server_name指定监听多个域名。

server {
  listen 80;
  server_name doc.myworldelite.com www.doc.myworldelite.com; # 他这里是在hosts文件中映射过了

  location / {}
}

location:路有映射,它负责对其虚拟主机接收到的请求做出映射,每个虚拟主机(server)只能有一个路由映射(location)。

# 对当前路径及子路径下的所有资源生效
location /index {
     root /apps/worldelite/api-docs; # 根目录, 并且index会拼接到这后面形成真正的根目录
     alias /home/index; # 别名,可以隐藏'location /'的后面的index,改为'location /static'
     index index.html # 默认页,可以配置多个
     # try_files $uri $uri/ /index.html; # $uri 是Nginx内部提供的一些参数变量,$uri可以获取请求的路由
     # 添加response header的属性
     add_header Access-Control-Allow-Origin *; # 允许所有域名的脚本访问该资源
     add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
     add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
}

Nginx修改静态资源不需要重启,但是修改conf配置文件需要重启。

2.3 Nginx的进程模型

Nginx启动之后会有两种进程,分别是master进程和worker进程。

8.jpg

多进程中的 Nginx 进程架构如下图所示,会有一个父进程(Master Process),它会有很多子进程(Child Processes)

  • Master Process 用来管理子进程的,其本身并不真正处理用户请求。
  • 某个子进程 down 掉的话,它会向 Master 进程发送一条消息,表明自己不可用了,此时 Master 进程会去新起一个子进程。
  • 某个配置文件被修改了 Master 进程会去通知 work 进程获取新的配置信息,这也就是我们所说的热部署。
  • 子进程间是通过共享内存的方式进行通信的。

2.3.1 配置文件重载原理

  • reload 重载配置文件的流程:
  • 向 master 进程发送 HUP 信号(reload 命令);
  • master 进程检查配置语法是否正确;
  • master 进程打开监听端口;
  • master 进程使用新的配置文件启动新的 worker 子进程;
  • master 进程向老的 worker 子进程发送 QUIT 信号;
  • 老的 worker 进程关闭监听句柄,处理完当前连接后关闭进程;
  • 整个过程 Nginx 始终处于平稳运行中,实现了平滑升级,用户无感知;

查看nginx进程

[root@a conf]# ps axu | grep nginx
root     127778  0.0  0.0  39312   984 ?        Ss   14:32   0:00 nginx: master process /usr/sbin/nginx
nginx    127779  0.0  0.1  39860  3424 ?        S    14:32   0:00 nginx: worker process
nginx    127780  0.0  0.1  39860  3424 ?        S    14:32   0:00 nginx: worker process
root     128500  0.0  0.1 112832  2356 pts/0    S+   14:33   0:00 grep --color=auto nginx

默认配置下,master与worker进程都只有一个,但是我们可以通过worker_processes配置worker进程数

worker_processes  1;

# worker_processes  auto;  #根据CPU核数自动启动进程数

worker的工作模式

worker对于连接是采用争抢的模式,谁先抢到就先交给谁处理,如果想要重新更新配置,由于已经抢到任务的worker不会参与争抢,那些空闲的worker就会去争抢连接,拿到连接后会自动更新配置信息,当那些有任务的worker完成任务后,会自动更新配置,这样就实现了无缝热部署。由于每个worker是独立的进程,如果有其中的一个worker出现问题,并不会影响其它worker继续进行争抢,在实现请求的过程,不会造成服务中断,建议worker数和服务器的cpu数相等是最为适宜的。

9.jpg

  • 如果只访问nginx的静态资源,一个发送请求会占用了 woker 的 2 个连接数
  • 而如果是作为反向代理服务器,一个发送请求会占用了 woker 的 4 个连接数
  • 如果只访问nginx的静态资源,最大并发数量应该是: worker_connections * worker_processes / 2
  • 而如果是作为反向代理服务器,最大并发数量应该是:worker_connections * worker_processes / 4

2.3.2 Nginx 模块化管理机制

Nginx 的内部结构是由核心部分和一系列的功能模块所组成。这样划分是为了使得每个模块的功能相对简单,便于开发,同时也便于对系统进行功能扩展。Nginx 的模块是互相独立的,低耦合高内聚。

10.jpg

2.4 location匹配规则

# 对当前路径及子路径下的所有资源匹配
location / {   
    root html;
}

# 对当前路径匹配,子路径下的资源无法匹配,此时访问的是localhost:xx/imooc/img/static/face1.png
location = /imooc/img/face1.png {   
    root static;
}

# 正则表达式匹配, *代表不区分大小写
# 由于这里没有指定开头和结尾,所以只要是访问的资源包含.GIF\.PNG\.BMP\.JPG\.JPEG这些的就可以正确匹配
# \. 是为了转义
location ~* \.(GIF|PNG|BMP|JPG|JPEG) {   
    root static;
}

# 正则表达式匹配, 区分大小写
location ~ \.(GIF|PNG|BMP|JPG|JPEG) {   
    root static;
}

# 正则表达式匹配,^表示以什么开头,~表示匹配到该字符串后停止以正则表达式进行匹配
# localhost:xx/imooc/face1.png          是可以访问到的
# localhost:xx/imooc/sub/face2.png      也是可以访问到的
location ^~ /imooc/ {
    root static;
}
# location 匹配规则优先级   |=|>|^~|>|~|=|~*|>无符号
location  = /images {
return 601;
}
location ^~ /images {
return 602;
}
location ~ /images {
return 603;
}
location ~*/images {
return 604;
}
location /images {
return 605;
}
location / {
return 606;
}

2.5 Nginx解决跨域问题

跨域,CORS(Cross-Origin Resource Sharing),即跨域资源共享。

它允许浏览器向跨域名(Origin)的服务器发起ajax请求获取响应,一般而言实现跨域可以通过Jsoup、SpringBoot Cors和Nginx。

# 在Nginx中添加跨域支持
server {
    listen 80;
    server_name admin.test.myworldelite.com;

    # 允许跨域请求的域,*代表所有
    add_header 'Access-Control-Allow-Origin' *;
    # 允许带上cookie请求
    add_header 'Access-Control-Allow-Credentials' 'true';
    # 允许请求的方法,比如 GET/POST/PUT/DELETE
    add_header 'Access-Control-Allow-Methods' *;
    # 允许请求的header
    add_header 'Access-Control-Allow-Headers' *;

    location / {}
}

2.6 Nginx配置静态资源防盗链

如果服务器不配置防盗链,则任何其他站点都可以通过你资源的url盗用你的静态资源。

# Nginx防盗链配置

server {
    # 对源站点验证
    valid_referers *.imooc.com; 
    # 非法引入会进入下方判断
    # $invalid_referer是Nginx的内部变量,如果源站点验证未通过,则会进入return 404
    if ($invalid_referer) {
        return 404;
    } 
}

2.7 Nginx构建集群

# nginx服务器ip是10.0.0.10
# 三台tomcat服务器的ip分别是:
#                       10.0.0.20
#                       10.0.0.21
#                       10.0.0.22

# 配置上游服务器
# 如果upstream中只有一台服务器,则Nginx相当于只起到一个反向代理屏蔽端口号的功能
upstream tomcatwebs {
    server 10.0.0.20:8080;
    server 10.0.0.21:8080;
    server 10.0.0.22:8080;
}

# 配置虚拟主机
server {
    listen 80;
    server_name localhost; # 虚拟主机的名字,无关紧要

    location / {
        # 指定的proxy_pass必须与upstream指定的字符串一致
        # Nginx拦截到的请求将会通过proxy_pass转发给对应的upstream
        proxy_pass http://tomcatwebs;
        proxy_set_header HOST $host;        
        proxy_set_header X-Real-IP $remote_addr;                    
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    }
}

2.8 负载均衡策略

Nginx默认使用轮询策略。

在 upstream 内可使用的指令:

server 定义上游服务器地址;

zone 定义共享内存,用于跨 worker 子进程;

keepalive 对上游服务启用长连接;

keepalive_requests 一个长连接最多请求 HTTP 的个数;

keepalive_timeout 空闲情形下,一个长连接的超时时长;

hash 哈希负载均衡算法;

ip_hash 依据 IP 进行哈希计算的负载均衡算法;

least_conn 最少连接数负载均衡算法;

least_time 最短响应时间负载均衡算法;

random 随机负载均衡算法;

2.8.1 加权轮询

upstream study {
    server 10.0.0.20:8080 weight=1;         # tomcat1
    server 10.0.0.21:8080 weight=2;         # tomcat2
    server 10.0.0.22:8080 weight=2;         # tomcat3
}

此时的轮询情况是:tomcat1 -> tomcat2 -> tomcat3 -> tomcat2 -> tomcat3

2.8.2 ip_hash

根据客户端的请求 ip 进行判断,只要 ip 地址不变就永远分配到同一台主机。它可以有效解决后台服务器 session 保持的问题。

注意:如果使用ip_hash,则不能将后台服务器直接移除,只能使用down。

# Simple Example
upstream study {
    ip_hash;

    server 10.0.0.20:8080;          # tomcat1
    server 10.0.0.21:8080 down;     # tomcat2
    server 10.0.0.22:8080;          # tomcat3
}

2.8.3 最少连接数算法

各个 worker 子进程通过读取共享内存的数据,来获取后端服务器的信息。来挑选一台当前已建立连接数最少的服务器进行分配请求

语法:least_conn;

上下文:upstream;
upstream demo_server {
  zone test 10M; # zone可以设置共享内存空间的名字和大小
  least_conn;
  server 10.0.0.20:8020;
  server 10.0.0.21:8030;
  server 10.0.0.22:8040;
}

server {
      listen 80;
      server_name balance.com;

      location /balance/ {
            proxy_pass http://demo_server;
      }
}

2.8.4upstream指令参数

  • max_conns:

限制最大连接数,它的默认值是0,即不做任何限制。注:该参数在1.11.5版本之前只对Nginx的商业版开放。

# Simple Example
upstream study {
    server 10.0.0.20:8080 max_conns=2;
}
  • slow_start:

让它指定的服务器慢启动,有些场景个别服务器可能不希望一开始就有用户流量打进来,可以配置slow_start注:该参数仅对商业版开放。

# Simple Example
upstream study {
    # slow_start 会将该主机的权重从0逐渐升级到10
    # slow_start 仅支持轮询带weight的负载均衡,不支持hash、random负载均衡
    # slow_start 不支持非集群环境下的主机
    server 10.0.0.20:8080 weight=10 slow_start=60s;
    server 10.0.0.21:8080 weight=2;
}
  • down:

它指定的服务器不参与负载均衡。

# Simple Example
upstream study {
    # 该主机将不参与负载均衡
    server 10.0.0.20:8080 down;
    server 10.0.0.21:8080;
}
  • backup:

它指定的服务器会成为备用机,正常情况下不会参与负载均衡,只有当其他服务器宕机之后,它才会参与。

# Simple Example
upstream study {
    # 该主机将不参与负载均衡
    server 10.0.0.20:8080 backup;
    server 10.0.0.21:8080 weight=1;
}
  • max_fails / fail_timeout:

max_fails指定服务器的最大失败次数,如果该服务器处理请求的失败次数达到了指定的阈值,则Nginx会将其剔出集群。

fail_timeout指定max_fails生效的时间范围与主机剔出集群后重新加入集群的时间,二者结合使用。

# Simple Example
upstream study {
    # 该主机如果在30s内,处理请求错误的次数达到了20次,则将该主机剔出集群30s,30s后重新加入集群
    server 192.168.95.5:8080 weight=1 max_fails=20 fail_timeout=30s;
    server 192.168.95.6:8080 weight=1;
}

2.8.5 Nginx upstream虚拟配置示例

# 示例1 
upstream backendwebs {                 #名字可以随便起
    server www.a.com;         # 后端的域名
    server www.b.com:8888;     # 后端的端口
}
server {
    location / {
        proxy_pass http://backendwebs; # proxy_pass调用upstream里定义的名字
    }
}
# 示例2
upstream wordpress.com {
    server 10.0.0.20 ;
    server 10.0.0.21 ;
}
upstream zh.com {

    server 10.0.0.22 weight=1;
    server 10.0.0.23 weight=2;
}
upstream phpshecom {
    ip_hash;
    server 10.0.0.24;
    server 10.0.0.25;
}
upstream php.com {
    least_conn;
    server 10.0.0.26;
    server 10.0.0.27;
}

server {
    listen 80;
    server_name wordpress.com;

    location / {
        proxy_pass http://wordpress.com;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    }
}

server {
    listen 80;
    server_name phpshe.sheng.com;

    location / {
        proxy_pass http://phpshecom;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    }
}
server {
    listen 80;
    server_name zh.sheng.com;

    location / {
        proxy_pass http://zh.com;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    }
}
server {
    listen 80;
    server_name php.sheng.com;

    location / {
        proxy_pass http://php.com;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    }
}

2.8.6 TCP负载均衡示例

# stream模块与http模块同级    注意:【不能放在http里面】
# nginx开启stream模块    ./configure --prefix=/usr/local/nginx --with-stream
# 因业务需要,搭建nginx负载均衡转发kafka集群,只能使用tcp
stream {
    server {
        listen 9092;
        proxy_pass kafka;
    }

    upstream kafka {
        server kafka01:9092 weight=1;
    }
}

2.9 Nginx缓存

两部分缓存

11.jpg

Nginx到浏览器之间会有一层缓存,浏览器的缓存是面向单用户的。

而上有服务器到Nginx之间也会有一层缓存,因为Nginx将请求反向代理到内网中其他的服务器去请求资源,这个也是有网络传输的,如果这个静态资源可以在Nginx中缓存,则可以节约时间。

2.9.1 设置浏览器缓存

expires [time]

# Simple Example
server {
    ...

    # 在/opt/static目录下有一个cache.html文件
    location /static {
        root /opt;
        # 缓存10s
        expires 10s;
    }
}

置完成后请求cache.html的响应头:

HTTP/1.1 200 OK
Server: nginx/1.19.9
# 服务器中的文件最后修改的时间
# 如果文件修改了,则会自动重新请求,不经过缓存
Last-Modified: Wed, 24 Mar 2021 14:32:07 GMT
Date: Wed, 24 Mar 2021 14:37:16 GMT                     # 响应时间
Expires: Wed, 24 Mar 2021 14:37:26 GMT                  # 缓存过期时间
Cache-Control: max-age=10                               # 缓存最大时间(s)
Content-Type: text/html
Content-Length: 11
ETag: "605b4d67-b"
Accept-Ranges: bytes

expires @[time]

# Simple Example
server {
    ...

    # 在/opt/static目录下有一个cache.html文件
    location /static {
        root /opt;
        # 缓存到今天晚上10点50分
        expires @22h50m;
    }
}

设置完成后请求cache.html的响应头:

HTTP/1.1 200 OK
Server: nginx/1.19.9
Last-Modified: Wed, 24 Mar 2021 14:42:01 GMT
Date: Wed, 24 Mar 2021 14:45:44 GMT
Expires: Wed, 24 Mar 2021 14:50:00 GMT                  # 缓存过期时间
Cache-Control: max-age=256                              # 缓存最大时间(s)
Content-Type: text/html
Content-Length: 22
ETag: "605b4fb9-16"
Accept-Ranges: bytes

2.9.2 设置反向代理缓存

http {
    ...

    # 设置缓存保存路径,如果该路径不存在会自动创建
    # keys_zone指定了一个共享空间,初始大小是5m
    # max_size指定了共享空间的最大大小,由服务器硬盘空间决定
    # inactive指定了缓存的保存时长,超时后会将共享空间中的缓存数据情况
    # use_temp_path是否使用临时目录,开启可能会对Nginx性能产生影响
    proxy_cache_path /usr/local/nginx/cache keys_zone=nginxCache:5m max_size=1g inactive=8h use_temp_path=off;

    server {
        ...

        # 该虚拟主机开启使用缓存
        proxy_cache nginxCache;
        # 对200和304状态码的缓存设置过期时间
        proxy_cache_valid 200 304 16h;

        location / {}
    }
}

2.10 Nginx配置SSL提供Https访问

如果不配置SSL,则无法通过https访问网站。

以阿里云为例:

  • 首先需要有一个域名,https协议是需要域名的,并且该域名需要备案。
  • 进入SSL证书,选择申请免费证书,免费证书只能对一级域名提供SSL服务?。
  • 申请证书并通过后将其下载到本地并解压,其中包含Apache、lls、Nginx、Tomcat,不同的服务器配置是不一样的。
  • Nginx目录中包含.crt文件和.key文件,将这两个文件上传到云服务器中Nginx的conf目录中(方便一点)。
  • 安装SSL模块:要在Nginx中配置https,就必须安装ssl模块——http_ssl_module

在Nginx的配置文件中将证书.crt及私钥.key与Nginx服务器绑定

# 个配置在阿里云中有配置样例,可以直接copy
#以下属性中,以ssl开头的属性表示与证书配置有关。

server {
    listen 443 ssl;
    #配置HTTPS的默认访问端口为443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    #如果您使用Nginx 1.15.0及以上版本,请使用listen 443 ssl代替listen 443和ssl on。
    server_name yourdomain.com; #需要将yourdomain.com替换成证书绑定的域名。
    root /usr/share/nginx/html;
    index index.html index.htm;
    ssl_certificate cert/cert-file-name.pem;    #需要将cert-file-name.pem替换成已上传的证书文件的名称。
    ssl_certificate_key cert/cert-file-name.key; #需要将cert-file-name.key替换成已上传的证书密钥文件的名称。
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    #表示使用的加密套件的类型。
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS协议的类型。
    ssl_prefer_server_ciphers on;
    location / {
        root /usr/share/nginx/html;  #站点目录。
        index index.html index.htm;
    }
}

# 可选:设置HTTP请求自动跳转HTTPS。

server {
    listen 80;
    server_name yourdomain.com; #需要将yourdomain.com替换成证书绑定的域名。
    # rewrite ^(.*)$ https://$host$1; #将所有HTTP请求通过rewrite指令重定向到HTTPS。
    # rewrite    ^      https://$host$request_uri?      permanent;  # rewrite 写法二
    return  ^(.*)$ https://$host$1; #将所有HTTP请求通过return指令重定向到HTTPS。推荐此种写法
    # return     301    https://$host$request_uri; #将所有HTTP请求通过return指令重定向到HTTPS。rerun写法二
#     location / {
         # 因为跳转了https这里的location等于没有配置,可以删除
#        index index.html index.htm;
#     }
}

2.11 nginx状态监控

server {
        listen 80;
        server_name localhost;
        location /nginx-status {
                stub_status     on;  # 开启状态模块
                access_log      off;
                }
}
名称 表示信息
Active connections 表示Nginx正在处理的活动连接数几个
server 表示Nginx启动到现在处理了几个连接
accepts 表示Nginx启动到现在成功创建几次握手
handled requests 表示处理请求几次
Reading 读取到客户端的 Header 信息数
Writing 返回给客户端 Header 信息数
Waiting 已经处理完正在等候下一次请求指令的驻留链接(开启keep-alive的情况下,这个值等于Active-(Reading+Writing))

2.12 Nginx 配置请求响应时间

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"'
                      '"$request_time" "$upstream_response_time"';     

(1)request_time
官网描述:request processing time in seconds with a milliseconds resolution; time elapsed between the first bytes were read from the client and the log write after the last bytes were sent to the client 。

指的就是从接受用户请求的第一个字节到发送完响应数据的时间,即包括接收请求数据时间、程序响应时间、输出
响应数据时间。

(2)upstream_response_time
官网描述:keeps times of responses obtained from upstream servers; times are kept in seconds with a milliseconds resolution. Several response times are separated by commas and colons like addresses in the $upstream_addr variable

是指从Nginx向后端(php-cgi)建立连接开始到接受完数据然后关闭连接为止的时间。

从上面的描述可以看出,$request_time肯定比$upstream_response_time值大,特别是使用POST方式传递参数时,因为Nginx会把request body缓存住,接受完毕后才会把数据一起发给后端。所以如果用户网络较差,或者传递数据较大时,$request_time会比$upstream_response_time大很多。

2.13 nginx配置访问权限

# 用户认证配置
# 安装httpd-tools
yum install -y httpd-tools

# 生成密码文件 htpasswd -bc /etc/nginx/.htpasswd root 123456

# 准备配置文件
server{
   listen 80;
   auth_basic             "accss_auth";  
   auth_basic_user_file   /etc/nginx/.htpasswd;
}

2.14 隐藏nginx版本号

2.14.1 方法一:修改配置文件方式

# vim etc/nginx/conf/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens off;                              #添加,关闭版本号
    ......
}
# 只能简单隐藏,懂nginx的人依然有办法看到真实版本号

2.14.2 方法二:修改源码文件,重新编译安装

2.14.2.1 修改源码版本信息

# vim /opt/nginx-1.19.0/src/core/nginx.h
#define NGINX_VERSION "1.1.1"                   #修改版本号
#define NGINX_VER "IIS" NGINX_VERSION           #修改服务器类型

2.14.2.2 重新编译安装

2.15.2.3 修改主配置文件

# vim /etc/nginx/conf/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens on;  #添加,打开版本号
    ......
}

# 重启服务查看版本号
# 推荐此方法改版本号,源码级别修改更彻底

示例:

# 基于多ip虚拟主机配置
# 基于多域名虚拟主机配置
# 基于多端口虚拟主机配置

三、Nginx日志处理

3.1 手动切割日志文件

/usr/local/nginx/sbin目录下创建cut_log.sh脚本文件,复制如下内容粘贴:

#!/bin/bash
LOG_PATH="/var/log/nginx/"
RECORD_TIME=$(date -d "yesterday" +%Y-%m-%d+%H:%M:%S)
# RECORD_TIME=$(date -d "yesterday" +%F_%T)
PID=/var/run/nginx/nginx.pid
mv ${LOG_PATH}/access.log ${LOG_PATH}/access.${RECORD_TIME}.log
mv ${LOG_PATH}/error.log ${LOG_PATH}/error.${RECORD_TIME}.log

#向Nginx主进程发送信号,用于重新打开日志文件
kill -USR1 `cat $PID`
# kill -USR1 $(cat $PID)

以后每次执行cut_log.sh文件就会对Nginx原有的access.logerror.log文件以时间为单位进行切割。

上面是个简单的示例,下面是一个完整脚本设计流程

脚本实现思路

1 定义日志要保存的天数SAVE_DAYS=7
2 重命名当天日志 mv ***.log ***_日期.log
3 重新打开nginx日志文件kill -USR1 nginx的PID进程文件
4 压缩已备份日志(节省空间)gzip ***_日期.log
5 清理保存天数之前的日志find 路径 -type f -mtime +几天前 | xargs rm -f

完整脚本如下

#!/bin/sh
#Command:/usr/nginx/nginx/tools/clearNginxLog.sh
#Execute time: 00:00:00
LOGS_PATH=/usr/nginx/logs/nginx

#nginx pid path
PID=/usr/nginx/nginx/nginx.pid

#nginx logs save days
SAVE_DAYS=7

#backup data format
TODAY=$(date -d 'today' +%Y-%m-%d)
CURRENTTIME=$(date -d 'today' +%Y-%m-%d-%H-%M-%S)

logfile=$LOGS_PATH/clearNginxLog_${TODAY}.log

echo "`date +%Y-%m-%d` `date +%H-%M-%S` Start run the shell $0." >> ${logfile}
echo "Security check start." >> ${logfile}
if [ $LOGS_PATH == "/" ] || [ $LOGS_PATH == "/etc" ] || [ $LOGS_PATH == "/opt" ] || [ $LOGS_PATH == "/usr" ];then
  echo "Nginx logs path is not right!!!" >> ${logfile}
  exit 1;
fi

if [ -z "$LOGS_PATH" ];then
  echo "Nginx logs path is null!!!" >> ${logfile} 
  exit 1;
fi

if [ -z "$SAVE_DAYS" ];then
  SAVE_DAYS=7
fi
echo "Security check success." >> ${logfile}

echo "Move and rename logs start."
if [ -f ${LOGS_PATH}/error_${TODAY}.log.gz ];then
  TODAY=$CURRENTTIME
fi

if [ -f ${LOGS_PATH}/access_${TODAY}.log.gz ];then
  TODAY=$CURRENTTIME
fi

if [ -f ${LOGS_PATH}/host.access_${TODAY}.log.gz ];then
  TODAY=$CURRENTTIME
fi
echo "Move and rename logs finished."

#bak log files
mv ${LOGS_PATH}/host.access.log ${LOGS_PATH}/host.access_${TODAY}.log
mv ${LOGS_PATH}/error.log ${LOGS_PATH}/error_${TODAY}.log
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${TODAY}.log

#RESTART nginx process open file pid
kill -USR1 `cat ${PID}`

#Compress xxx.log to xxx.log.gz and auto remove xxx.log
if [ -f "/usr/bin/gzip" ];then
  gzip ${LOGS_PATH}/host.access_${TODAY}.log
  gzip ${LOGS_PATH}/error_${TODAY}.log
  gzip ${LOGS_PATH}/access_${TODAY}.log
fi
echo "Move and rename logs success." >> ${logfile}

echo "Command: find ${LOGS_PATH} -type f -mtime +{SAVE_DAYS} | xargs rm -f" >> ${logfile}
echo "clear files:" >> ${logfile}
find ${LOGS_PATH} -type f -mtime +${SAVE_DAYS} -print >> ${logfile}
find ${LOGS_PATH} -type f -mtime +${SAVE_DAYS} | xargs rm -f

echo "`date +%Y-%m-%d` `date +%H-%M-%S` End run the shell $0." >> ${logfile}
exit 0

3.2 自动切割日志文件

在生产环境建议每天执行一次cut_log.sh脚本。

安装linux定时任务插件

yum install -y crontabs

crontab -e 编辑并添加一行新的任务,这里为了测试,指定的是每分钟执行一次。

*/1 * * * * /usr/local/nginx/sbin/cut_log.sh

常用定时任务指令

systemctl start crond           # 启动
systemctl stop crond            # 停止
systemctl restart crond         # 重启
crond reload                    # 重新载入配置
crontab -e                      # 编辑定时任务
crontab -l                      # 打印已有定时任务列表

3.3 crontab表达式

* * * * *                           
# 分别代表分、时、日、月、星期
# 范围分别是:
# 0-59 0-23 1-31 1-12 1-7
  • 每分钟执行
*/1 * * * *
  • 每天凌晨晚上23:59执行
59 23 * * *
  • 每天凌晨1:00执行
0 1 * * *