Nginx详解

目录

1 Nginx是什么

2 nginx应用

3 nginx架构特性

3.1 nginx程序架构

3.2 nginx功能特性

4 nginx并发模型

4.1 master进程

4.2 worker进程

4.3 并发处理

4.4 惊群问题

5 Nginx的事件处理

5.1 Nginx的特点

5.2 Nginx的内部(进程)模型

5.3 Nginx是如何处理一个请求

6 Nginx应用场景

6.1 正向代理

6.2 反向代理

6.3  透明代理

6.4  负载均衡


1 Nginx是什么

   nginx是一个被广泛使用的集群架构组件,我们有必要对它有足够的了解。下面将先认识nginx:包括应用场景、nginx基本架构、功能特性、并发模型以及配置说明,最后我们再总结下,为什么选择nginx的原因。

代理服务器:一般是指局域网内部的机器通过代理服务器发送请求到互联网上的服务器,代理服务器一般作用在客户端。应用比如:GoAgent,

 

 一个完整的代理请求过程为:客户端首先与代理服务器创建连接,接着根据代理服务器所使用的代理协议,请求对目标服务器创建连接、或者获得目标服务器的指定资源。 Web代理(proxy)服务器是网络的中间实体。 代理位于Web客户端和Web服务器之间,扮演“中间人”的角色。HTTP的代理服务器即是Web服务器又是Web客户端。

代理服务器是介于客户端和Web服务器之间的另一台服务器,有了它之后,浏览器不是直接到Web服务器去取回网页而是向代理服务器发出请求,信号会先送到代理服务器,由代理服务器来取回浏览器所需要的信息并传送给你的浏览器。

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

反向代理服务器:在服务器端接受客户端的请求,然后把请求分发给具体的服务器进行处理,然后再将服务器的响应结果反馈给客户端。Nginx就是其中的一种反向代理服务器软件。

Nginx:Nginx ("engine x") ,Nginx (“engine x”) 是俄罗斯人Igor Sysoev(塞索耶夫)编写的一款高性能的 HTTP 和反向代理服务器。也是一个IMAP/POP3/SMTP代理服务器;也就是说,Nginx本身就可以托管网站,进行HTTP服务处理,也可以作为反向代理服务器使用。

说明:客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。

反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端。

  

用户A始终认为它访问的是原始服务器B而不是代理服务器Z,但实用际上反向代理服务器接受用户A的应答,从原始资源服务器B中取得用户A的需求资源,然后发送给用户A。由于防火墙的作用,只允许代理服务器Z访问原始资源服务器B。尽管在这个虚拟的环境下,防火墙和反向代理的共同作用保护了原始资源服务器B,但用户A并不知情。 

2 nginx应用

 

       nginx (engine x)是一个可以作为HTTP WEB服务器、反向代理服务器、邮件代理服务器和一个通用的TCP / UDP代理服务器(1.9.0版本后)的多功能架构组件,同时也可以提供一定的缓存服务功能。

       nginx应用比较多的场景是WEB服务器和反向代理服务器,这两个场景的相关配置后面的文章我们会分别操作配置,这里先来认识下:

1、WEB服务器:这是应用比较多的场景,配置虚拟主机提供HTTP WEB服务。可以先通过动态/静态内容分离,而后为静态内容(html/css/js/图片等)提供HTTP访问功能;而动态内容可以整合代理模块,代理给上游服务器,来支持对外部程序的直接调用或者解析,如FastCGI支持PHP。

2、反向代理服务器:这是应用非常多的场景,为后端服务器代理。接收客户端请求,根据负载均衡策略转发给后端多个上游服务器处理;然后再等待后端服务器返回请求响应,接收到后再返回给请求的客户端。

3 nginx架构特性

3.1 nginx程序架构

1、一个master进程生成多个worker子进程(每个进程只有一个线程),一个worker响应多个用户请求;

2、非阻塞、IO复用、事件驱动:select,poll, epoll, kqueue,/dev/poll;

3、支持sendfile,sendfile64;

4、支持文件AIO(异步I/O);

5、支持mmap;

6、灵活的文件配置;

