web之家  

https://www.jianshu.com/p/cbf06e139a88

 

为什么基于事件驱动的服务器能实现高并发?

https://www.zhihu.com/question/64727674

 

1 WEB服务端综述部分
2 Nginx部分
3 Tomcat部分

1 WEB服务端综述部分

1.1 什么是WEB服务器

WEB服务器也称为WORLD WIDE WEB服务器,主要功能是提供网上信息浏览服务。

  • 服务器是一种被动程序:只有发出请求,服务器才会响应。
  • Internet上的服务器也称为Web服务器。
  • Web服务器是指驻留于因特网上某种类型计算机的程序。服务器使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,这就是人们常把它们称为HTTP服务器的原因。
  • 比较常用的Java服务器有Tomcat、Resin、JBoss、WebSphere 和 WebLogic 等。
  • 只有将开发的Web项目放置到该容器中,才能使网络中的所有用户通过浏览器进行访问。

1.2 Web服务器的工作原理:

  1. 客户端发送请求
  2. 服务器解析请求
  3. 读取其它信息(非必须步骤)
  4. 完成请求的动作
  5. 关闭文件和网络连接,结束会话

2 Nginx部分

2.1 什么是Nginx?

Nginx是一款轻量级的Web服务器/反向代理服务器。其特点是占有内存少,并发能力强。

中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

2.2 为什么要用Nginx?

优点:

  • 跨平台、配置简单;
  • 非阻塞、高并发连接;
  • 内存消耗小;
  • 稳定性高:1 宕机的概率非常小;2 内置的健康检查功能:如果有一个服务器宕机,会做一个健康检查,再发送的请求就不会发送到宕机的服务器了。重新将请求提交到其他的节点上;
  • 节省宽带:支持GZIP压缩,可以添加浏览器本地缓存;
  • master/worker结构:一个master进程,生成一个或者多个worker进程;
  • 接收用户请求是异步的:浏览器将请求发送到nginx服务器,它先将用户请求全部接收下来,再一次性发送给后端web服务器,极大减轻了web服务器的压力;
  • 网络依赖性比较低,只要ping通就可以负载均衡;
  • 事件驱动:通信机制采用epoll模型;

2.3 为什么Nginx性能高?

  1. 得益于它的事件处理机制
    异步非阻塞事件处理机制:运用了epoll模型,提供了一个队列,排队解决。
    所谓事件驱动架构,简单来说,就是由一些事件发生源来产生事件,由一个或多个事件收集器(epolld等)来收集、分发事件,然后许多事件处理器会注册自己感兴趣的事件,同时会“消费”这些事件。nginx不会使用进程或线程作为事件消费者,只能是某个模块,当前进程调用模块。
  2. 请求的多阶段异步处理
    请求的多阶段异步处理只能基于事件驱动框架实现,就是把一个请求的处理过程按照事件的触发方式分为多个阶段,每个阶段都可以有事件收集、分发器(epoll等)来触发。比如一个http请求可以分为七个阶段。
  3. 内存池的设计
    为了减少避免出现内存碎片、减少向操作系统申请内存的次数、降低各个模块的开发复杂度,Nginx采用了简单的内存池(统一申请,统一释放)。比如为每个http请求分配一个内存池,请求结束时销毁整个内存池。
  4. 优秀模块 模块设计
    高度模块化设计,除了少量核心代码,其他一切接模块。官方Nginx共有五大类型模块:核心模块、配置模块、事件模块、HTTP模块、mail模块。
    要注意的是:nginx的模块是静态的,添加和删除模块都要对nginx进行重新编译,这一点与Apache的动态模块完全不同。

2.4 传统web服务器与Nginx间重要差别?

传统web服务器(如Apache)的请求基于TCP连接建立、关闭上。每个请求在连接建立后都将始终占用系统资源,直到连接关闭才会释放资源。
前者每个事件消费者独占一个进程资源,后者只是被事件分发者进程短期调用而已。

2.5 为什么不使用多线程?

多线程会导致较大的并发量。
Apache: 创建多个进程或线程,而每个进程或线程都会为其分配cpu和内存,导致较大并发量。
Nginx: 采用单线程来异步非阻塞处理请求,不会为每个请求分配cpu和内存资源,节省了大量资源。

