跳到主要内容

Nginx

一、什么是 nginx​

Nginx 是一个免费的,开源的,高性能的 HTTP 服务器和反向代理,以及 IMAP/POP3 代理服务器。Nginx 以其高性能,稳定性,丰富的功能,简单的配置和低资源消耗而闻名。

二、优点(高性能、高并发、低内存)​

更快

传统的基于进程或线程处理并发连接的模型,使用单独进程或线程来处理每一个请求,并阻塞网络或输入输出。

nginx 是一个模块化的、事件驱动的、异步的、单线程的、非阻塞的架构。

nginx 大量使用多路复用和事件通知,并将特定任务专门用于分离进程。在数量有限的单线程中,高效运行循环中处理连接。

高扩展性(模块化)

高度模块化的设计是 Nginx 的架构基础。

高可靠性

Nginx 可以在服务器上持续不间断的运行数年。

热部署

在升级的时候不需要终止服务

BSD 许可证

开源免费,修改源码之后可进行商用。

三、Nginx 架构​

四、Nginx 命令与配置文件​

4.1、安装​

yum install -y nginx

安装之后查看 nginx 的安装位置

whereis nginx

查看 nginx 进程

ps -ef | grep nginx  # 能够看到一个 master 进程多个 worker 进程

master 进程的作用:master 进程主要用来管理监控 worker 进程,包含接收外界的信息,并将接收到的信号发送给各个 worker 进程,监控 worker 进程的状态,当 worker 进程出现异常退出后,会自动重新启动新的 worker 进程。还负责读取配置文件,判断配置文件语法是否真确。

worker 进程作用:专门用来处理用户请求的,各个 worker 进程之间是平等的并且相互独立,处理请求的机会也是一样的。

我们可以通过给 master 进程发送信号量来控制 nginx 来进行启停操作。

那么如何获取 master 进程的 pid 呢?

  • ps -ef | grep nginx
  • 在 nginx.pid 文件存放着 master 进程的 pid

信号量(kill 信号量 pid)

信号量

  • TERM,INF

nginx 立即关闭

  • QUIT

master 进程控制所有的 worker 进程不在接受新的请求,等所有请求处理完成之后再关闭 nginx

  • HUP

master 进程会把控制旧的 work 进程不再接收新的请求,等处理完请求后将旧的 work 进程关闭掉,然后根据 nginx 的配置文件重新启动新的 work 进程

  • USR1

告诉 Nginx 重新开启日志文

  • USR2 (平滑的升级)

告诉 master 进程要平滑升级,这个时候,会重新开启对应的 master 进程和 work 进程,整个系统中将会有两个 master 进程,并且新的 master 进程的 PID 会被记录在/usr/local/nginx/logs /nginx.pid 而之前的旧的 master 进程 PID 会被记录在 /usr/local/nginx/logs/nginx.pid.oldbin 文件中,接着再次发送 QUIT 信号给旧的 master 进程,让其处理完请求后再进行关闭

  • WINCH

(优雅关闭旧的进程)发送 WINCH 信号给 master 进程,让 master 进程控制不让所有的 work 进程在接收新的请求了,请求处理完后关闭 work 进程。注意 master 进程不会被关闭掉

4.2、nginx 应用程序命令​

nginx -s reload # 重新加载配置文件,热重启 HUP

nginx -s reopen # 重启 Nginx USR1

nginx -s stop # 快速关闭 TERM、INT

nginx -s quit # 等待工作进程处理完成后关闭 QUIT

nginx -T # 查看当前 Nginx 最终的配置

nginx -t # 检查配置是否有问题

4.3、配置文件结构​

将默认配置文件 nginx.conf 去掉注释

user nginx;

worker_processes 1;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;

server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

配置指令(key)、配置指令值(value)、配置指令语句、配置指令域({})、配置全局域

发现 默认配置文件中有三大块,全局块,events 块,http{ server { location}} 块。

main、events、http、upstream、server、location、stream、types、if

配置文件中的计量单位

1) 容量

k、K、m、M、g、G

2)时间

ms、s、m、h、d、w、M、y

4.4、全局块​

user :用于配置运行 Nginx 服务器的 worker 进程的用户和用户组,用于设置 master 进程启动后,fork 出的 worker 进程运行在哪个用户和用户组下。当按照 “user username” 设置时,用户组名与用户名相同。

master_process on|off; 用来指定是否开启工作进程。