7、占用内存小:10,000个非活动HTTP保持连接占用大约2.5M内存。

Nginx架构图

一个master进程,可生成一个或多个worker进程

  • master:负责加载分析配置文件、管理worker进程、平滑升级、...

  • worker:处理并响应用户请求

一个master有多个worker,每个worker可响应n个请求,每个worker有核心模块core和外围的诸多模块modules组成,为了实现http功能有http协议的ht_core模块,为了功能完善还有很多其它模块,如实现负载均衡的ht_upstream模块,ht_proxy反代模块,Fastcgi模块ht_fastcgi模块;

用到哪些功能编译哪些模块或载入哪些模块即可;基于每种模块,可以与后端的不同应用通信;例如基于ht_core模块可与web ;基于server通信,基于ht_fastcgi模块可与php通信;基于memcache模块可与mamcache通信;所以这是反代模型工作时的架构;

nginx是高度模块化的,nginx的woker进程中除了用于响应用户请求之外,还有实现管理的组件,如cache loader负责加载缓存、cache manager负责管理缓存,用到时可启用,否则可不启用;

基于在本地磁盘上与本地磁盘数据通信时,支持高级IO机制、sendfile机制、AIO机制、mmap机制等;

实现并发用户请求响应时,可基于kevent、epoll、select;

从完整视角看nginx的功能

worker进程接收客户端的请求,如果使用缓存功能,可把后端服务器的内容缓存到本地,还负责从缓存中加载数据,直接响应给客户端;如果客户端请求的内容没有,还代理客户端到后端服务器上取资源,如果后端服务器是http就使用http模块进行,如果是php服务器就使用FastCGI模块进行;即向客户端提供服务、向后端提供反代、又能将后端服务器内容在本地缓存下来以提高性能,能够基于kv结构在本地将数据存下来,检索性能是O1的恒定不变,把key(键)缓存在内存中,检索起来非常快;

mmap内存映射,如何文件要想被访问,都要先从磁盘载入(布置到)内存才能被访问;而内存映射指的是,在内存空间中找一段空间,并没有把数据复制过来,是可以直接通过这段内存加载数据,在有些场景中,为了避免打开文件复制内存中这个复制过程,直接把文件映射一下,能够完成某个文件被访问到;

Nginx模块类型

核心模块:core module
标准模块

  • Standard HTTP modules 标准http模块
  • Optional HTTP modules 可选http模块
  • Mail modules 邮件模块
  • Stream moudles 流模块:实现传输层代理(4层代理)

3rd party modules:第三方模块

每个模块都引入2个项目:第一,指令,有某个模块,就有相应的配置指令,没有编译的模块就没有这个配置指令;第二,还有内置变量,不同模块有不同变量;

3.2 nginx功能特性

基本功能

实现与服务静态文件(静态资源的web服务器),能缓存打开的文件描述符;

反向代理服务器,缓存、负载均衡、健康状态检测;

支持FastCGI;

模块化机制,非DSO机制,支持多种过滤器gzip,SSI和图像的模块完成图形大小调整等;

支持SSL;

扩展功能

基于名称和IP做虚拟主机;

支持keeplive;

支持平滑配置更新或程序版本升级;

定制访问日志,支持使用日志缓存以提高性能;

支持URL rewrite;

支持路径别名;

支持基于IP及用户的认证;

支持速率限制,并发数限制等;

4 nginx并发模型

       如前图,一个master进程生成多个worker子进程(每个进程只有一个线程),一个worker响应多个用户请求。如果单进程启动:仅有一个进程,既充当master进程的角色,也充当worker进程的角色。

4.1 master进程

      充当整个进程组与用户的交互接口(接收来自外界的信号,向各worker进程发送信号),同时监控worker进程的运行状态。

      它不需要处理网络事件,不负责业务的执行,只会通过管理worker进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。

