nginx详解

Posted 跟着卓仔一起成长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nginx详解相关的知识,希望对你有一定的参考价值。

昨天去练球、ktv和夜店嗨皮了,清明节最后一天得学习了,学习下nginx吧。


1

使用场景!


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


主要有2个使用场景:


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


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



2

配置文件区域说明!



nginx主要配置文件nginx.conf,里面主要包括以下几个配置区域,如下:


main块

配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。


events块

配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。


http块

可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。


upstream块

配置HTTP负载均衡器分配流量到几个应用程序服务器。


server块

配置虚拟主机的相关参数,一个http中可以有多个server。


location块

配置请求的路由,以及允许根据用户请求的URI来匹配指定的各location以进行访问配置;匹配到时,将被location块中的配置所处理。



3

并发模型!



nginx并发模型为异步非阻塞,这也是nginx为什么的支持5w并发的原因。

它的底层结构分为master进程和work进程:



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


master进程

 

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


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


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为计算时间。这时需要通过监控工具来获取相应数据来计算。


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


工作流程


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进程再次参与抢锁,这样就回到了第二步,进行循环处理并发连接;


惊群问题


惊群问题是异步非阻塞模型都会存在的问题。

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


举个例子:

listen_fd = socket(...);epoll_fd = epoll_create(...);fork(); //创建子进程while(){ accept() 等待接受连接 epoll_ctl  epoll_wait(...) //等待事件的产生}

当listen_fd有新的accept()请求过来,操作系统会唤醒所有子进程(因为这些进程都epoll_wait()同 一个listen_fd,操作系统又无从判断由谁来负责accept,索性干脆全部叫醒……),但最终只会有一个进程成功accept,其他进程 accept失败。


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


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


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


4

负载均衡!


nginx非常适合做负载均衡服务器,但负载均衡分为两种,一个是服务端负载均衡,一个是客户端负载均衡。

服务端负载均衡:

一种是硬件负载均衡,硬件比如:F5、Array等

另一种是软件负载均衡,软件比如:LVS、Nginx等


客户端负载均衡:



服务端负载均衡就是 大量的客户端发出请求时先通过服务端负载均衡器进行转发到不同的服务器上请求,可以有效的平衡并发。

但客户端负载均衡是在微服务系统中,客户端请求已经进入某个服务A,但这个服务还需要调用其他服务B,但如果并发特别高的时候,A服务同时需要调用B服务多次,B服务的负载压力很大,所以A服务调用B服务时还需要负载均衡,平衡B服务的并发。

在Spring cloud中ribbon和feign(底层也是ribbon)就是客户端复杂均衡。


5

总结!


nginx非常适合做前端web服务器和反向代理服务器(负载均衡)。


nginx可以和redis对比一下,他们的性能都很好,都是采用epoll模型。


但redis是同步非阻塞,nginx是异步非阻塞。


redis是单线程处理的并发,可以避免锁和线程切换的问题。 但并发性却存在上限,

所以nginx的多进程模式并发就非常好,但调用epoll_wait 函数的时候会把所有worker进程唤醒,存在惊群问题(所有异步模型都存在)。


所以nginx采用共享锁的机制,一个请求来了,只有拿到锁的worker模型才能处理它。


所以nginx的并发性非常好,很适合做负载均衡。


而且和Spring cloud 对比的ribbon和feign对比,nginx是服务端负载均衡,ribbon和feign是客户端负载均衡。





参考:

https://blog.csdn.net/tjiyu/article/details/53027619

以上是关于nginx详解的主要内容,如果未能解决你的问题,请参考以下文章

详解Android WebView加载html片段

14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段

Python中verbaim标签使用详解

nginx.conf 忽略了 nginx-ingress 配置映射片段

将 nginx rtmp 片段发送到 WebRTC

Linux下nginx编译安装教程和编译参数详解