首页 > 技术文章 > Nginx学习

hangzhi 2018-05-24 17:14 原文

一  Nginx简介 (转自https://www.aliyun.com/zixun/content/3_12_518285.html)

  nginx是一个高性能的HTTP和反向代理服务器,也是个IMAP/POP3/SMTP代理服务器。

  nginx的优点:

   1.处理静态文件,索引文件以及自动索引;打开文件描述符缓冲 

   2.无缓存的反向代理加速,简单的负载均衡和容错   

   3.FastCGI,简单的负载均衡和容错

   4.模块化的结构,包括gzipping,byte ranges,chunked responses,以及SSI-filter等filter。如果由FastCGI或其它代理服务器处理单页中存在的多个SSI,则这项处理可以并行运行,而不需要相互等待。

   5.支持SSL 和 TLS SNI

  高并发连接:官方测试能够支撑5万并发连接,在实际生产环境中跑到2~3万并发连接数。

  内存消耗少:在3万并发连接下,开启的10个Nginx 进程才消耗150M内存(15M*10=150M)。

配置文件非常简单:风格跟程序一样通俗易懂。

成本低廉:Nginx为开源软件,可以免费使用。而购买F5 BIG-IP、NetScaler等硬件负载均衡交换机则需要十多万至几十万人民币。

支持Rewrite重写规则:能够根据域名、URL的不同,将 HTTP 请求分到不同的后端服务器群组。

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

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

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

模块化设计:模块可以动态编译10、外围支持好:-文档全、二次开发和模块较多

支持热部署:可以不停机重载配置文件

支持事件驱动、AIO、mmap等性能优化

 

二  反向代理/负载均衡

反向代理  

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

数据转发功能,为Nginx提供了跨越单机的横向处理能力,使Nginx摆脱只能为终端节点提供单一功能的限制,而使它具备了网路应用级别的拆分、封装和整合的功能。同时,Nginx的配置系统提供的层次化和松耦合使得系统的扩展性也达到比较高的程度。

作用

  1. 保护网站安全:任何来自Internet的请求都必须先经过代理服务器
  2. 通过配置缓存功能加速Web请求:可以缓存真实web服务器上的某些静态资源,减轻真实web资源的负载压力
  3. 实现负载均衡:充当负载均衡服务器均衡的分发请求,平分集群中各个服务器的负载压力

负载均衡

负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求按照某种策略分配到服务器集合的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡解决了大量并发访问服务问题,其目的就是用最少的投资获得接近于大型主机的性能。

Nginx如何实现多个Worker进程之间的负载均衡?Nginx采用了一个简单的算法,这个算法大致描述如下:每个Worker进程在初始化的时候会有一个Ngx_Accept_Disabled整形变量。这个变量初始值是每个进程自身连接池大小的7/8,符号为负。每次进程建立了一个连接就把这个值加1。直到这个值为正,当前进程不在处理新的连接,此时如果有锁,释放锁。这时其他进程获得锁的几率变大。每次完成连接后再把这个值减1,直到他恢复到初始值,进程开始尝试获取锁。这个策略比较简单,在一定程度上实现的负责均衡。

负载均衡算法

Nginx 的 Upstream 模块所支持负载均衡的算法:

  1. 默认的方式是轮询,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器宕机,能自动剔除。
  2. 权重轮询均衡:可以指定轮询几率,权重(Weight)和访问比率成正比,用于后端服务器性能不均的情况。
  3. 每个请求按访问 Ip 的 Hash 结果分配,这样每个访客固定访问一个后端服务器,在有些应用情况下,需要将来自同一客户端的所有请求都分配给同一台服务器去负担,例如服务器将客户端注册、购物等服务请求信息保存的本地数据库的情况下,把客户端的子请求分配给同一台服务器来处理就显的至关重要了。
  4. 按后端服务器的响应时间来分配请求,响应时间短的优先分配。
  5. 按访问 Url 的 Hash 结果来分配请求,使每个 Url 定向到同一个后端服务器,后端服务器为缓存时比较有效。在 Nginx.Conf 配置文件中,用 Upstream 指令定义一组

(以 4 台服务器为例)负载均衡后端服务器池:

Upstream Servername {

Server 192.168.1.10:80 Weight=1 Max_Fails=3 Fail_Timeout=60s;

Server 192.168.1.11:80 Weight=1 Max_Fails=3 Fail_Timeout=60s;

Server 192.168.1.12:80 Weight=1 Max_Fails=3 Fail_Timeout=60s;

Server 192.168.1.13:80 Weight=1 Max_Fails=3 Fail_Timeout=60s;

}

其中,Servername 是服务器组名;Weight:设置服务器的权重,默认值是 1,权重值越大那么该服务器被访问到的几率就越大;Max_Fails 和 Fail_Timeout :这两个是关联的,如果某台服务器在 Fail_Timeout 时间内出现了 Max_Fails 次连接失败,那么 Nginx 就会认为那个服务器已经宕机,从而在 Fail_Timeout 时间内不再去查询它。

 

三  nginx配置详情

四  nginx+keepalived高可用

 

五 nginx进程模型 (转自https://www.cnblogs.com/AlwaysFixBug/p/4811838.html)

  Nginx在启动后,会有一个Master进程和多个Worker进程。Master进程主要用来管理Worker进程,包含:接收来自外界的信号,向各Worker进程发送信号,监控Worker进程的运行状态,当Worker进程退出后(异常情况下),会自动重新启动新的Worker进程。而基本的网络事件,则是放在Worker进程中来处理了。多个Worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个Worker进程中处理,一个Worker进程,不可能处理其它进程的请求。Worker进程的个数是可以设置的,一般我们会设置与机器Cpu核数一致,我们之前说过,推荐设置Worker的个数为Cpu的核数,在这里就很容易理解了,更多的Worker数,只会导致进程来竞争Cpu资源了,从而带来不必要的上下文切换。而且,Nginx为了更好的利用多核特性,提供了Cpu亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来Cache的失效。像这种小的优化在Nginx中非常常见,比如,Nginx在做4个字节的字符串比较时,会将4个字符转换成一个Int型,再作比较,以减少Cpu的指令数等等。Nginx的进程模型,可以由下图来表示:

                   Nginx进程模型

 

在Nginx启动后,Master进程会接收来自外界发来的信号,再根据信号做不同的事情。所以我们要控制Nginx,只需要通过Kill向Master进程发送信号就行了。比如Kill -HUP Pid,则是告诉Nginx,需要重启Nginx。Master进程在接收到Kill信号后是怎么做的呢?首先Master进程在接到信号后,会先重新加载配置文件,然后再启动新的Worker进程,并向所有老的Worker进程发送信号,告诉他们可以光荣退休了。新的Worker在启动后,就开始接收新的请求,而老的Worker在收到来自Master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。

Worker进程又是如何处理请求的呢?我们前面有提到,Worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的Http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个Worker进程都是从Master进程Fork过来,在Master进程里面,先建立好需要Listen的Socket(Listenfd)之后,然后再Fork出多个Worker进程。所有Worker进程的Listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有Worker进程在注册Listenfd读事件前抢Accept_Mutex,抢到互斥锁的那个进程注册Listenfd读事件,在读事件里调用Accept接受该连接。当一个Worker进程在Accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由Worker进程来处理,而且只在一个Worker进程中处理。

Nginx采用这种进程模型有什么好处呢?当然,好处肯定会很多了。首先,对于每个Worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断。

惊群效应

什么是惊群效应,这个Nginx的进程模型有关。Nginx采用的是多Worker进程处理连接的方式,是一个请求只能由一个进程独占,所以除了那个先拿到请求的和Tomcat等一般的服务器不同,没有一个专门用于处理连接的工作单元。每个进程都是独立的工作单元。假如说现在没有连接请求到服务器,那么所有Worker进程都是处于休眠监听状态的,但是一旦有请求到来,那么所有休眠的Worker进程都会被唤醒,但除了建立连接的进程外其他进程又会恢复到休眠状态。这样的开销是可以避免的,在某些情况下,进程被频繁的大面积唤醒,休眠会消耗大量的资源。Nginx的做法是某一时刻只有一个Worker进程监听端口,具体的做法是设置一把锁。当进程空闲下来试图去监听端口时先尝试获取锁,如果没获取到锁那么进程继续当前工作。如果获取到了锁,则监听端口,负责处理新的连接请求。这里有一个问题,什么时候释放锁呢?是等到进程处理完所有事件后么?这样可能会导致事件过长,那么如何减少时间呢?Nginx的做法是设置两个队列,一个用于存放获取锁后建立的新的连接事件,另一个存放普通事件。当进程处理完新的连接事件后就释放锁,减少锁的占用事件。

 

推荐阅读