开发笔记:Nginx的故事

目录

什么是Nginx?

什么是反向代理?

正向代理

反向代理

Nginx进程模型

进程模型的好处

worker抢占机制

修改Nginx工作进程数

Nginx事件模型

在Nginx的角度思考如何选择IO模型

IO复用模型 -> epoll

CPU亲和

零拷贝sendFile

动静分离

Nginx文件夹结构

Nginx配置文件结构

特殊配置介绍

关于location

Nginx控制浏览器缓存时间 => expires(浏览器缓存)

Nginx设置跨域

Nginx valid_referer 防盗链

Nginx设置Tomcat集群

反向代理的静态资源缓存在nginx服务器(也称代理缓存)

Nginx负载均衡

前置知识upstream

轮询

权重

IP Hash

URL Hash

最少连接数

Nginx日志

变量列表

Nginx和Lua

Lua


 

什么是Nginx?

    Nginx是一个高性能的HTTP服务器,它是一个高性能的Web和反向代理服务器由俄罗斯的程序设计师Igor Sysoev开发。Nginx在反向代理、Rewrite规则、稳定性、内存消耗等方面表现出很强的优势,选用Nginx代替传统的Apache服务器会获得很多方面的性能提升。(参考网上资料加以整理)。简而言之,Nginx是一款轻量级高性能且好用的HTTP服务器,在近几年被广泛使用,在使用量上有超越Apache的趋势。


什么是反向代理?

    Nginx是常用的反向代理服务器,那么什么是反向代理,反向代理和正向代理有什么区别,可能各位大哥都了解这个东西,但是如何清楚地描述它嘞?

正向代理

正向代理就是沿着你请求的方向进行代理,比如说你的目标网站是CSDN,直接去访问它访问不通,那么就可以找一个代理服务器帮助我们,通过代理服务器请求到CSDN的网站,这个代理服务器有可能是移动、电信或者联通的服务器。

反向代理

正向代理是代理服务器帮助你访问到你想要访问的目标网站上,但是不考虑细节,比如说具体访问到那个IP地址的服务器提供的服务,而这个部分就是由反向代理来实现,可能文字描述比较迷,可以通过下图理解:

开发笔记:Nginx的故事_第1张图片

上图就是使用反向代理来实现路由的一个例子,请求来到Nginx服务器,通过Nginx服务器来决定访问到那个IP地址的服务器上,这就是反向代理。通过反向代理还可以实现负载均衡等功能,比如根据权重分发请求到不同的集群服务器上。


Nginx进程模型

Nginx在启动后会有一个master进程和一个或多个worker进程。

  • master进程为进程:管理worker进程,接收来自外界的信号,想工作进程发送信号,也就是给工作进程分配工作。master还会监听worker的运行状态,如果worker发生了什么异常退出了,master会重新启动一个worker。
  • worker进程为工作进程

开发笔记:Nginx的故事_第2张图片

管理员发出stop等命令,master会传递给worker,若worker连接了客户端会等待其释放连接后执行停止。

进程模型的好处

采用进程模型而不是线程,其好处是进程间相互独立,互不影响,如果一个worker除了一些问题不会影响到其他的进程。

 

worker抢占机制

worker的具体抢占机制如下:

开发笔记:Nginx的故事_第3张图片

 

如何修改Nginx工作进程数

修改下图中红框的配置即可,比如说我们想将其改为1个,就设置为worker_processes 1;即可

开发笔记:Nginx的故事_第4张图片


Nginx事件模型

了解了Nginx进程模型后,Nginx采用进程而不是线程,相互独立的同时,可能就出现这样的疑问=>进程模型去处理的话并发性不就很差?

对于这个问题就不得不提到Nginx事件模型。

Linux下Nginx采用的是epoll多路复用IO模型

在Nginx的角度思考如何选择IO模型