2.6 Nginx是如何处理一个请求的呢?

  1. nginx在启动时,会解析配置文件,得到需要监听的端口与ip地址。
  2. 在nginx的master进程里面先初始化好这个监控的socket,再fork出多个子进程出来, 子进程会竞争accept新的连接。此时,客户端就可以向nginx发起连接了。
  3. 当客户端与nginx进行三次握手,与nginx建立好一个连接后,此时,某一个子进程会accept成功,然后创建nginx对连接的封装,即ngx_connection_t结构体。
  4. 根据事件调用相应的事件处理模块,如http模块与客户端进行数据的交换。
  5. 最后,nginx或客户端来主动关掉连接。

2.7 正向代理

一个位于客户端和原始服务器(origin server)之间的服务器。

客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。

举个例子:我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我

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

正向代理总结就一句话:代理端代理的是客户端。

2.8 反向代理

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

反向代理总结就一句话:代理端代理的是服务端。

反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。这对于安全方面来说是很好的。

正向代理和反向代理好文阅读

https://www.zhihu.com/question/24723688

2.9 动态资源、静态资源分离

动态资源、静态资源分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来。

动静资源做拆分后,就可以根据静态资源的特点做缓存,这就是网站静态化处理的核心思路。

动态资源、静态资源分离简单的概括是:动态文件与静态文件的分离。

2.10 为什么要做动、静分离?

在我们的软件开发中,有些请求是需要后台处理的静态文件(如:.jsp,.do等等),有些请求是不需要经过后台处理的动态文件(如:css、html、jpg、js等等文件)。

动、静分离的策略可以提高用户访问静态代码的速度,降低对后台应用访问。一般是将静态资源放到nginx中,动态资源转发到tomcat服务器中。

2.11 负载均衡

指通过代理服务器将接收的请求均衡的分发到各服务器中。

负载均衡主要解决网络拥塞问题,提高服务器响应速度,服务就近提供,达到更好的访问质量,减少后台服务器大并发压力。

2.12 请列举Nginx和Apache 之间的不同点?

 
image.png

2.13 请列举Nginx服务器的最佳用途

  1. 在网络上部署动态HTTP内容。
  2. 作为负载均衡器。

3 Tomcat部分

3.1 Tomcat顶层架构

 
image.png

Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务。

Service主要包含两个部分:Connector和Container。从上图中可以看出 Tomcat 的心脏就是这两个组件,他们的作用如下:

1、Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化;
2、Container用于封装和管理Servlet,以及具体处理Request请求;

一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但是可以有多个Connectors,这是因为一个服务可以有多个连接,如同时提供Http和Https链接,也可以提供向相同协议不同端口的连接。

 
image.png

多个 Connector 和一个 Container 就形成了一个 Service,有了 Service 就可以对外提供服务了,Service 的生存环境是Server ,所以整个Tomcat的生命周期由 Server 控制。

另外,上述的包含关系或者说是父子关系,都可以在tomcat的conf目录下的server.xml配置文件中看出,下图是删除了注释内容之后的一个完整的server.xml配置文件(Tomcat版本为8.0)

 
image.png

详细的配置文件文件内容可以到Tomcat官网查看:http://tomcat.apache.org/tomcat-8.0-doc/index.html

 

上边的配置文件,还可以通过下边的一张结构图更清楚的理解:

 
image.png

Server标签设置的端口号为8005,shutdown=”SHUTDOWN” ,表示在8005端口监听“SHUTDOWN”命令,如果接收到了就会关闭Tomcat。一个Server有一个Service,当然还可以进行配置,一个Service有多个,Service左边的内容都属于Container的,Service下边是Connector。