worker_process num/auto; 用于配置 Nginx 生成工作进程的数量,这个是 Nginx 服务器实现并发处理服务的关键所在。理论上来说 worker process 的值越大,可以支持的并发处理量也越多,但事实上这个值的设定是需要受到来自服务器自身的限制,建议将该值和服务器 CPU 的内核数保存一致

daemon:设定 Nginx 是否以守护进程的方式启动。(独立于控制终端,不会随着终端关闭而停止)

pid:用来配置 Nginx 当前 master 进程的进程号 ID 存储的文件路径。

error_log:用来配置 Nginx 的错误日志存放路径

include:用来引入其他配置文件,使 Nginx 的配置更加灵活

4.5、Events 块​

accept_mutex 来设置 Nginx 网络连接序列化

multi_accept:用来设置是否允许同时接收多个网络连接

worker_connections:用来配置单个 worker 进程最大的连接

use:用来设置 Nginx 服务器选择哪种事件驱动来处理网络消息。

4.6、http 块​

default_type:用来配置 Nginx 响应前端请求默认的 MIME 类型

access.log:用来记录用户所有的访问请求。

error.log:记录 nginx 本身运行时的错误信息,不会记录用户的访问请求。

log_format:用来指定日志的输出格式

sendfile:用来设置 Nginx 服务器是否使用 sendfile()传输文件,该属
性可以大大提高 Nginx 处理静态资源的性能

keepalive_timeout:用来设置长连接的超时时间。

keepalive_requests:用来设置一个 keep-alive 连接使用的次数。

4.7、Server 块​

listen:用来配置监听端口

server_name 指令:用来设置虚拟主机服务名称

域名匹配的四种写法:

匹配优先级:精确匹配 > 左侧通配符匹配 > 右侧通配符匹配 > 正则表达式匹配 > default_server

通配符不能出现在域名的中间,只能出现在首段或尾端。

~ 作为正则表达式字符串开始标记。

4.8、location 块​

location 语法

location [ = | ~ | ~* | ^~ ] /URI { … }
location @/name/ { … }

location : 用来设置请求的 URI

location /abc {} # uri 必须以 /abc 开头

location =/abc {} # 精准匹配,/abc /abc?name=wanghzy 可以 /abc/ /abcdef 不行

location ~ {} # ~ 表示正则匹配区,分大小写。 ~* 正则匹配忽略大小写

location ^~ {} # 用于不包含正则表达式的 uri 前,模式匹配,停止搜索其他模式

4.9、 root、alias​

root:设置请求的根目录

alias:用来更改 location 的 URI

以上两个指令都可以来指定访问资源的路径。

# 图片放在 /usr/local/nginx/html/images/logo.png;
location /images {
root /usr/local/nginx/html;
}

location /images {
alias /usr/local/nginx/html; # 通过 /images/logo.png 访问不到图片,需要将 alias 修改为 /usr/local/nginx/html/images;
# alias /usr/local/nginx/html/images;
}

root 和 alias 的区别

root 的处理结果:root 路径 + location 路径

alias 的处理结果:使用 alias 路径替换 location 路径

alias 是一个目录别名的定义,root 则是最上层目录的含义。

如果 location 路径是以 / 结尾,则 alias 也必须是以 / 结尾,root 没有要求。

index 指令:设置网站的默认首页。 index 后面可以跟多个设置,如果访问的时候没有指定具体访问的资源,则会依次进行查找,找到第一个为止。

erroe_page 指令:设置网站的错误页面。出现对应的响应 code 后,如何来处理。

# 指定具体跳转的地址
server {
error_page 404 https://www.baidu.com;
}
server {
error_page 404 /50x.html;
error_page 500 502 503 504 /50x.html;
location =/50x.html{
root html;
}
}
#使用 location 的@符合完成错误信息展示
server{
error_page 404 @jump_to_error;
location @jump_to_error {
default_type text/plain;
return 404 'Not Found Page...';
}
}
#可选项=[response] 的作用是用来将相应代码更改为另外一个,此时前台的响应的状态码为 200
server{
error_page 404 =200 /50x.html;
location =/50x.html{
root html;
}
}

4.10、rewrite​

rewrite 是 Nginx 的一个指令,用于基于正则表达式匹配的结果来修改和重定向 URL。

set 指令 : 该指令用来设置一个新的变量。该变量名称要用"$"作为变量的第一个字符。

if 指令:该指令用来支持条件判断,并根据条件判断结果选择不同的 Nginx 配置。

空值或者 “0” 为 false,其余为 true

=、!= 笔记字符串是否相等。 字符串不需要加引号,等号前后加空格。

可以使用正则表达式匹配字符串

~

~*

!、!*

文件是否存在 -f 、 !-f