相比大家都了解,如果我们使用阻塞的IO模型,也就是一个进程处理一个请求,当请求发生阻塞,进程会在那里等待,再多来一个请求,我们的系统就需要多fork一个进程,这样当请求量一上来,我们需要的进程数量是一个非常大的数字,这样系统吃不消。

所以从Nginx的角度看,阻塞的IO模型是不可取的,因为它的目标是一个能够支持高并发的服务器。那么我们就要思考如何让一个进程能够处理多个请求,这就需要说到IO复用模型。

IO复用模型 -> epoll

什么是IO复用模型,关于五种IO模型本人在这篇博客有介绍过:https://blog.csdn.net/qq_36652619/article/details/102996683

这里再介绍一次IO复用模型

用本狗子以前介绍Socket与IO模型的图来讲解一下大致的结构:

开发笔记:Nginx的故事_第5张图片

其大致的思路就是一开始会创建一个监听,循环监听所有的IO是否有可读的数据,如果有的话,就将数据读取,这个思路的伪代码如下:

while true{
    for i in steam[]{
        if i has data{
            read until unavailable
        }
    }    
}

这种模式的话就是IO复用模型,会不断地轮询查看是否有数据,这样的话其实有一定的缺陷:

当所有的IO流都没有数据的话,我们的CPU就一直在白干,一直轮询

所以就引出了IO复用的几种模型比如说select模型:

while true{
    //只有有数据的时候才会轮询
    select(stream[]){
        for i in steam[]{
            if i has data{
                read until unavailable
            }
        }  
    }  
}

select模型解决了上面的白干的缺陷,但是select模型有一个文件句柄的限制,而epoll模型解决了这个限制,同时epoll模型最大的优势体现在callback事件回调的机制优化,也就是当流可读会事件回调,那么这样较大的提高了效率。

所以Nginx中采用的就是这样的epoll模型,一个进程可以处理大量请求。

所以通过epoll的模式让Nginx能够高并发。


CPU亲和

将CPU核心和Nginx工作进程绑定,让每个worker进程在一个cpu上执行,减少cpu的缓存损失加强性能。

开发笔记:Nginx的故事_第6张图片

Nginx进程和核心的匹配(除了下面那种方法还可以手动配置):

worker_cpu_affinity auto;

零拷贝sendFile

传统的HTTP服务器传输文件的过程如下:

开发笔记:Nginx的故事_第7张图片

文件会经过内核空间切换到用户空间再到内核空间传递到socket,而nginx的零拷贝的过程如下:

开发笔记:Nginx的故事_第8张图片

减少了内核空间和用户空间之间的切换,提高了文件传输的效率。

动静分离

所以有了这个优点之后很多用Nginx做动静分离的场景。

动静分离比较常见,所以这里就放一个流程图,其实就是将静态资源和静态资源分离开。

开发笔记:Nginx的故事_第9张图片

 


Nginx文件夹结构

nginx

-------------------- CHANGES     //版本更新的内容,跟王者荣耀的更新通知差不多,记录每个版本修改了什么

-------------------- conf                //配置文件的文件夹

-------------------- configure        //用来编译和配置

-------------------- contrib            //一些工具文件夹

-------------------- html                 //默认存放的静态文件,安装完会拷到指定目录

-------------------- LICENSE        //说明

---------------------Makefile          //通过makefile文件来描述源程序之间的相互关系并自动维护编译工作,本质上makefile文件是个文本文件,用于配置编译过程。

---------------------man                //一些手则

---------------------objs                //里面有很多模块,也包含第三方的模块

---------------------README

---------------------src                 //nginx的源码


Nginx配置文件结构

Nginx的配置文件nginx.conf的内部结构是这样的:

开发笔记:Nginx的故事_第10张图片

特殊配置介绍

1. tcp_nopush

开启了sendfile之后可以开启tcp_nopush,指当数据表累积一定大小后才发送,提高效率。

sendfile    on;
tcp_nopush  on;

2. 设置客户端与服务端请求的超时时间,减少资源损耗。