3.2 Tomcat顶层架构小结

  • (1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个Connector和一个Container;
  • (2) Server掌管着整个Tomcat的生死大权;
  • (3)Service 是对外提供服务的;
  • (4)Connector用于接受请求并将请求封装成Request和Response来具体处理;
  • (5)Container用于封装和管理Servlet,以及具体处理request请求;

OK 面试到这里就差不多了。后面的是较为深入的理解。




3.3 Connector和Container的微妙关系

由上述内容我们大致可以知道一个请求发送到Tomcat之后,首先经过Service然后会交给我们的Connector,Connector用于接收请求并将接收的请求封装为Request和Response来具体处理,Request和Response封装完之后再交由Container进行处理,Container处理完请求之后再返回给Connector,最后在由Connector通过Socket将处理的结果返回给客户端,这样整个请求的就处理完了!

Connector最底层使用的是Socket来进行连接的,Request和Response是按照HTTP协议来封装的,所以Connector同时需要实现TCP/IP协议和HTTP协议!

Tomcat既然处理请求,那么肯定需要先接收到这个请求,接收请求这个东西我们首先就需要看一下Connector!

3.4 Connector架构分析

Connector用于接受请求并将请求封装成Request和Response,然后交给Container进行处理,Container处理完之后在交给Connector返回给客户端。

因此,我们可以把Connector分为四个方面进行理解:

  • (1)Connector如何接受请求的?
  • (2)如何将请求封装成Request和Response的?
  • (3)封装完之后的Request和Response如何交给Container进行处理的?
  • (4)Container处理完之后如何交给Connector并返回给客户端的?

首先看一下Connector的结构图(图B),如下所示:

 
image.png

1 Connector是使用ProtocolHandler来处理请求的。

不同的ProtocolHandler代表不同的连接类型,比如:Http11Protocol使用的是普通Socket来连接的,Http11NioProtocol使用的是NioSocket来连接的。

其中ProtocolHandler由包含了三个部件:Endpoint、Processor、Adapter。

(1)Endpoint用来处理底层Socket的网络连接,Processor用于将Endpoint接收到的Socket封装成Request,Adapter用于将Request交给Container进行具体的处理。

(2)Endpoint由于是处理底层的Socket网络连接,因此Endpoint是用来实现TCP/IP协议的,而Processor用来实现HTTP协议的,Adapter将请求适配到Servlet容器进行具体的处理。

(3)Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理。

至此,我们应该很轻松的回答(1)(2)(3)的问题了,但是(4)还是不知道,那么我们就来看一下Container是如何进行处理的以及处理完之后是如何将处理完的结果返回给Connector的?

3.5 Container架构分析

Container用于封装和管理Servlet,以及具体处理Request请求,在Connector内部包含了4个子容器,结构图如下(图C):


 
image.png

4个子容器的作用分别是:

  • (1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;
  • (2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;
  • (3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;
  • (4)Wrapper:每一Wrapper封装着一个Servlet;

下面找一个Tomcat的文件目录对照一下,如下图所示:

 
image.png

Context和Host的区别是Context表示一个应用,我们的Tomcat中默认的配置下webapps下的每一个文件夹目录都是一个Context,其中ROOT目录中存放着主应用,其他目录存放着子应用,而整个webapps就是一个Host站点。

我们访问应用Context的时候,如果是ROOT下的则直接使用域名就可以访问,例如:www.ledouit.com,如果是Host(webapps)下的其他应用,则可以使用www.ledouit.com/docs进行访问,当然默认指定的根应用(ROOT)是可以进行设定的,只不过Host站点下默认的主营用是ROOT目录下的。

3.6 Container如何处理请求的

Container处理请求是使用Pipeline-Valve管道来处理的!(Valve是阀门之意)

Pipeline-Valve是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将处理后的请求返回,再让下一个处理着继续处理。

 
image.png

Pipeline-Valve使用的责任链模式和普通的责任链模式有些不同,区别主要有以下两点:

(1)每个Pipeline都有特定的Valve,而且是在管道的最后一个执行,这个Valve叫做BaseValve,BaseValve是不可删除的;

(2)在上层容器的管道的BaseValve中会调用下层容器的管道。

Container包含四个子容器,而这四个子容器对应的BaseValve分别在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。

Pipeline的处理流程图如下(图D):

 
image.png

(1)Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道);

(2)在Engine的管道中依次会执行EngineValve1、EngineValve2等等,最后会执行StandardEngineValve,在StandardEngineValve中会调用Host管道,然后再依次执行Host的HostValve1、HostValve2等,最后在执行StandardHostValve,然后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValve。

(3)当执行到StandardWrapperValve的时候,会在StandardWrapperValve中创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理!

(4)当所有的Pipeline-Valve都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端。

4 参考链接

https://blog.csdn.net/lz233333/article/details/51210554
https://segmentfault.com/a/1190000010677483
https://blog.csdn.net/xlgen157387/article/details/79006434
https://blog.csdn.net/watson2016/article/details/77938678



作者:艾剪疏
链接:https://www.jianshu.com/p/cbf06e139a88
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted on 2021-05-11 20:15  路修远而求索  阅读(155)  评论(0编辑  收藏  举报