(二期)16、tomcat的整体架构与session共享方案

【课程16】tomcat...共享.xmind47.6KB

【课程16】tomcat...流程.xmind0.6MB

【课程16】tomcat...组件.xmind0.6MB

【课程16】tomcat...架构.xmind0.9MB

【课程16】手写一...mcat.xmind0.1MB

【课程16预习】tom...架构.xmind0.6MB

课程目标:

  • 理解tomcat的基本组成与工作流程
  • 学会手动写一个迷你tomcat

讲课顺序

  • tomcat简介
  • 整体架构
  • 架构组成了解
  • 工作流程
  • 两大组件
  • 手写一个简易tomcat
  • 优化方向
  • tomcat的session插件演示
tomcat维基百科

Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等。

由于Tomcat本身也内含了一个HTTP服务器,它也可以被视作一个单独的Web服务器。

http server与tomcat

划重点:

  • http server与application server的不一样在哪?

严格的来说,Apache/Nginx 应该叫做「HTTP Server」;而 Tomcat 则是一个「Application Server」,或者更准确的来说,是一个「Servlet/JSP」应用的容器。

一个 HTTP Server 关心的是 HTTP 协议层面的传输和访问控制,所以在 Apache/Nginx 上你可以看到代理、负载均衡等功能。客户端通过 HTTP Server 访问服务器上存储的资源(HTML 文件、图片文件等等)。一个 HTTP Server 始终只是把服务器上的文件如实的通过 HTTP 协议传输给客户端。

对于 Tomcat 来说,就是需要提供 JSP/Sevlet 运行需要的标准类库、Interface 等。为了方便,应用服务器往往也会集成 HTTP Server 的功能,但是不如专业的 HTTP Server 那么强大,所以应用服务器往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server 分发到客户端。

HTTP服务器本质上也是一种应用程序——它通常运行在服务器之上,绑定服务器的IP地址并监听某一个tcp端口来接收并处理HTTP请求。

Tomcat运行在JVM之上,它和HTTP服务器一样,绑定IP地址并监听TCP端口,同时还包含以下指责:

  • 管理Servlet程序的生命周期
  • 将URL映射到指定的Servlet进行处理
  • 与Servlet程序合作处理HTTP请求——根据HTTP请求生成HttpServletRequest对象并传递给Servlet进行处理,将Servlet中的HttpServletResponse对象生成的内容返回给浏览器。
tomcat的整体架构
整体架构

划重点:

  • 主要两个组件是哪两个?
  • 两个重要组件的功能分别是啥?

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

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

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

其他组件说明:

  • Jasper:负责jsp页面的解析,jsp属性的验证,同时负责将jsp动态转换为java代码并编译成class。
  • Naming:资源管理,负责数据库连接池、EJB、mail等通过JDNI获取的内容。
  • Session:会话管理的组件
  • Logging:日志相关
  • JMX:性能监控等

小结:

