服务器-Tomcat经验

文章目录
  1. 1. 服务器-Tomcat经验
    1. 1.1. 应用服务器和web服务器区别
    2. 1.2. 支持的并发(Tomcat只能顶几百的并发)
    3. 1.3. tomcat不遵守双亲委派
      1. 1.3.1. tomcat要解决的问题
      2. 1.3.2. tomcat如何设计自己独特的类加载机制
      3. 1.3.3. 为了实现隔离性
        1. 1.3.3.1. 我们扩展出一个问题:如果tomcat 的 Common ClassLoader 想加载 WebApp ClassLoader 中的类,该怎么办?

服务器-Tomcat经验

应用服务器和web服务器区别

应用服务器通过应用程序接口(通常是网络请求API)把业务逻辑暴露给客户端应用程序。而WEB服务器通过HTTP提供静态内容给浏览器等客户端。

Apache、Nginx、IIS、IHS(IBM HTTP SERVER)是目前最主流的三个Web服务器。

Tomcat、Jetty、WebLogic、Websphere、JBoss都是应用服务器。

支持的并发(Tomcat只能顶几百的并发)

负载均衡嘛,一台服务几百,那就多搞点。

Tomcat/conf/server.xml修改配置

1
2
3
4
5
6
7
8
9
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
  redirectPort="8443"
  URIEncoding="UTF-8"
  minSpareThreads="25"
  maxSpareThreads="300"
  maxThreads="500"
  acceptCount="500"
  connectionTimeout="30000"
  enableLookups="false"/>

maxIdleTime:最大空闲时间,超过这个空闲时间,且线程数大于minSpareThreads的,都会被回收,默认值1分钟(60000ms);
minSpareThreads:最小空闲线程数,任何情况都会存活的线程数,即便超过了最大空闲时间,也不会被回收,默认值4;
maxSpareThreads:最大空闲线程数,在最大空闲时间(maxIdleTime)内活跃过,此时空闲,当空闲时间大于maxIdleTime则被回收,小则继续存活,等待被调度,默认值50;
maxThreads:最大线程数,大并发请求时,tomcat能创建来处理请求的最大线程数,超过则放入请求队列中进行排队,默认值为200;
acceptCount:当最大线程数(maxThreads)被使用完时,可以放入请求队列排队个数,超过这个数返回connection refused(请求被拒绝)。默认1000。

假设响应时间是300ms,那1秒3请求,*maxThread,那就是600tps了。

正常一点服务器上的Tomcat都能达到5000甚至10000的并发。只不过在大多数的web应用中,任务执行时间并不会太短,而且还涉及到数据库操作,所以大部分情况下Tomcat的最高并发就只有几百。

tomcat不遵守双亲委派

既然 Tomcat 不遵循双亲委派机制,那么如果我自己定义一个恶意的HashMap,会不会有风险呢?(阿里的面试官问)

答: 显然不会有风险,如果有,Tomcat都运行这么多年了,那群Tomcat大神能不改进吗? tomcat不遵循双亲委派机制,只是自定义的classLoader顺序不同,但顶层还是相同的,还是要去顶层请求classloader.

tomcat要解决的问题

要解决什么问题:

  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机,这是扯淡的。
  3. web容器也有自己依赖的类库,不能于应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  4. web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情,否则要你何用? 所以,web容器需要支持 jsp 修改后不用重启。

tomcat如何设计自己独特的类加载机制

image-20210731190338417

  • commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  • catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
  • sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
  • WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;

为了实现隔离性

tomcat 违背了java 推荐的双亲委派模型了吗?答案是:违背了。 我们前面说过:

双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。

很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。

我们扩展出一个问题:如果tomcat 的 Common ClassLoader 想加载 WebApp ClassLoader 中的类,该怎么办?

看了前面的关于破坏双亲委派模型的内容,我们心里有数了,我们可以使用线程上下文类加载器实现,使用线程上下文加载器,可以让父类加载器请求

子类加载器去完成类加载的动作。就是虽然用了父,但实际还是用子类加载器完成。