目录是否存在 -d 、 !-d

文件是否可执行 -x 、 !-x

break 指令:break 前面生效,后面不生效

return 指令:于完成对请求的处理,直接向客户端返回

rewrite 指令:通过正则表达式来改变 URI rewrite regex replacement [flag];

last: 终止继续在本 location 块中处理接收到的 URI,并将此处重写的 URI 作为一个新的 URI,使用各 location 块进行处理。该标志将重写后的 URI 重写在 server 块中执行,为重写后的 URI 提供了转入到其他 location 块的机会

break:将此处重写的 URI 作为一个新的 URI,在本块中继续进行处理。该标志将重写后的地址在当前的 location 块中执行,不会将新的 URI 转向其他的 location 块。

redirect:将重写后的 URI 返回给客户端,状态码为 302,指明是临时重定向 URI,主要用在 replacement 变量不是以"http://"或者" https://" 开头的情况

permanent:将重写后的 URI 返回给客户端,状态码为 301,指明是永久重定向 URI,主要用在 replacement 变量不是以"http://"或者" https://" 开头的情况

4.11、反向代理​

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

以 / 结尾 表示绝对根路径

不以 / 结尾 表示相对路径

4.12、map 指令​

nginx 的 map 指令的作用是: 基于一个变量的值创建新变量.

# 定义协议转发策略
map $http_x_forwarded_proto $final_scheme {
default $scheme; # 如果上游没传,使用当前协议
"" $scheme; # 空值时使用当前协议
"~.+" $http_x_forwarded_proto; # 有值时使用上游传来的值
}

上面的案例中 $http_x_forwarded_proto 就是源变量, $final_scheme 就是新变量的名称.

default $scheme; 表示, 如果下面的匹配规则没有匹配到(用 $http_x_forwarded_proto 的值来进行匹配),就使用 $scheme 的值作为 $final_scheme 的值.

map 的匹配模式

  1. 字面量. 直接匹配,优先级最高, 如 "http" "abcxz" 表示, 如果 $http_x_forwarded_proto 的值是 http, 则将 $final_scheme 的值设置为 abczx
  2. 掩码(前缀/后缀), 如 *.example.com 或 mail.* 注意, * 不能出现在中间.
  3. 正则表达式
    • ~ 区分大小写
    • ~* 不区分大小写
    • () 目标组捕获, 如 ~^/images/(.*)$, 捕获的内容会被存储到 $1, $2 等变量中
  4. default, 优先级最低, 当上面的匹配模式匹配不到时,使用 default 来进行兜底

五、nginx 能干什么(负载均衡、缓存、访问和带宽控制)​

5.1、热部署​

什么是热部署?​

热部署就是在应用正在运行的时候升级软件,却不需要重新启动应用。

nginx 是如何实现热部署的?​

我们知道 Nginx 中的进程分为 master 进程,worker 进程。其中 master 进程是用来管理监控 worker 进程的主进程。这个进程是由 root 发起。原因是 http 这个服务需要启用 80 端口,而只有 root 才有权限启用 80 端口。

worker 进程才是真正处理请求的进程。是以 use 指令配置的用户去执行的。

当使用 nginx -s reload 重新加载配置文件的时候,master 进程会对配置文件进行语法检查,如果存在语法错误,则返回错误,不进行装载。如果配置文件没有语法错误,那么 nginx 也不会将新的配置加载到现有的 worker 进程中。而是,先不改变已经建立连接的 worker 进程,等待 worker 将所有请求结束之后,将原先在旧配置下启动的 worker 进程杀死,然后使用新的配置创建新的 worker。

nginx 实现热部署的步骤。

1、备份旧版本的二进制文件

2、编译新的二进制文件,并替换原来的二进制文件

3、给旧 master 进程发送 USR2 信号,使 nginx 停止接收请求,用新版本接替 kill -USR2 pid;

4、关掉旧 worker 进程 kill -WINCH pid;

5、关掉旧 master 进程 kill -QUIT pid;

5.2、反向代理​

什么是正向代理和反向代理?​

正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器) ,然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。

反向代理:反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器, 即用户直接访问反向代理服务器就可以获得目标服务器的资源。 同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为 Web 加速,即使用反向代理作为 Web 服务器的前置机来降低网络和服务器的负载,提高访问效率。

示例:服务器端

被代理服务器

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

代理服务器(nginx)

server {
listen 8082;
server_name localhost;
location /server1{
proxy_pass http://xxxx:9001/;
}
location /server2{
proxy_pass http://xxxx:9002/;
}
location /server3{
proxy_pass http://xxxx:9003/;
}
}