(1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个Connector和一个Container;

(2)Server掌管着整个Tomcat的生死大权;

(4)Service 是对外提供服务的;

(5)Connector用于接受请求并将请求封装成Request和Response来具体处理;

(6)Container用于封装和管理Servlet,以及具体处理request请求;

两大组件 --- Connector

划重点:

  • connector的工作流程?
  • connector有哪些优化手段?
基本功能

一个Connecter将在某个指定的端口上侦听客户请求,接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理Engine(Container中的一部分),从Engine出获得响应并返回客户。

Tomcat中有两个经典的Connector,

  • 一个直接侦听来自Browser的HTTP请求,
  • 另外一个来自其他的WebServer请求。

HTTP/1.1 Connector在端口8080处侦听来自客户Browser的HTTP请求,AJP/1.3 Connector在端口8009处侦听其他Web Server(其他的HTTP服务器)的Servlet/JSP请求。

Connector 最重要的功能就是接收连接请求然后分配线程让 Container 来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。

Connector 中具体是用ProtocolHandler 来处理请求的,不同的ProtocolHandler 代表不同的连接类型,比如, Http11Protocol 使用的是普通Socket 来连接的, Http 11 NioProtocol 使用的是NioSocket 来连接的。

ProtocolHandler 里面有3 个非常重要的组件: Endpoint 、Processor 和Adapter。

  • Endpoint用于处理底层Socket 的网络连接,
  • Acceptor 用于监昕请求
  • AsyncTimeout 用于检查异步request 的超时
  • Handler 用于处理接收到的Socket,在内部调用了Processor 进行处理。
  • Processor 用于将Endpoint 接收到的Socket 封装成Request,
  • Adapter 用于将封装好的Request 交给Container 进行具体处理。

也就是说Endpoint用来实现TCP/IP 协议, Processor 用来实现HTTP 协议, Adapter 将请求适配到Servlet 容器进行具体处理。

优化方向

在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,就是在这里做优化。 可以说,Servlet容器处理请求,是需要Connector进行调度和控制的,Connector是Tomcat处理请求的主干 ,因此Connector的配置和使用对Tomcat的性能有着重要的影响。

优化包括NIO/BIO模式、线程池、连接数等。

优化一:指定protocol -- BIO、NIO、NIO2,APR。

如果没有指定protocol,则使用默认值HTTP/1.1,其含义如下:

  • 在Tomcat7中,自动选取使用BIO或APR(如果找到APR需要的本地库,则使用APR,否则使用BIO);
  • 在Tomcat8中,自动选取使用NIO或APR(如果找到APR需要的本地库,则使用APR,否则使用NIO)。

优化二:3个参数:acceptCount、maxConnections、maxThreads

当客户端向服务器发送请求时,如果客户端与OS 完成三次握手建立了连接,则OS 将该连接放入accept 队列。

对应三个节点,请求进入accept队列中,请求获取到链接,请求获得线程处理请求。

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" acceptCount="2" maxConnections="10" maxThreads="2"
           connectionTimeout="20000"
           redirectPort="8443" />
  • 1、acceptCount

accept队列的长度;当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100。

acceptCount的设置,与应用在连接过高情况下希望做出什么反应有关系。如果设置过大,后面进入的请求等待时间会很长;如果设置过小,后面进入的请求立马返回connection refused。

  • 2、maxConnections

Tomcat在任意时刻接收和处理的最大连接数。当Tomcat接收的连接数达到maxConnections时,Acceptor线程不会读取accept队列中的连接;这时accept队列中的线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections。如果设置为-1,则连接数不受限制。

maxConnections的设置与Tomcat的运行模式有关。

  1. 如果tomcat使用的是BIO,那么maxConnections的值应该与maxThreads一致;
  1. 如果tomcat使用的是NIO,那么类似于Tomcat的默认值,maxConnections值应该远大于maxThreads。
  • 3、maxThreads

请求处理线程的最大数量。默认值是200(Tomcat7和8都是的)。如果该Connector绑定了Executor,这个值会被忽略,因为该Connector将使用绑定的Executor,而不是内置的线程池来执行任务。

优化三:线程池Executor

Executor元素代表Tomcat中的线程池,可以由其他组件共享使用;要使用该线程池,组件需要通过executor属性指定该线程池。

<Executor name="tomcatThreadPool" namePrefix ="catalina-exec-" maxThreads="150" minSpareThreads="4" />

<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" acceptCount="1000" />
  • name:该线程池的标记
  • maxThreads:线程池中最大活跃线程数,默认值200(Tomcat7和8都是)
  • minSpareThreads:线程池中保持的最小线程数,最小值是25
  • maxIdleTime:线程空闲的最大时间,当空闲超过该值时关闭线程(除非线程数小于minSpareThreads),单位是ms,默认值60000(1分钟)
  • daemon:是否后台线程,默认值true
  • threadPriority:线程优先级,默认值5
  • namePrefix:线程名字的前缀,线程池中线程名字为:namePrefix+线程编号

linux下的一些有用命令

netstat命令是一个监控TCP/IP网络的非常有用的工具

#查看连接情况
netstat -nat | grep 8080

1、LISTEN

服务侦听中(LISTEN)状态。

2、ESTABLISHED

ESTABLISHED的意思是建立连接。表示两台机器正在通信。

3、CLOSE_WAIT

对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭

4、TIME_WAIT

我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。

#获取tomcat的pid
ps -ef | grep tomcat

#查看该进程内有多少个线程
#其中,nlwp含义是number of light-weight process。
ps -o nlwp 32283

#ps -eLo pid ,stat可以找出所有线程,并打印其所在的进程号和线程当前的状态
#两个grep命令分别筛选进程号和线程状态;
#wc统计个数
ps -eLo pid,stat | grep 32283| grep running | wc -l

(pid是32283)

(该进程内有32个线程)

(查看进程的运行情况,SL表示空闲)

(筛选出运行中的线程,结果是0)

两大组件 --- Container

划重点:

  • container的每一个组件分别代表着项目的那些部分?
  • 注意组件之间的上下隶属关系
组成部分

Container用于封装和管理Servlet,以及具体处理Request请求,在Connector内部包含了4个子容器

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

(1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;

(2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;

(3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;

(4)Wrapper:每一Wrapper封装着一个Servlet;

tomcat的基本工作流程

划重点

  • tomcat的工作流程是怎么样的?
  • 能否根据流程抽象一些重要步骤出来?

如何确定请求由谁处理?

当请求被发送到Tomcat所在的主机时,如何确定最终哪个Web应用来处理该请求呢?

(1)根据协议和端口号选定Service和Engine

Service中的Connector组件可以接收特定端口的请求,因此,当Tomcat启动时,Service组件就会监听特定的端口。在第一部分的例子中,Catalina这个Service监听了8080端口(基于HTTP协议)和8009端口(基于AJP协议)。当请求进来时,Tomcat便可以根据协议和端口号选定处理请求的Service;Service一旦选定,Engine也就确定。

通过在Server中配置多个Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。

(2)根据域名或IP地址选定Host

Service确定后,Tomcat在Service中寻找名称与域名/IP地址匹配的Host处理该请求。如果没有找到,则使用Engine中指定的defaultHost来处理该请求。在第一部分的例子中,由于只有一个Host(name属性为localhost),因此该Service/Engine的所有请求都交给该Host处理。

(3)根据URI选定Context/Web应用

这一点在Context一节有详细的说明:Tomcat根据应用的 path属性与URI的匹配程度来选择Web应用处理相应请求,这里不再赘述。

(HTTP请求过程)

Tomcat Server处理一个HTTP请求的过程

1、用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。

2、Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。

3、Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。

4、Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。

5、path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。

6、构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。

7、Context把执行完之后的HttpServletResponse对象返回给Host。

8、Host把HttpServletResponse对象返回给Engine。

9、Engine把HttpServletResponse对象返回Connector。

10、Connector把HttpServletResponse对象返回给客户Browser。

一些相关图

(配置文件server.xml)

(tomcat的组件启动流程图)

手写一个迷你tomcat

代码作者:张丰哲  https://www.jianshu.com/p/dce1ee01fb90

  • 需求

编写一个迷你tomcat

  • 需求分析

tomcat是一个专门处理servlet的web容器。前提需要了解tomcat的工作原理与流程。

一般容器处理流程是这样的,客户端发起请求,web容器接受请求,处理请求,然后把得到结果返回给客户端。

所以提取要点如下:

  • 请求端口监控
  • 把请求的信息封装起来
  • 请求处理
  • 把响应结果封装起来

因此至少需要以下几个类

  • Request 封装请求
  • Servlet 请求处理的Servlet
  • Response 封装响应结果
  • MyTomcat 启动监控和处理服务

以上可以说我们已经设计出了一个超级简单的tomcat,但是这个tomcat有点局限性,只有一个servert, 也就是说,这个tomcat只能处理一个url,为了让服务器能够处理多个servlet,我们必须抽象封装servlet。 请求url与servelt是一一对应关系,所以,我们可以通过一个map把这些关系在启动过程中就初始化加载进来, 因此我们可以封装一个ServletMapping类用于封装映射关系, 然后初始化的话可以放在一个config类中统一管理(真实的tomcat是直接在web.xml配置映射关系) 因此又多了两个类

  • ServletMapping 封装url与Servlet的对应关系
  • ServletMappingConfig 配置项目的Servlet与Url关系,用于初始化

然后,现在可以通过url找到对应的servlet了,每个Servrt的结构应该一直,因此抽象一个MyServlet类,固定处理的方法是service(); 后面添加业务处理的时候都要继承这个MyServlet抽象类。比如我要加一个HelloWorldServlet,对应url是"/hello", 我就需要显示MyServlet抽象类,编写业务逻辑,然后在ServletMappingConfig中配置映射关系。

现在好了,我编写了很多url对应的servelt,如果找不到url,我应该抛出404错误,这个我们先跳过。 当我获取到url对应的servelt名称之后,现在又有一个问题来了,我如何去运行这个servlet的service()业务代码呢? 同学们可能说直接new HelloWorldServlet().service()不就行了么,这里涉及到一个问题,因为后面业务越来越多,需要的servelt也越来越多, 所以不可能全部通过一个个去判断然后new对象,这时候我们自然想到可以通过反射方式获取servlet实例,然后调用service(); 所以在tomcat的处理请求阶段,我们可以通过反射方式去调用业务逻辑。

至此。需求分析完毕。

具体代码请看具体项目。

为什么要实现session共享

我们使用单台Tomcat的时候不会有共享sesssion的疑虑,只要使用Tomcat的默认配置即可,session即可存储在Tomcat上。

但是随着业务的扩大,增加Tomcat节点构成Tomcat集群大势所趋,分布式带来了增加更大规模并发请求的优势,但是也随之到来了一个问题,每个Tomcat只存储来访问自己的请求产生的session,如果Tomcat-A已经为客户端C创建了会话session,那么Tomcat-B并不知道客户端已与集群中的Tomcat-A产生了会话,在访问时就会为C再创建一份session,如果是基于session的验证会话权限的接口(如用户登录认证后才可访问的数据接口),将会导致在访问集群中不同节点的时候重复认证。session的不共享导致原来的会话管理机制在Tomcat集群中无法工作。

tomcat中的session是如何工作的

深度好文:https://www.cnblogs.com/kismetv/p/7228274.html

tomcat集群环境下实现session共享的几种方式

第一种:粘性session,基于nginx的ip-hash,当前用户的请求都集中定位到一台服务器中,这样单台服务器保存了用户的session登录信息。

第二种:session复制共享:sessionreplication,如tomcat自带session共享,主要是指集群环境下,多台应用服务器之间同步session,使session保持一致,对外透明。

第三种:基于cache DB缓存的session共享,比如基于 memcache/redis缓存的 session 共享。

注意点,只支持tomcat7,tomcat8以上不支持。

实现过程

第一步:首先导入相关的jar包到tomcat的lib文件夹中,如redis和tomcat关联的jar包,redis的包等。

commons-pool2-2.2.jar0.1MB

tomcat-redis-session-m....0.0.jar21KB

jedis-2.5.2.jar0.3MB

第二步:配置tomcat。打开context.xml,在<Context>标签内添加如下代码,其中,host是redis的ip,port是端口。:

context.xml1.7KB

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
 <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" host="localhost"  port="6379" database="0" maxInactiveInterval="60" />

第三步:接下来就是可以直接把项目放在webapp下面运行项目啦,你会发现,tomcat的session信息已经存到redis中。多个tomcat可以改变端口,然后用nginx做下负载均衡,可以随时切换tomcat,然后session已经共享了。

index.jsp0.6KB

  • 试验大环境:(分别8080,8081端口)

https://pan.baidu.com/s/1IXyXGgkGkHqLNKmyewGF1A

(转)tomcat架构&session共享的更多相关文章

  1. 高级运维(五):构建memcached服务、LNMP+memcached、使用Tomcat设置Session、Tomcat实现session共享

    一.构建memcached服务 目标: 本案例要求先快速搭建好一台memcached服务器,并对memcached进行简单的添.删.改.查操作: 1> 安装memcached软件,并启动服务d ...

  2. 配置tomcat的session共享

    可通过下面方法限制一个用户访问一个服务器之后就只在该服务器上操作. 请求负载过程中会话信息不能丢失.那么在多个tomcat中session需要共享. 配置tomcat的session共享可以有三种解决 ...

  3. Apache代理Tomcat实现session共享构建网上商城系统

    一.环境介绍 二.安装配置后端服务器 三.安装配置前端服务器 四.配置Tomcat服务器实现session共享 五.构建网上商城系统 一.环境介绍 系统版本:CentOS 6.4_x86_64 Mys ...

  4. 浅谈负载均衡之【tomcat分布式session共享】

    1)整理集成所需jar kryo-1.0.3.jar kryo-serializers-0.8.jar memcached-2.4.2.jar memcached-session-manager-1. ...

  5. apache+tomcat实现session共享

    apache+tomcat上篇文章,实现了负载均衡,现在我们实现session共享 一.tomcat集群配置,session 同步配置: tomcat1配置  A.修改Engine节点信息: < ...

  6. memached实现tomcat的session共享

    由于项目服务器用的阿里云的ECS,Memcached也采用的阿里云.多个tomcat集群的session都存储在一个云memcached中. 配置步骤如下: 一.tomcat增加memcached支持 ...

  7. Tomcat中session共享问题的简单解决办法

    tomcat-redis-session-manager 使用redis配置tomcat共享session 结构图: 分析: 分布式web server集群部署后需要实现session共享,针对 to ...

  8. tomcat memecached session 共享同步问题的解决

    事件缘由:一个主项目“图说美物”,另外一个子功能是品牌商的入驻功能,是跟主项目分开的项目,为了共享登录的用户信息,而实现session共享,俩个tomcat,一个tomcat6,一个tomcat7 w ...

  9. Memcached做Tomcat的session共享

    基于cache DB缓存的session共享 基于memcache/redis缓存的session共享.即使用cacheDB存取session信息,应用服务器接受新请求将session信息保存在cac ...

随机推荐

  1. qq浏览器默认字体设置

  2. Runtime(IV) - 序列化与反序列化

    准备条件 父类 Biology Biology.h #import <Foundation/Foundation.h> @interface Biology : NSObject { NS ...

  3. 动态创建 Plist 文件

    简介 Property List,属性列表文件,它是一种用来存储串行化后的对象的文件.属性列表文件的扩展名为.plist ,因此通常被称为 plist文件,文件是xml格式的. 写入plist文件 在 ...

  4. DNN模型训练词向量原理

    转自:https://blog.csdn.net/fendouaini/article/details/79821852 1 词向量 在NLP里,最细的粒度是词语,由词语再组成句子,段落,文章.所以处 ...

  5. Java综合高级篇

    1.你用过哪些集合类? 大公司最喜欢问的Java集合类面试题 40个Java集合面试问题和答案 java.util.Collections 是一个包装类.它包含有各种有关集合操作的静态多态方法. ja ...

  6. linux常用命令:pwd 命令

    Linux中用 pwd 命令来查看”当前工作目录“的完整路径. 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录.在不太确定当前位置时,就会使用pwd来判定当前目录在文件系统内的确切位置. ...

  7. SQL优化(转)

    1. 负向条件查询不能使用索引 select * from order where status!=0 and stauts!=1 not in/not exists都不是好习惯 可以优化为in查询: ...

  8. Linux基础命令---修改用户信息usermod

    usermod 修改用户的信息,包括用户名.密码.家目录.uid等. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.Fedora. 1.语法 use ...

  9. Git从远程仓库里拉取一条本地不存在的分支方法

    Git从远程仓库里拉取一条本地不存在的分支方法 从远程仓库里拉取一条本地不存在的分支时,进入到对应目录先执行git fetch然后再执行git checkout -b 本地分支名 origin/远程分 ...

  10. go语言,golang学习笔记2 web框架选择

    go语言,golang学习笔记2 web框架选择 用什么go web框架比较好呢?能不能推荐个中文资料多的web框架呢? beego框架用的人最多,中文资料最多 首页 - beego: 简约 & ...