nginx详解
Posted 跟着卓仔一起成长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nginx详解相关的知识,希望对你有一定的参考价值。
昨天去练球、ktv和夜店嗨皮了,清明节最后一天得学习了,学习下nginx吧。
使用场景!
nginx (engine x)是一个可以作为HTTP WEB服务器、反向代理服务器、邮件代理服务器和一个通用的TCP / UDP代理服务器(1.9.0版本后)的多功能架构组件,同时也可以提供一定的缓存服务功能。
主要有2个使用场景:
1、WEB服务器:这是应用比较多的场景,配置虚拟主机提供HTTP WEB服务。可以先通过动态/静态内容分离,而后为静态内容(html/css/js/图片等)提供HTTP访问功能;而动态内容可以整合代理模块,代理给上游服务器,来支持对外部程序的直接调用或者解析,如FastCGI支持php。
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块中的配置所处理。
并发模型!
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;如果操作系统支持原子整型,才会使用共享内存实现原子上锁,否则使用文件上锁。
负载均衡!
一种是硬件负载均衡,硬件比如:F5、Array等
另一种是软件负载均衡,软件比如:LVS、Nginx等
总结!
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详解的主要内容,如果未能解决你的问题,请参考以下文章
14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段