跳到主要内容

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地址加端口号形式。

以 / 结尾 表示绝对根路径

不以 / 结尾 表示相对路径

五、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;
}
}