4.2 worker进程

      主要任务是处理基本的网络事件,完成具体的任务逻辑。多个worker进程之间是对等的,互相独立的。

      worker进程主要关注点是与客户端或后端服务器(此时nginx作为中间代理)之间的数据可读/可写等I/O交互事件,所以工作进程的阻塞点是在像select()、epoll_wait()等这样的I/O多路复用函数调用处,以等待发生数据可读/写事件。当然也可能被新收到的进程信号中断。

      worker进程个数

     如果负载以CPU密集型应用为主,一般会设置与机器cpu核数一致或少一个(用来处理用户等其他任务);

     如果负载以IO密集型为主,如响应大量内容给客户端,则worker数应该为CPU个数的1.5或2倍。  

     因为更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。

     更具体的可以根据公式:Nthread = Ncpu*Ucpu*(1+W/C),Ncpu是cpu的个数,Ucpu是cpu的使用率,W为等待时间,C为计算时间。这时需要通过监控工具来获取相应数据来计算。

     最后,再以监控工具数据为准进行微调。

4.3 并发处理

A、在master进程里面,先创建socket,并bind、listen在80端口(所以master进程需要root权限);

B、然后再fork出多个worker进程,这样每个worker进程都可以去accept这个socket(会产生惊群问题), 或者使用锁机制,让抢到锁的一个worker进程去accept这个socket,注意这里一般使用select/poll/epoll机制来解决accept阻塞问题;

C、当一个新连接进来后,而只有抢到锁的一个进程可以accept这个连接进行处理(也是放入epoll中)

D、抢到锁的worker进程accept到新连接后,会立即释放锁;然后所有worker进程再次参与抢锁,这样就回到了第二步,进行循环处理并发连接;

4.4 惊群问题

A、生产原因:像上面第二步,多个worker进程等待同一个socket的连接事件,当这个事件发生时,这些进程被同时唤醒,就是惊群。

注意,在linux2.6内核上,accept系统调用已经不存在惊群,但用epoll机制来解决accept阻塞问题,epoll_wait会有惊群问题(新增 EPOLLEXCLUSIVE 选项解决了)。

B、导致后果:许多worker进程被内核重新调度唤醒,只有一个进程可以accept这个连接进行处理,其他余者皆失败,导致性能浪费。

C、nginx解决方案:使用锁机制,让抢到锁的一个worker进程去accept(epoll_wait)这个socket;如果操作系统支持原子整型,才会使用共享内存实现原子上锁,否则使用文件上锁。

5 Nginx的事件处理

对于一个基本的web服务器来说,事件通常有三种类型,网络事件、信号、定时器。 

首先看一个请求的基本过程:建立连接---接收数据---发送数据 。

再次看系统底层的操作 :上述过程(建立连接---接收数据---发送数据)在系统底层就是读写事件。

 1)如果采用阻塞调用的方式,当读写事件没有准备好时,必然不能够进行读写事件,那么久只好等待,等事件准备好了,才能进行读写事件。那么请求就会被耽搁 。阻塞调用会进入内核等待,cpu就会让出去给别人用了,对单线程的worker来说,显然不合适,当网络事件越多时,大家都在等待呢,cpu空闲下来没人用,cpu利用率自然上不去了,更别谈高并发了 。

 2)既然没有准备好阻塞调用不行,那么采用非阻塞方式。非阻塞就是,事件,马上返回EAGAIN, 告诉你,事件还没准备好呢,你慌什么,过会再来吧。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再 来看看事件好了没。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的 

小结:非阻塞通过不断检查事件的状态来判断是否进行读写操作,这样带来的开销很大。 

3)因此才有了异步非阻塞的事件处理机制。具体到系统调用就是像select/poll/epoll/kqueue这样的系统调用。他们提供了一种机制,让你可以同时监控多个事件,调用他们是阻塞的,但可以设置超时时间,在超时时间之内,如果有事件准备好了,就返回。这种机制解决了我们上面两个问题。 

以epoll为例:当事件没有准备好时,就放入epoll(队列)里面。如果有事件准备好了,那么就去处理;如果事件返回的是EAGAIN,那么继续将其放入epoll里面。从而,只要有事件准备好了,我们就去处理她,只有当所有时间都没有准备好时,才在epoll里 面等着。这样,我们就可以并发处理大量的并发了,当然,这里的并发请求,是指未处理完的请求,线程只有一个,所以同时能处理的请求当然只有一个了,只是在 请求间进行不断地切换而已,切换也是因为异步事件未准备好,而主动让出的。这里的切换是没有任何代价,你可以理解为循环处理多个准备好的事件,事实上就是 这样的。 