keepalive_timeout   65;

3. 开启压缩,让html/js/css压缩后快速传输

gzip  on;
# 小于1024字节的文件不会压缩
gzip_min_length  1024;
# 压缩比,范围:1-9,压缩比越大占用CPU越大
gzip_comp_level  5;
# 要压缩的类型
gzip_types  text/plain application/javascript application/x-javascript text/javascript text/xml text/css;

4. worker进程工作数设置,设置为cpu的数目,设置方法上文介绍了

 

关于location

location是路径匹配规则,可以看成是路由映射

# 默认模式可以访问指定文件夹下的文件
location / {

}

# 精准匹配,精准的匹配到某个文件
location / = {

}

# ~^表示以某个路径作为前缀
location ~^ /pre/img/ {
    root /home;
}

# 正则表达式
# *表示不区分大小写
location ~* \.(JPG|png) {
    root /home;
    index index.html index.htm
}

Nginx控制浏览器缓存时间 => expires(浏览器缓存)

通过设置expires可以控制静态资源的缓存时间。但是静态资源发生变动的话,会重新去请求

location / {
    root /home/static;

    expires 30s;
}

 


Nginx设置跨域

#允许跨域请求的域,*代表所有
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' *;

这里注意一个问题,就是Nginx和SpringMVC本身都配置了跨域会报错,具体看本人这篇:https://blog.csdn.net/qq_36652619/article/details/89377196


Nginx valid_referer 防盗链

location ~* \.(JPG|png) {
    # 如果来自*.domain.com会继续往下走,如果不是的话会返回403
    valid_referers *.domain.com;
    if ($invalid_referer) {
        return 403;
    }
    root /home;
}

Nginx设置Tomcat集群

其实这个很简单,大家可能都玩过,设置两台Tomcat集群,其结构图如下:

开发笔记:Nginx的故事_第11张图片

nginx.conf:

upstream www.mydomain.com {
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

反向代理的静态资源缓存在nginx服务器(也称代理缓存)

upstream www.mydomain.com {
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

# 路径代表缓存的路径
# keys_zone 设置共享内存以及占用空间大小
# inactive 超过此时间则被清理
# max_size 设置硬盘中最多可以缓存多少数据,当到达该数值时,nginx会删除最少访问的数据。
proxy_cache_path /test/cache/ keys_zone=my_zone:10m inactive=12h max_size=5g;

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
        # 使用缓存
        proxy_cache my_zone;
    }
}

ps:三种缓存=>

开发笔记:Nginx的故事_第12张图片

 

Nginx负载均衡

有集群必有负载均衡,Nginx有几种负载均衡的模式。

前置知识upstream

文档:http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#upstream

max_conns

每台服务器的最大连接数,设置可以避免连接数过大

