炼数成金 门户 大数据 Java 查看内容

详解主流Java应用服务器的工作原理及组件设计

2018-3-7 14:28| 发布者: 炼数成金_小数| 查看: 19281| 评论: 0|原作者: 刘光瑞|来自: DBAplus社群

摘要: 大概从2000年以后,Java应用服务器的使用主要经历了3个阶段:J2EE应用服务器、Servlet容器及Web服务器、响应式微服务。首先,是J2EE应用服务器。这部分在以Spring为主的without EJB的应用框架出现之前,基本上是企业 ...

Java 服务器 架构 Web Tomcat

作者介绍
刘光瑞,现任窝客研发总监,负责窝客产品研发管理及总体架构设计。
拥有十几年企业级大型业务系统研发架构经验,成功带领团队设计并研发基于Tomcat的组件化微服务架构。
热衷于系统架构、Java技术栈及应用服务器中间件的学习及研究。

今天所讲内容的大纲如下:
Java应用服务器分类
Servlet容器工作原理
Tomcat组件及请求处理

一、Java应用服务器分类
大概从2000年以后,Java应用服务器的使用主要经历了3个阶段:J2EE应用服务器、Servlet容器及Web服务器、响应式微服务。

1、J2EE应用服务器
首先,是J2EE应用服务器。这部分在以Spring为主的without EJB的应用框架出现之前,基本上是企业应用开发的标配。这类应用服务器严格实现了J2EE规范,通过了SUN的相关认证,还支持标准的基于J2EE的应用开发,包括EJB、JMS、JTA、Servlet、JSF等等。


这类应用服务器有很强的配置和优化能力,非常适合集中式的大型企业级应用开发。这一类的产品情况如下:


像WebSphere这一类商用产品,是大型的银行、电信应用的主流服务器,甚至配合IBM的JVM实现,有着非常好的性能优势。

免费的诸如JBOSS,使用也非常广泛,作为商用企业级应用服务器的减配版。

企业级应用服务器的特点就是过重。大概2010年之后(具体时间不确定),有几个转向了OSGi这种模块化架构,期望提供一种更加灵活的架构。像JBoss这一类产品在互联网规模化、轻量化的大背景下,似乎使用的相对越来越少。但是在集中式的企业级应用场景,它们应该还是主流,轻量级服务器是很难取代的。

2、Servlet容器及Web服务器
这一类在后面才提到,并不是说它们的历史较短,像Tomcat的历史可以说是最长的几款服务器实现。而是说它们被大规模用于生产环境的尝试,相对较晚。

这是与互联网应用大规模分布式架构分不开的。在轻量级的架构中,绝大多数应用实际上主要使用了服务器的Servlet容器部分,其它部分很少使用,而是使用更完善的第三方框架去替代。这时候,J2EE服务器显得过重,所以开始更倾向于只使用Servlet容器提供HTTP服务。


这一类服务器见图片,主要是Tomcat、Resin、Jetty、Undertow。

Tomcat大家想必都很熟悉了,基本Java Web应用开发入门就使用。它主要的使用场景还是独立启动部署Web应用,嵌入式的场景与Jetty相比,要相对差一些;Undertow出现相对晚一些,它是JBoss实现的新的Servlet容器,以前JBoss直接使用Tomcat作为Servlet容器。

如果大家基于Spring Boot开发应用,想必都知道,现在Spring Boot对这三款容器都支持,现在用的比较多的是Tomcat和Jetty,Undertow使用的相对较少。

后两者是很少作为独立启动的服务器来使用的,尤其是Undertow,应该不支持这种场景。

3、响应式微服务
这一类严格说并不是Web服务器。有时候(如微服务架构),我们更倾向于直接提供HTTP服务,这个时候并不需要支持Web,不需要Servlet规范。


这一类就是为这种场景设计的,目前有两类方案可以来满足这种场景,一种是Vert.x,这个国内目前使用应该不是很多。主要是它不支持Servlet规范,这估计是一方面的原因。

还有一种是Play Framework内置的基于事件的HTTP服务,和Vert.x类似,它们都是为高并发的互联网服务开发实现的。今天对于这种方案我们不做展开,还是以主流的Servlet方案为主。

二、Servlet容器工作原理
应用服务器基于Servlet提供基础的HTTP服务,包括Web服务、SOA,即便是JSP页面,最终也是通过Servlet实现的。因此Servlet容器可以说是Web服务的核心。


1、容器的核心部分
对于一款Servlet容器,主要分为两部分:链接器和容器。前者是服务器对I/O的封装,后者是对Servlet规范的实现。


大家可以简要看一下这一篇的内容:一款服务器通过链接器读取网络请求,将其转换为符合Servlet规范的Request对象,同时负责将Servlet容器的响应输出到客户端。

它对Servlet容器屏蔽了协议及I/O方式等的区别。无论是HTTP还是AJP、还是HTTPS,在容器中获取到的都是一个标准的Request对象。


而容器呢,主要负责三个方面的工作:
按照Servlet规范(Web.xml/注解等等),识别部署的Web应用,将其解析为内部的请求处理组件;
接收链接器的请求调用(一般不需要容器负责请求映射,映射部分是链接器完成的);
按照Servlet规范进行请求处理,这部分主要是Filter等的处理。


2、工作原理
大家可以看一下这个示意图:


对于链接器,无论采用哪一种I/O,都是采用一种线程池的方式来处理的。

主要有两个线程池,一个用于接收请求,一个用于处理请求。接收请求的线程负责读取请求头,完成请求映射,并将请求提交到映射到的请求处理组件(一个指定的Servlet)。