4)与多线程的比较:

     与多线程相比,这种事件处理方式是有很大的优势的,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量级。并发数再多也不会导致无谓的资源浪费(上下文切换)。

小结:通过异步非阻塞的事件处理机制,Nginx实现由进程循环处理多个准备好的事件,从而实现高并发和轻量级。 

master/worker结构:一个master进程,生成一个或多个worker进程

内存消耗小:处理大并发的请求内存消耗非常小。在3万并发连接下,开启的10个Nginx 进程才消耗150M内存(15M*10=150M) 成本低廉:Nginx为开源软件,可以免费使用。而购买F5 BIG-IP、NetScaler等硬件负载均衡交换机则需要十多万至几十万人民币

内置的健康检查功能:如果 Nginx Proxy 后端的某台 Web 服务器宕机了,不会影响前端访问。

节省带宽:支持 GZIP 压缩,可以添加浏览器本地缓存的 Header 头。

稳定性高:用于反向代理,宕机的概率微乎其微

5.1 Nginx的特点

1、nginx代理和后端web服务器间无需长连接;

2、接收用户请求是异步的,即先将用户请求全部接收下来,再一次性发送后后端web服务器,极大的减轻后端web服务器的压力

3、发送响应报文时,是边接收来自后端web服务器的数据,边发送给客户端的

4、网络依赖型低。NGINX对网络的依赖程度非常低,理论上讲,只要能够ping通就可以实施负载均衡,而且可以有效区分内网和外网流量

5、支持服务器检测。NGINX能够根据应用服务器处理页面返回的状态码、超时信息等检测服务器是否出现故障,并及时返回错误的请求重新提交到其它节点上

5.2 Nginx的内部(进程)模型

nginx是以多进程的方式来工作的,当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式。nginx采用多进程的方式有诸多好处 .

 (1) nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控 worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。而基本的网络事件,则是放在worker进程中来处理了 。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的 。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。 worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的 。

(2)Master接收到信号以后怎样进行处理(./nginx -s reload )?首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的进程,并向所有老的进程发送信号,告诉他们可以光荣退休了。新的进程在启动后,就开始接收新的请求,而老的进程在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出 .

(3) worker进程又是如何处理请求的呢?我们前面有提到,worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket之后,然后再fork出多个worker进程,这样每个worker进程都可以去accept这个socket(当然不是同一个socket,只是每个进程的这个socket会监控在同一个ip地址与端口,这个在网络协议里面是允许的)。一般来说,当一个连接进来后,所有在accept在这个socket上面的进程,都会收到通知,而只有一个进程可以accept这个连接,其它的则accept失败,这是所谓的惊群现象。当然,nginx也不会视而不见,所以nginx提供了一个accept_mutex这个东西,从名字上,我们可以看这是一个加在accept上的一把共享锁。有了这把锁之后,同一时刻,就只会有一个进程在accpet连接,这样就不会有惊群问题了。accept_mutex是一个可控选项,我们可以显示地关掉,默认是打开的。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

(4):,nginx采用这种进程模型有什么好处呢?采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快重新启动新的worker进程。当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。当然,好处还有很多,大家可以慢慢体会。

(5).有人可能要问了,nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发数很有限啊,多少个worker就能处理多少个并发,何来高并发呢?非也,这就是nginx的高明之处,nginx采用了异步非阻塞的方式来处理请求,也就是说,nginx是可以同时处理成千上万个请求的 .对于IIS服务器每个请求会独占一个工作线程,当并发数上到几千时,就同时有几千的线程在处理请求了。这对操作系统来说,是个不小的挑战,线程带来的内存占用非常大,线程的上下文切换带来的cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的。我们之前说过,推荐设置worker的个数为cpu的核数,在这里就很容易理解了,更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,提供了cpu亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效 

5.3 Nginx是如何处理一个请求