upstream www.mydomain.com {
    server 192.168.1.11:8080 max_conns=10000;
    server 192.168.1.12:8080 max_conns=1000;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

down

这个参数来标记服务器不可用

upstream www.mydomain.com {
    server 192.168.1.11:8080 down;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

backup

开发笔记:Nginx的故事_第13张图片

将服务器标记为备份服务器。当其他服务器宕机的时候会加入集群

upstream www.mydomain.com {
    server 192.168.1.11:8080 backup;
    server 192.168.1.12:8080;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

max_fails和fail_timeout

开发笔记:Nginx的故事_第14张图片

开发笔记:Nginx的故事_第15张图片

上面这段说明,在fail_timeout设置的时间内,出现了max_fails次请求失败,则在这段时间内视为服务器不可用,请求会打到正常的服务器。默认是十秒。

upstream www.mydomain.com {
    server 192.168.1.11:8080 max_fails=3 fail_timeout=10s;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

keepalive

将一些连接保持为长连接,减少新增和销毁的开销,多个连接公用一个长连接,提高性能,

关于长连接:

  • 同步方式下客户端所有请求共用同一连接,在获得连接后要对连接加锁,在读写结束后才解锁释放连接,性能低下,基本很少采用,唯一优点是实现极其简单。
  • 异步方式下所有请求都带有消息ID,因此可以批量发送请求,异步接收回复,所有请求和回复的消息都共享同一连接,信道得到最大化利用,因此吞吐量最大。
upstream www.mydomain.com {
    server 192.168.1.11:8080 max_fails=3 fail_timeout=10s;
    server 192.168.1.12:8080;
    keepalive 50;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
        proxy_http_version 1.1;                         # 设置http版本为1.1
        proxy_set_header Connection "";
    }
}

 

轮询

轮询的思想其实特别简单,就口头描述了,比如说我们上面做了两个Tomcat集群,第一个请求给第一个Tomcat,第二个请求给第二个Tomcat,第三个请求给第一个Tomcat,第四个请求给第二个Tomcat,以此类推。

这种就是Nginx默认的形式,这种形式一般适用于,所有的集群服务器都是同样配置的,因为每个Tomcat分配到的请求是一样的。

 

权重

权重的方式其实也比较好理解,字面意思,两台服务器,根据每台服务器的配置高低分配不同的权重,比如说现在有三个请求,一台2核4G的服务器一台4核8G的服务器,那么让其中两个请求打到4核8G的服务器上,另外一个请求打到2核4G的服务器,这样的形式就是权重的方式。

按照上述例子的配置方法:(其中weight默认是1)

upstream www.mydomain.com {
    server 192.168.1.11:8080 weight=2;
    server 192.168.1.12:8080 weight=1;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

 

IP Hash

这是通过IP进行哈希的方式来负载均衡,用户请求过来的IP的网络号去进行一个哈希算法然后达到对应的服务器上面,如果请求的网络号一样,那么会打到同一台服务器上,也就是会访问到同样的服务器,访问到同样的缓存。弊端的话其实它有可能不均匀,某些网络号的请求量大,某些小。

配置方法如下:

upstream www.mydomain.com {
    ip_hash;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

 

URL Hash

通过用户请求的url进行哈希,同样的url会哈希到同一台服务器,这种可以做不同服务访问到不同的服务器上。

配置方法:

upstream www.mydomain.com {
    hash $request_uri;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

 

最少连接数

看那台服务器的连接数少,就请求到哪台服务器上面。

upstream www.mydomain.com {
    least_conn;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

server {
    listen            80;
    server_name       www.mydomain.com

    location / {
        proxy_pass    http://www.mydomain.com;
    }
}

 


Nginx日志

nginx的日志如下:

  • access.log:访问日志
  • error.log:根据不同级别记录错误日志比如说错误运行日志请求日志

Nginx通过log_format将需要的信息输出到日志中去,

nginx.conf:

开发笔记:Nginx的故事_第16张图片

变量列表

$remote_addr:客户端(用户)IP地址 
$time_local:访问时间
$request:get请求的url地址(目标url地址)的host
'$status:http状态码
$body_bytes_sent:请求页面大小
$http_referer: 来源页面,即从哪个页面转到本页
$http_user_agent:用户浏览器其他信息,浏览器版本、浏览器类型
$http_x_forwarded_for:请求中的X-Forwarded-For信息

另外,http的头信息可以通过$http_加上参数名字,其中大写改小写,横杠改成下划线例如:$http_user_agent

还有很多nginx的变量可以去官方文档查找。


Nginx和Lua

这里仅做科普,不详细讲解Lua的开发与应用

Lua

一个轻量级的可扩展脚本语言。一些功能可以通过几行代码实现,常用于埋点统计比如用户IP、访问等信息,运行上也很轻量。结合Nginx和Lua可以提高并发,因为Nginx能够接受大量的请求,恰好和Lua的轻量搭配。在秒杀系统中也有使用Lua作限流的一种方式。

 

你可能感兴趣的:(开发笔记:Nginx的故事)