0%

Nginx使用及原理

本文主要解释nginx.conf如何配置,和为什么这样配置。

一、基本概念

1、HTTP代理和反向代理

先不说教科书上的文绉绉的字段,我也记不住。

我只说的我的理解:代理,相当于一个中间层,将服务的提供者和服务的使用者隔开。

  • 服务提供者将服务(可以理解成数据)传送给代理服务器,但是不知道谁去使用该服务,这叫做正向代理
  • 服务使用者从代理服务器获取服务(数据),但不知道真正是哪台服务器提供的服务,这叫反向代理

举个例子:如果小明去食堂吃饭,服务员端来饭菜,小明不知道这个菜是哪位厨师做的,这叫反向代理。厨师将饭菜做好后给服务员,但不知道谁去吃,这叫正向代理。

那么为什么要用代理呢?

我的理解主要有:

  • 一是,可以屏蔽某一方,用于保密;
  • 二是,将服务单一化、统一化,方便使用;
  • 三是,对于公共的一些处理,我们可以在代理服务器上统一处理。
2、负载均衡

负载均衡,可以有两个方面的含义:

  • 一方面,是将单一的重负载分担到多个网络节点上做并行处理,节点将任务处理完毕后汇总返回,这样提高网络系统的处理能力。我感觉,Elasticsearch这种搜索引擎就是采用这种”分而治之”思想。但是这种问题,需要能够划分成子问题。
  • 另一方面,将大量前端并发访问分担到后端各个服务器节点上分别处理,这样可以有效减少前端用户的等待时间,减轻单机压力。Nginx服务器就是这种。

Nginx服务器的负载均衡策略有很多,可以分为两个部分:

  • 内置策略:包括轮询、加权轮询、IP Hash。
  • 扩展策略:是指第三方模块实现的策略,有url hash,包括我在使用的sticky策略。
3、Web缓存

作为前置的服务器,可以缓存前端请求,将页面静态文件等资源缓存,从而提高性能。

二、配置文件的基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
work_process 1;

events{
worker_connections 10240;
}

http{
include mine.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 60;
server{
listen 80;
server_name localhost;
location / {
root html;
index index.html
}
}
}

上述配置文件中,将配置文件的骨架抽离出来了。
所有的配置和编程语言一样,括号外面的全局生效,里面的在{}范围内生效,出现冲突,也遵循就近原则。
整体上可以看成:

1
2
3
4
5
6
7
8
--nginx.conf
--全局块
--events块
--http块
--http全局块
--server块1
--server块2
--server块n
1、全局块:

影响全局,比如work_process指的是nginx可以生成几个进程共同处理请求。官方文档建议是1个,但是出于性能考虑,我认为和计算机的CPU核数相同就好。

1
worker_process 2;     #存在2个work进程处理请求
2、events块

影响Nginx服务器与用户的网络连接。

常用的设置有:

  • 是否对多个worker process序列化

    网络中有种现象叫做“惊群”,该问题产生于,当有个网络连接到来时,多个睡眠等待进程会被同时叫醒。但是,只有一个进程获得连接。如果每次叫醒的进程过多,对资源是一种浪费。

处理方案:将接受连接的进程进行序列化,避免争抢。配置如下:

1
accept_mutex on|off;
  • 是否允许接受多个网络连接

    每个 work process是否接受多个连接,配置如下:

1
multi_accept on|off;
  • 选取哪一种事件驱动模型处理连接请求

    将每个消息看成一个事件,当消息来临时。采用什么样的方式处理该事件。有select、poll和epoll等方式。配置如下:

1
use method;
  • 每个work process可以同时支持的最大连接数目
1
worker_connections 512;
3、http块

重要部分!代理、缓存、日志定义等绝大多数功能都在其中。

  • 文件引入、MIME-TYPE定义。
    用于Nginx区分资源,比如HTML、XML、GIF等,打开mime.types文件可以看到对应的定义。
1
2
include         mime.types
default_type application/octet-stream #处理类型
  • 日志自定义。

    1
    access_log path [format[buffer=size]]
  • 是否使用sendfile传输文件。

    1
    2
    sendfile            on|off  #是否开启
    sendfile_max_chunk size #chunk的大小,nginx每次调用sendfile()传输大小不超过这个值
  • 连接超时时间。nginx与前端保持连接的时间。

    1
    keepalive_timeout timeout[header_timeout]
  • 单连接请求数上限。通过某一连接发送的次数,默认100

    1
    keepalive_requests number;
4、server块

server块 代表虚拟主机的概念。目的是节约硬件成本,用一台主机对外可以表现出多个机器的感觉。

每个server块 就相当于一台虚拟主机。

  • 配置监听
    1
    2
    listen 80;
    server_name ip|域名;
5、location块

其实是server块中的一个命令,用来匹配请求,然后对该请求进行重写、转发等功能。正则匹配url后进行处理。

1
2
3
location / {
proxy_pass http://defaultServer ; #将请求分发给defaultServer
}

三、Nginx服务器事件驱动模型

记得有一次面试,面试官是网易金融的架构师。问到了事件驱动模型,我一脸懵逼,囧。所以现在遇到了,单独拉出来记录一下。

在Java的SpringMVC那一套中,每个请求都是实打实的请求request,然后交给dispacherServlet来处理各个请求。Servlet就一个实例。然后nginx采用的这套模型和java中的不同。

事件驱动模型是由事件收集器、事件发送器和事件处理器三部分基本单元构成。

在nginx中,基于事件驱动模型,这些消息事件在“事件处理器”中采用的方式是:

  • “事件发送器”每传递过来一个请求,“消息事件”就将其放到一个待处理的事件的列表中,使用非阻塞I/O方式调用“事件处理器”来处理请求。
  • 事件驱动处理 就是 多路I/O复用方法。在Nginx中,最常见的是:select模型、poll模型和epoll模型。
1、select模型
  1. 创建所关注事件的描述符集合。关注该描述符的Read、Write和Exception事件,所以创建三类事件描述符集合。
  2. 调用select()函数,等待事件发生。
  3. 轮询所有事件描述符集合中的每个事件的描述符,检查是否有相应事件发生,有了就处理。
2、poll模型

poll模型与select模型类似,创建->等待->轮询。
区别在于poll模型没有针对Read、Write和Exception事件分别做集合,而是只有一个集合,在描述符的对应结构上分别设置这三个事件。poll是select的升级版。

3、epoll模型

epoll是poll的变种,非常优秀!
之前的流程是 创建事件列表->将列表传入内核->返回结果后轮询列表;
当列表事件很多时,效率较低。
epoll让内核创建事件描述符。事件发生后,内核将事件的描述符返回给epoll,从而进行处理。所以没有轮询操作。

四、参考&致谢

《Nginx高性能Web服务器详解》 苗泽编著

《Mastering Nginx》 [瑞士]Dimitri Aivaliotis 著

觉得不错?