首先,nginx在启动时,会解析配置文件,得到需要监听的端口与ip地址,然后在nginx的master进程里面,先初始化好这个监控的socket(创建socket,设置addrreuse等选项,绑定到指定的ip地址端口,再listen),然后再fork(一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程 )出多个子进程出来,然后子进程会竞争accept新的连接。此时,客户端就可以向nginx发起连接了。当客户端与nginx进行三次握手,与nginx建立好一个连接后,此时,某一个子进程会accept成功,得到这个建立好的连接的socket,然后创建nginx对连接的封装,即ngx_connection_t结构体。接着,设置读写事件处理函数并添加读写事件来与客户端进行数据的交换。最后,nginx或客户端来主动关掉连接,到此,一个连接就寿终正寝了。 

当然,nginx也是可以作为客户端来请求其它server的数据的(如upstream模块),此时,与其它server创建的连接,也封装在ngx_connection_t中。作为客户端,nginx先获取一个ngx_connection_t结构体,然后创建socket,并设置socket的属性( 比如非阻塞)。然后再通过添加读写事件,调用connect/read/write来调用连接,最后关掉连接,并释放ngx_connection_t。 

说明:nginx在实现时,是通过一个连接池来管理的,每个worker进程都有一个独立的连接池,连接池的大小是worker_connections。这里的连接池里面保存的其实不是真实的连接,它只是一个worker_connections大小的一个ngx_connection_t结构的数组。并且,nginx会通过一个链表free_connections来保存所有的空闲ngx_connection_t,每次获取一个连接时,就从空闲连接链表中获取一个,用完后,再放回空闲连接链表里面。 

在这里,很多人会误解worker_connections这个参数的意思,认为这个值就是nginx所能建立连接的最大值。其实不然,这个值是表示每个worker进程所能建立连接的最大值,所以,一个nginx能建立的最大连接数,应该是worker_connections * worker_processes。当然,这里说的是最大连接数,对于HTTP请求本地资源来说,能够支持的最大并发数量是worker_connections * worker_processes,而如果是HTTP作为反向代理来说,最大并发数量应该是worker_connections * worker_processes/2。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服务的连接,会占用两个连接。 

6 Nginx应用场景

6.1 正向代理

正向代理:内网服务器主动去请求外网的服务的一种行为

光看概念,可能有读者还是搞不明白:什么叫做“正向”,什么叫做“代理”,我们分别来理解一下这两个名词。

正向:相同的或一致的方向

代理:自己做不了的事情或者自己不打算做的事情,委托或依靠别人来完成。

借助解释,回归到nginx的概念,正向代理其实就是说客户端无法主动或者不打算完成主动去向某服务器发起请求,而是委托了nginx代理服务器去向服务器发起请求,并且获得处理结果,返回给客户端。

从下图可以看出:客户端向目标服务器发起的请求,是由代理服务器代替它向目标主机发起,得到结果之后,通过代理服务器返回给客户端。

举个栗子:广大社会主义接班人都知道,为了保护祖国的花朵不受外界的乌烟瘴气熏陶,国家对网络做了一些“优化”,正常情况下是不能外网的,但作为程序员的我们如果没有谷歌等搜索引擎的帮助,再销魂的代码也会因此失色,因此,网络上也曾出现过一些fan qiang技术和软件供有需要的人使用,如某VPN等,其实VPN的原理大体上也类似于一个正向代理,也就是需要访问外网的电脑,发起一个访问外网的请求,通过本机上的VPN去寻找一个可以访问国外网站的代理服务器,代理服务器向外国网站发起请求,然后把结果返回给本机。

正向代理的配置:

server { 
#指定DNS服务器IP地址   
resolver 114.114.114.114;    
#指定代理端口     
listen 8080;   
location / { 
#设定代理服务器的协议和地址(固定不变)     
proxy_pass http://$http_host$request_uri;  
}   
}  

这样就可以做到内网中端口为8080的服务器主动请求到1.2.13.4的主机上,如在Linux下可以:

curl --proxy proxy_server:8080 http://www.taobao.com/ 

正向代理的关键配置:

  1. resolver:DNS服务器IP地址
  2. listen:主动发起请求的内网服务器端口
  3. proxy_pass:代理服务器的协议和地址