这儿大家注意一点,容器映射完成的结果是一个Servlet,而不是一个Web应用,至少Tomcat是这样处理的,Jetty更轻量。

虽然Servlet的具体实现不同,但是完成的工作基本类似,而且模式也类似(除去我们说的第三类)。

接下来我们具体看一下Tomcat是如何实现Servlet容器的:相对于Jetty轻量的处理架构,Tomcat更像“服务器”一些,它考虑了一些服务器的特性,如虚拟主机。

三、Tomcat组件及请求过程
1、容器主要组件
Tomcat的主要组件可以看一下下面这张图:它底层通过Java命名服务统一对各种组件进行管理,体现了服务器软件的“管理”特性;然后是链接器实现Coyote和Jasper JSP引擎。


Tomcat与Jetty相比,它更是一款完整的Servlet容器方案。而Jetty是以模块化的形式提供了Servlet容器以及各种HTTP工具集。像JSP引擎,Jetty直接使用的Tomcat中的Jasper(还有另一种可选方案)。

最上面的Catalina是Tomcat容器的实现。大家如果看Tomcat的异常堆栈,就会发现包名基本都是以这个作为开头。

Tomcat链接器,我们可以简单的按两层进行划分:应用层和传输层。


应用层里,版本的Tomcat支持HTTP、AJP以及HTTP2,传输层支持NIO、NIO2以及APR,版本已经不支持BIO。

链接器还有一个很重要的组件就是线程池,想必做过基本的Tomcat优化的人都调整过Tomcat并发链接数。线程池的分类我们刚才也说过了,分为接收线程池和请求处理线程池。

2、Tomcat Servlet容器组件
Servlet容器的组件见图:简单来说,Tomcat通过一种分层的架构使得Servlet容器有很好的灵活性,而且通过生命周期管理接口,为这些各层的对象提供统一的生命周期管理。


分层如下:Engine-Host-Context-Wrapper。引擎是较高级,我们可以认为就是容器本身。Host是虚拟主机的概念,这样可以在Tomcat配置多个虚拟主机。Context就是我们的Web应用,Wrapper是Web应用中的Servlet,所以还是刚才说的,Tomcat中的请求映射是体现到Servlet上。

基于分层的组件,Tomcat还提供了完善的生命周期事件处理机制,Web应用的自动扫描启动、热部署、卸载等都是通过事件实现的。如果阅读Tomcat代码,需要重点关注下面的生命周期监听。


HostConfig主要用于扫描Web应用,自动根据Web应用目录创建Context。ContextConfig重点处理Servlet规范,生成Servlet、Filter等各种规范组件。最后,Tomcat自身也实现了一种链式的请求处理机制,这一点和规范中的Filter类似,这就是Valve。

在Tomcat中,Filter中可以做的事情,Valve可以做;Valve可以做的事情,Filter却不一定可以做,需要深入和服务器交互的工作,一般都是用Valve实现。

3、请求处理过程
这是一张Tomcat请求处理过程的时序图,大家看一下就会发现。Tomcat在这种分层的容器设计方案下,请求处理是很简单的,重点在前期的请求接收及I/O处理(Processor的各种实现)、Mapper的映射以及Wrapper中的规范处理。


4、Tomcat的优化
最后一点内容,我们再概要介绍一下Tomcat的优化。今天介绍的相对比较基础,大家感兴趣的还是需要去看相关的专门的书籍。

Tomcat优化主要但不限于以下四个方面:线程池、协议、JVM以及I/O,之所以说不限于,是因为应用服务器的优化,不仅要去优化其自身,诸如操作系统等也是要统一考虑的。


线程池就是我们刚才说的两类。接收线程池一般都是CPU内核数即可。当然如果服务器核数非常多,可以适当调小。这个线程池处理速度比请求处理线程池要快的多,因此要考虑这两者的匹配,原因PPT中都介绍了。


做请求处理线程池这个设置时,较好做一些基准测试,并没有什么较精确的经验值。

协议层面。这个最常见的就是开启HTTP GZip压缩。如果配置了前置的Web服务器,那么静态文件可以考虑直接放到Web服务器上,然后可以修改HTTP链接器的I/O方式。新版本的Tomcat默认是NIO,可以改为APR,后者可以充分发挥本地调用的优势,与直接使用Apache基本是类似的。


当然对于前置了Web服务器的,可以采用AJP协议与Web服务器链接。Apache应该没问题,Nginx好像没有官方的AJP实现。第三方的就需要考虑健壮性和支持程度了。


然后是JVM,这部分估计最常见的就是调整JVM的堆内存。对于垃圾回收算法,也需要根据具体的应用场景进行调整。是吞吐量优先还是响应时间优先,需要使用多少线程去处理,这些都需要在具体的硬件配置下进行具体的测试才行。


今天的内容到此就结束了,主要内容还是非常概要,每一部分大家如果想深入了解,都需要去阅读相关书籍。协议、规范、JVM,这些都是必不可少的。

欢迎加入本站公开兴趣群
软件开发技术群
兴趣范围包括:Java,C/C++,Python,PHP,Ruby,shell等各种语言开发经验交流,各种框架使用,外包项目机会,学习、培训、跳槽等交流
QQ群:26931708

Hadoop源代码研究群
兴趣范围包括:Hadoop源代码解读,改进,优化,分布式系统场景定制,与Hadoop有关的各种开源项目,总之就是玩转Hadoop
QQ群:288410967 
2

鲜花

握手

雷人

路过

鸡蛋

刚表态过的朋友 (2 人)

相关阅读

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

 

GMT+8, 2018-12-17 18:25 , Processed in 0.151571 second(s), 24 queries .