5.3、负载均衡​

负载均衡的优点:通过某种负载分担技术,让所有节点以最小的代价、最好的状态对外提供服务,快速获取重要数据,最大化降低了单个节点过载、甚至 crash 的概率,解决大量并发访问服务问题,简要概括就是:解决并发压力,提高应用处理性能;提供故障转移,实现高可用;通过添加或减少服务器数量,提供网站伸缩性;安全防护。

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

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

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

状态

概述

down

将该服务器标记为永久不可用,当前的 server 暂时不参与负载均衡

backup

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

max_fails

允许请求失败的次数

fail_timeout

经过 max_fails 失败后, 服务暂停时间

max_conns

用来设置代理服务器同时活动链接的最大数量

负载均衡策略

算法名称

说明

轮询

默认方式

weight

权重方式

upstream backend{
server 192.168.200.146:9001 weight=10;
server 192.168.200.146:9002 weight=5;
server 192.168.200.146:9003 weight=3;
}

ip_hash

依据 ip 分配方式

upstream backend{
ip_hash;
server 192.168.200.146:9001 weight=10;
server 192.168.200.146:9002 weight=5;
server 192.168.200.146:9003 weight=3;
}

least_conn

依据最少连接方式

upstream backend{
least_conn;
server 192.168.200.146:9001 weight=10;
server 192.168.200.146:9002 weight=5;
server 192.168.200.146:9003 weight=3;
}

url_hash

依据 URL 分配方式

fair

依据响应时间方式

5.4、动静分离​

什么是动静分离?​

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

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

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

为什么要动静分离?​

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

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

如何实现动静分离?

upstream webservice{
server 192.168.200.146:8080;
}
server {
listen 80;
server_name localhost;
#动态资源
location /demo {
proxy_pass http://webservice;
}
# 静态资源
location ~/.*\.(png|jpg|gif|js){
root html/web;
gzip on;
}
location / {
root html/web;
index index.html index.htm;
}
}

六、常见问题​

6.1、nginx: [warn] conflicting server name "xxxx" on 0.0.0.0:443, ignored​

问题原因:意重复绑定了 server name,但这个警告不会影响到服务器运行。

解决方法:把 include 引入的文件中,server_name 改成不重复即可。

6.2、源码安装​

./configure \
--prefix=/usr/local/nginx \
--conf-path=/etc/nginx/nginx.conf \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_auth_request_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_degradation_module \
--with-http_slice_module \
--with-http_stub_status_module \
--with-mail_ssl_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-stream_ssl_preread_module

make && make install

6.3、跨域问题​

location / {
# 允许跨域的请求,可以自定义变量$http_origin,*表示所有
add_header 'Access-Control-Allow-Origin' *;
# 允许携带 cookie 请求
add_header 'Access-Control-Allow-Credentials' 'true';
# 允许跨域请求的方法:GET,POST,OPTIONS,PUT
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT';
# 允许请求时携带的头部信息,*表示所有
add_header 'Access-Control-Allow-Headers' *;
# 允许发送按段获取资源的请求
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
# 一定要有!!!否则 Post 请求无法进行跨域!
# 在发送 Post 跨域请求前,会以 Options 方式发送预检请求,服务器接受时才会正式请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
# 对于 Options 方式的请求返回204,表示接受跨域请求
return 204;
}
}

七、nginx 内置参数​

  • $remote_addr 客户端的 IP 地址(TCP 连接的源 IP)
  • $proxy_add_x_forwarded_for 在现有的 X-Forwarded-For 头部基础上追加 $remote_addr
  • $scheme 请求的协议, http/https
  • $host 请求的主机名, Host 请求头
http {
map $http_x_forwarded_proto $final_scheme {
"" $scheme; # $http_x_forwarded_proto 为空时使用 $scheme 的值
"~.+" $http_x_forwarded_proto; # 非空时,使用 $http_x_forwarded_proto 的值
default $scheme; # 默认值
}
servel {
listen: 11111;
server_name example.com;

location / {
# X-Real-IP 记录的是请求当前 nginx 的 ip
proxy_set_header X-Real-IP $remote_addr;
# X-Forwarded-For 请求头记录的是多层代理 IP 链,格式是<原始客户端 IP,代理 1 IP,代理 2 IP,....>
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# X-Forwarded-Proto 请求头记录的是客户端请求所使用的协议
proxy_set_header X-Forwarded-Proto $final_scheme;
# Host 请求头记录的是请求当前 nginx 所使用的 host
proxy_set_header Host $host;
}
}
}