6.2 反向代理

反向代理:reverse proxy,是指用代理服务器来接受客户端发来的请求,然后将请求转发给内网中的上游服务器,上游服务器处理完之后,把结果通过nginx返回给客户端。

上面讲述了正向代理的原理,相信对于反向代理,就很好理解了吧。

反向代理是对于来自外界的请求,先通过nginx统一接受,然后按需转发给内网中的服务器,并且把处理请求返回给外界客户端,此时代理服务器对外表现的就是一个web服务器,客户端根本不知道“上游服务器”的存在。

举个栗子:一个服务器的80端口只有一个,而服务器中可能有多个项目,如果A项目是端口是8081,B项目是8082,C项目是8083,假设指向该服务器的域名为www.xxx.com,此时访问B项目是www.xxx.com:8082,以此类推其它项目的URL也是要加上一个端口号,这样就很不美观了,这时我们把80端口给nginx服务器,给每个项目分配一个独立的子域名,如A项目是a.xxx.com,并且在nginx中设置每个项目的转发配置,然后对所有项目的访问都由nginx服务器接受,然后根据配置转发给不同的服务器处理。具体流程如下图所示:

反向代理配置:

server { 
    #监听端口 
    listen 80; 
    #服务器名称,也就是客户端访问的域名地址 
    server_name  a.xxx.com; 
    #nginx日志输出文件 
    access_log  logs/nginx.access.log  main; 
    #nginx错误日志输出文件 
    error_log  logs/nginx.error.log; 
    root   html; 
    index  index.html index.htm index.php; 
    location / { 
        #被代理服务器的地址 
        proxy_pass  http://localhost:8081; 
        #对发送给客户端的URL进行修改的操作 
        proxy_redirect     off; 
        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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; 
        proxy_max_temp_file_size 0; 
   } 
} 

这样就可以通过a.xxx.com来访问a项目对应的网站了,而不需要带上难看的端口号。

反向代理的配置关键点是:

  1. server_name:代表客户端向服务器发起请求时输入的域名
  2. proxy_pass:代表源服务器的访问地址,也就是真正处理请求的服务器(localhost+端口号)。

6.3  透明代理

透明代理:也叫做简单代理,意思客户端向服务端发起请求时,请求会先到达透明代理服务器,代理服务器再把请求转交给真实的源服务器处理,也就是是客户端根本不知道有代理服务器的存在。

举个栗子:它的用法有点类似于拦截器,如某些制度严格的公司里的办公电脑,无论我们用电脑做了什么事情,安全部门都能拦截我们对外发送的任何东西,这是因为电脑在对外发送时,实际上先经过网络上的一个透明的服务器,经过它的处理之后,才接着往外网走,而我们在网上冲浪时,根本没有感知到有拦截器拦截我们的数据和信息。

有人说透明代理和反向代理有点像,都是由代理服务器先接受请求,再转发到源服务器。其实本质上是有区别的,透明代理是客户端感知不到代理服务器的存在,而反向代理是客户端感知只有一个代理服务器的存在,因此他们一个是隐藏了自己,一个是隐藏了源服务器。事实上,透明代理和正向代理才是相像的,都是由客户端主动发起请求,代理服务器处理;他们差异点在于:正向代理是代理服务器代替客户端请求,而透明代理是客户端在发起请求时,会先经过透明代理服务器,再达到服务端,在这过程中,客户端是感知不到这个代理服务器的。

6.4  负载均衡

负载均衡:将服务器接收到的请求按照规则分发的过程,称为负载均衡。负载均衡是反向代理的一种体现。

可能绝大部分人接触到的web项目,刚开始时都是一台服务器就搞定了,但当网站访问量越来越大时,单台服务器就扛不住了,这时候需要增加服务器做成集群来分担流量压力,而在架设这些服务器时,nginx就充当了接受流量和分流的作用了,当请求到nginx服务器时,nginx就可以根据设置好的负载信息,把请求分配到不同的服务器,服务器处理完毕后,nginx获取处理结果返回给客户端,这样,用nginx的反向代理,即可实现了负载均衡。

nginx实现负载均衡有几种模式:

1.轮询:每个请求按时间顺序逐一分配到不同的后端服务器,也是nginx的默认模式。轮询模式的配置很简单,只需要把服务器列表加入到upstream模块中即可。

下面的配置是指:负载中有三台服务器,当请求到达时,nginx按照时间顺序把请求分配给三台服务器处理。

upstream serverList { 
server 1.2.3.4; 
server 1.2.3.5; 
server 1.2.3.6; 
} 

2.ip_hash:每个请求按访问IP的hash结果分配,同一个IP客户端固定访问一个后端服务器。可以保证来自同一ip的请求被打到固定的机器上,可以解决session问题。

下面的配置是指:负载中有三台服务器,当请求到达时,nginx优先按照ip_hash的结果进行分配,也就是同一个IP的请求固定在某一台服务器上,其它则按时间顺序把请求分配给三台服务器处理。

upstream serverList { 
    ip_hash 
    server 1.2.3.4; 
    server 1.2.3.5; 
    server 1.2.3.6; 
} 

3.url_hash:按访问url的hash结果来分配请求,相同的url固定转发到同一个后端服务器处理。

upstream serverList { 
    server 1.2.3.4; 
    server 1.2.3.5; 
    server 1.2.3.6; 
    hash $request_uri;  
    hash_method crc32;  
} 

 

fair:按后端服务器的响应时间来分配请求,响应时间短的优先分配。

upstream serverList { 
    server 1.2.3.4; 
    server 1.2.3.5; 
    server 1.2.3.6; 
    fair; 
} 

 

而在每一种模式中,每一台服务器后面的可以携带的参数有:

  1. down: 当前服务器暂不参与负载
  2. weight: 权重,值越大,服务器的负载量越大。
  3. max_fails:允许请求失败的次数,默认为1。
  4. fail_timeout:max_fails次失败后暂停的时间。
  5. backup:备份机, 只有其它所有的非backup机器down或者忙时才会请求backup机器。

如下面的配置是指:负载中有三台服务器,当请求到达时,nginx按时间顺序和权重把请求分配给三台服务器处理,例如有100个请求,有30%是服务器4处理,有50%的请求是服务器5处理,有20%的请求是服务器6处理。

upstream serverList { 
    server 1.2.3.4 weight=30; 
    server 1.2.3.5 weight=50; 
   server 1.2.3.6 weight=20; 
} 

如下面的配置是指:负载中有三台服务器,服务器4的失败超时时间为60s,服务器5暂不参与负载,服务器6只用作备份机。

upstream serverList { 
    server 1.2.3.4 fail_timeout=60s; 
    server 1.2.3.5 down; 
    server 1.2.3.6 backup; 
} 

下面是一个配置负载均衡的示例(只写了关键配置):

其中:

upstream:是负载的配置模块,serverList是名称,随便起

server_name:是客户端请求的域名地址

proxy_pass:是指向负载的列表的模块,如serverList

upstream serverList { 
     server 1.2.3.4 weight=30; 
     server 1.2.3.5 down; 
     server 1.2.3.6 backup; 
 }    
  
 server { 
     listen 80; 
     server_name  www.xxx.com; 
    root   html; 
    index  index.html index.htm index.php; 
    location / { 
        proxy_pass  http://serverList; 
        proxy_redirect     off; 
        proxy_set_header   Host             $host; 
   } 
} 

 

5. 静态服务器

现在很多项目流行前后分离,也就是前端服务器和后端服务器分离,分别部署,这样的方式能让前后端人员能各司其职,不需要互相依赖,而前后分离中,前端项目的运行是不需要用Tomcat、Apache等服务器环境的,因此可以直接用nginx来作为静态服务器。

静态服务器的配置如下,其中关键配置为:

  1. root:直接静态项目的绝对路径的根目录。
  2. server_name : 静态网站访问的域名地址。
server { 
       listen  80;                                                          
       server_name  www.xxx.com;                                                
       client_max_body_size 1024M; 
       location / { 
              root   /var/www/xxx_static; 
              index  index.html; 
          } 
   } 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值