1、描述Tomcat的架构;
核心架构图:
架构简介:
- Server是管理Service接口的,是Tomcat的一个顶级容器。管理着多个Service;
- Service 是服务,管理着一个Container和多个Connector,Service的存在依赖于Server;
- Container : 一个或者多个Container 可以对应一个Connector,这样就组成了一个Service,Service生命周期的由Server进行管理;
- Container和Connector之间的交互媒介是Service,一个Service可以对应多个Connector,但是只能有一个Container容器。
核心类:
Tomcat容器结构图:
Tomcat常用组件介绍:
- Server:tomcat实例,即运行的一个jvm进程;监听于8005端口接收“SHUTDOWN”。各server监听的端口不能相同;因此,一个物理主机上启动多个server实例应该使用不同的端口;
- service:用于实现将一个或多个connector关联至一个engine;
- connector:进入tomcat的请求可分为两类:
- tomcat作为独立的应用程序服务器:standalone,此时,请求将来自于浏览器;
- tomcat作为应用程序服务器:请求将来自于前面的反代主机;
- Engine:Servlet的一个实例,即servlet引擎,其内部可以有一个或多个Host组件来定义站点;通常需要通过defaultHost的属性定义默认虚拟主机;
- Host组件:位于Engine容器中用于接收请求并进行相应处理的主机或虚拟主机;
- Context组件:Context在某些意义上类似于apache中的路径别名,一个Context定义用于标识tomcat实例中的一个Web应用程序;
- Realm组件:一个Realm表示一个安全上下文,它是一个授权访问某个给定Context的用户列表和某用户所允许切换的角色相关定义的列表。因此,Realm就像是一个用户和组相关的数据库。定义Realm时惟一必须要提供的属性是classname,它是Realm的多个不同实现,用于表示此Realm认证的用户及角色等认证信息的存放位置。
- Valve类似于过滤器,它可以工作于Engine和Host/Context之间、Host和Context之间以及Context和Web应用程序的某资源之间。一个容器内可以建立多个Valve,而且Valve定义的次序也决定了它们生效的次序。
Tomcat的目录结构:
- 脚本及启动时用到的类;
- lib:类库;
- conf:配置文件;
- logs:日志文件;
- webapps:webapp默认的部署目录;
- work:工作目录;
- temp:临时文件目录
2、详细解释Tomcat的配置文件及配置文件中的参数所代表的含义;
Tomcat的配置文件:
- server.xml:主配置文件
- context.xml:每个webapp都可以有专用的配置文件,这些配置文件通常位于webapp应用程序自己的目录下的WEB-INF目录中;此context.xml为每个webapp提供默认配置;
- web.xml:每个webapp只有在“部署”后才能被访问,此文件则用于为各webapps定义默认的部署方式;
- tomcat-users.xml:用户认证的帐号和密码文件;
- catalina.policy:当使用-security选项来启动tomcat实例时,会读取此配置文件来实现基于安全策略的运行方式;
- catalina.properties:java属性的定义文件,用于设定类加载器路径,以及一些与JVM调优相关的参数等;
- logging.propeties:日志系统相关的配置;
元素名 | 属性 | 解释 |
Server | className | 这个类必须是org.apache.catalina.Server的实现类,如果没有指定类名,则使用标准实现。 |
address | 这是等待关闭命令的TCP/IP地址,如果没有指定,默认使用localhost。 | |
port | 这个端口是用于接收关闭服务的端口,可以设置为-1来禁用。 | |
shutdown | 这个命令字符串必须通过TCP/IP端口接收,才能关闭Tomcat。 | |
Service | className | 这个类必须是org.apache.catalina.Service的实现类。 |
name | Service的展示名称,如果使用标准的Catalina组件,这个名称会包含在日志信息中。同一个Server下的每个Service的名称必须唯一。 | |
Connector | allowTrace | 是否允许TRACE HTTP方法,默认false。 |
asyncTimeout | 异步请求超时时间,单位毫秒,默认10000ms(10秒)。 | |
enableLookups | 如果想使用request.getRemoteHost()方法通过DNS查找远程请求客户端的真实的主机名,则设置为true。设置为false会跳过DNS查找,直接返回IP地址。DNS查找默认禁用。 | |
maxHeaderCount | 一个请求允许最大的请求头数量。如果超出限制请求会被拒绝。如果为负值,无限制。默认值100。 | |
maxParameterCount | GET和POST请求的参数(和值)的最大数量,超出的参数会被忽略。如果是0或者小于0,表示无限制。默认为10000。 | |
maxPostSize | POST请求的最大字节数。如果为负,无限制。默认2097152字节(即2Mb)。 | |
maxSavePostSize | POST请求的最大保存/缓冲字节数。-1表示无限制,0表示禁用保存/缓冲,默认为4096字节(4Kb)。 | |
port | TCP端口,用于创建Server socket并等待进入连接。操作系统允许1个服务器监听1个IP的1个指定端口。如果值为0,Tomcat会为这个Connector选择一个随机的空闲端口。 | |
protocol |
通信协议。默认为HTTP/1.1,这个协议使用自动切换机制来选择阻塞式基于Java的Connector或者基于APR/native的Connector。如果要使用明确的协议,而不是自动切换机制选择的协议,可以选择下面的值:
|
|
proxyName | 如果当前Connector使用代理配置,使用这个属性指定Server名称。这个Server名称,可以调用request.getServerName()方法返回。 | |
proxyPort | 指定代理的Server端口。 | |
redirectPort | 如果当前Connector不支持SSL请求,但是收到的请求匹配web.xml中配置的security-constraint选项,要求使用SSL端口,那么Catalina会自动把请求转发到这个指定端口。 | |
scheme | 给当前协议设置一个名字,这样可以通过request.getScheme()方法获得协议名词,比如给SSL协议取名HTTPS。默认值为http。URIEncoding:字符编码。用于URI字节解码,和URL %xx部分数据的解码。默认为ISO-8859-1。 | |
useIPVHosts | 将该属性设置为true会导致Tomcat使用收到请求的IP地址,来决定将请求发送到哪个主机。默认false。 | |
acceptCount | 当所有的可用线程都在使用中,传入连接请求队列的最大长度。当队列满时,任何请求都会被拒绝。默认100。 | |
address | 如果服务器有多个IP,这个属性指定使用哪个IP地址用于监听端口。默认使用与服务器关联的全部IP地址。 | |
compressableMimeType | HTTP压缩的元数据类型,参数可以使用逗号间隔。默认为text/html,text/xml,text/plain,text/css,text/javascript,application/javascript。 | |
compression |
为了节省服务器带宽,Connector可以使用HTTP/1.1 GZIP压缩。
|
|
compressionMinSize | 当compression设置为on,指定压缩前的最小数据量。默认为2048。 | |
connectionTimeout | 连接超时时间。-1表示无限制。默认值60000ms(60秒)。但server.xml默认配置为20000。 | |
disableUploadTimeout | 是否禁用上传超时时间,开启后,上传数据的连接使用单独的超时时间。 | |
connectionUploadTimeout | 上传数据时,连接超时时间。 | |
executor | 指向Executor元素的引用。如果设置了这个元属性,并且对应的Executor存在,Connector将使用这个Executor,而其他所有线程相关属性将被忽略。如果未指定此属性,Connector会使用一个私有的、内部Executor来提供线程池。 | |
executorTerminationTimeoutMillis | 在关闭Connector之前,那个私有的、内部Executor等待请求处理线程的终结的超时时间。BIO Connector默认值为0ms。NIO和APR/native Connector默认值为5000ms。 | |
keepAliveTimeout | 长连接超时时间。Connector在关闭连接之前,会等待另一个HTTP请求的时间。默认值是connectionTimeout的属性值。-1无超时时间。 | |
maxKeepAliveRequests | HTTP请求最大长连接数量。如果值为1,禁用长连接。设为-1,无限制。默认值为100。 | |
maxConnections | 在任何给定的时间服务器接收并处理的最大连接数。当这个数字已经达到了,服务器将不会接受任何连接,直到连接的数量降到低于此值。基于acceptCount,操作系统可能仍然接收连接。 | |
maxHttpHeaderSize | 请求头和响应头的最大字节数。默认8192(8Kb) | |
maxThreads | 最多同时处理的请求的最大线程数量,这决定了同时处理请求的最大数量。默认200。 | |
minSpareThreads | 最小空闲线程数量。默认10。 | |
socketBuffer | Socket输出缓冲区大小。单位字节。-1表示禁用缓冲区。默认值9000字节。 | |
SSLEnabled | 是否开启SSL加密传输。需要配置secure和scheme属性。 | |
Context | cookies | 是否使用cookie,可以通过cookie鉴别session。默认true。设置为false,则无法使用cookie完成session鉴证,然后必须依赖于URL重写。 |
docBase | 应用程序文件的根目录。如果应用程序不在Host元素的appBase路径下,需要设置此属性。 | |
path | 应用程序的访问路径(context path)。 | |
reloadable | 自动重新加载class和jar文件。设置为true,Catalina会监视/WEB-INF/classes/ 和/WEB-INF/lib目录下的变动,如果检测到变动就会自动重新加载应用程序。此功能非常有用但是不建议在生产环境使用。 | |
Engine | defaultHost | 默认的主机名,它必须指向一个Host元素的name属性。 |
name | Engine的逻辑名称,用于日志和错误信息。如果在一个Server中使用多个Service元素,每个Engine必须使用唯一的名称。 | |
jvmRoute | 在负载均衡场景中使用,用以实现会话黏性,此标识在参与集群的所有节点上必须唯一; | |
Host | appBase | 此Host的webapps目录,即存放非归档的web应用程序的目录或归档后的WAR文件的目录路径;可以使用基于$CATALINA_HOME的相对路径; |
name | 一般是虚拟主机注册到DNS的网络名称。必须有一个Host的name作为Engine的defaultHost。 | |
autoDelploy | 在Tomcat处于运行状态时放置于appBase目录中的应用程序文件是否自动进行deploy;默认为true; | |
unpackWars | 在启动此webapps时是否对WAR格式的文档文件先进行展开;默认为true; | |
Realm | JAASRealm | 基于Java Authintication and Authorization Service实现用户认证; |
JDBCRealm | 通过JDBC访问某关系型数据库表实现用户认证; | |
JNDIRealm | 基于JNDI使用目录服务实现认证信息的获取; | |
MemoryRealm | 查找tomcat-user.xml文件实现用户信息的获取; | |
UserDatabaseRealm | 基于UserDatabase文件(通常是tomcat-user.xml)实现用户认证,它实现是一个完全可更新和持久有效的MemoryRealm,因此能够跟标准的MemoryRealm兼容;它通过JNDI实现; | |
Valve | AccessLogValve | 访问日志Value; |
ExtendedAccessValve | 扩展功能的访问日志Valve; | |
JDBCAccessLogValve | 通过JDBC将访问日志信息发送到数据库中; | |
RequestDumperValve | 请求转储Valve; | |
RemoteAddrValve | 基于远程地址的访问控制; | |
RemoteHostValve | 基于远程主机名称的访问控制; | |
SemaphoreValve | 用于控制Tomcat主机上任何容器上的并发访问数量; | |
JvmRouteBinderValve | 在配置多个Tomcat为以Apache通过mod_proxy或mod_jk作为前端的集群架构中,当期望停止某节点时,可以通过此Valve将用记请求定向至备用节点;使用此Valve,必须使用JvmRouteSessionIDBinderListener; | |
ReplicationValve | 专用于Tomcat集群架构中,可以在某个请求的session信息发生更改时触发session数据在各节点间进行复制; | |
SingleSignOn | 将两个或多个需要对用户进行认证webapp在认证用户时连接在一起,即一次认证即可访问所有连接在一起的webapp; | |
ClusterSingleSingOn | 对SingleSignOn的扩展,专用于Tomcat集群当中,需要结合ClusterSingleSignOnListener进行工作; |
3、配置apache通过mod_proxy模块与Tomcat连接的详细过程;
环境:
apache代理服务器:192.168.0.20
tomcat服务器:192.168.0.22
1.后端tomcat配置
######安装jdk###### ~]# rpm -ivh jdk-7u79-linux-x64.rpm ~]# vim /etc/profile.d/java.sh export JAVA_HOME=/usr/java/latest export PATH=$JAVA_HOME/bin:$PATH ~]# source /etc/profile ~]# java -version java version "1.7.0_79" Java(TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode) ######安装tomcat###### ~]# yum install tomcat tomcat-lib tomcat-admin-webapps tomcat-webapps -y ######修改tomcat配置文件,在默认Host类中添加Context###### ~]# vim /etc/tomcat/server.xml ... <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="/test" docBase="testapp"/> ... #######创建webapp特有的目录结构######### ~]# cd /var/share/tomcat/webapps/ ~]# mkdir /testapp/{classes,lib,WEB-INF,META-INF} -p #######创建jsp探测页面######## ~]# vim testapp/index.jsp <%@ page language="java" %> <%@ page import="java.util.*" %> <html> <head> <title>JSP Test Page</title> </head> <body> <% out.println("Tomcat_A_22"); %> </body> </html> ~]# systemctl start tomcat.service ######在客户端访问tomcat服务器正常###### ~]# curl 192.168.0.22:8080/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_A_22 </body> </html>
2.前端apache代理配置
~]# yum install httpd -y ######请先确保httpd包含了http协议的代理模块###### ~]# httpd -M ... proxy_http_module (shared) ######创建一个代理虚拟主机###### ~]# vim /etc/httpd/conf/httpd.conf #DocumentRoot "/var/www/html" #注释掉该行 ~]# vim /etc/httpd/conf.d/http_tomcat.conf <VirtualHost *:80> ServerName tc1.magedu.com ProxyRequests Off ProxyVia On ProxyPreserveHost On <Proxy *> Require all granted </Proxy> ProxyPass / http://192.168.0.22:8080/ ProxyPassReverse / http://192.168.0.22:8080/ <Location /> Require all granted </Location> </VirtualHost> ~]# systemctl start httpd.service ######在客户端访问apache代理###### ~]# curl 192.168.0.20/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_A_22 </body> </html>
4、配置基于mod_jk的负载均衡;
环境:
apache代理服务器(mod_jk):192.168.0.20
tomcat服务器A:192.168.0.22
tomcat服务器B:192.168.0.23
1.后端tomcat服务器配置
######修改Host类,添加jvmRoute属性###### #Tomcat_A: ~]# vim /etc/tomcat/server.xml ... <Host name="localhost" appBase="webapps jvmRoute="TomcatA"" #jvmRoute值要与workers.properties中节点名称一致 unpackWARs="true" autoDeploy="true"> <Context path="/test" docBase="testapp"/> ... #Tomcat_B: ~]# vim /etc/tomcat/server.xml ... <Host name="localhost" appBase="webapps jvmRoute="TomcatB"" unpackWARs="true" autoDeploy="true"> <Context path="/test" docBase="testapp"/> ... ~]# systemctl restart tomcat.service
2.前端apache代理服务器配置
########安装mod_jk模块########### ~]# yum groupinstall "Development Tools" "Server Platform Development" -y~]# yum install httpd-devel -y
~]# tar xf tomcat-connectors-1.2.40-src.tar.gz ~]# cd tomcat-connectors-1.2.40-src ~]# ./configure --with-apxs=/usr/bin/apxs ~]# make && make install ########创建mod_jk模块配置文件########## ~]# vim /etc/httpd/conf.d/mod_jk.conf LoadModule jk_module modules/mod_jk.so JkWorkersFile /etc/httpd/conf.d/workers.properties JkLogFile logs/mod_jk.log JkLogLevel debug JkMount /* tcsrvs JkMount /jk_status StatA #########修改worker配置文件########## ~]# vim /etc/httpd/conf.d/workers.properties worker.list=tcsrvs,StatA #将tcsrvs组加入worker.list worker.TomcatA.host=192.168.0.22 worker.TomcatA.port=8009 worker.TomcatA.type=ajp13 worker.TomcatA.lbfactor=1 #设置后端节点的权重 worker.TomcatB.host=192.168.0.23 worker.TomcatB.port=8009 worker.TomcatB.type=ajp13 worker.TomcatB.lbfactor=1 worker.tcsrvs.type=lb #定义tcsrvs类型为lb worker.tcsrvs.balance_workers=TomcatA,TomcatB #指定tcsrvs组成员 worker.StatA.type=status ~]# systemctl reload httpd.service ######在客户端上进行测试###### ~]# curl 192.168.0.20/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_A_22 </body> </html> ~]# curl 192.168.0.20/test/ <html> <head> <title>JSP Test Page</title> </head> <body> Tomcat_B_23 </body> </html> ######成功实现负载均衡!######
5、配置tomcat集群,能够实现用户的session会话保持。
环境:
apache代理服务器(mod_jk):192.168.0.20
tomcat服务器A:192.168.0.22
tomcat服务器B:192.168.0.23
1.前端apache代理仍使用上题的环境,这里不再赘述
2.后端两台tomcat服务器配置
#######修改tomcat配置文件,添加下面内容############# ~]# vim /etc/tomcat/server.xml ... <Engine name="Catalina" defaultHost="localhost" jvmRoute="TomcatA"> #Engine中要添加jvmRoute名称 <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <Manager className="org.apache.catalina.ha.session.BackupManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6"/> <!-- <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> --> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.101.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="192.168.0.22" #不同节点改为实际的地址 port="5000" selectorTimeout="100" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster> ... ########配置webapps,编辑WEB-INF/web.xml,添加<distributable/>########### ~]# cd /var/lib/tomcat/webapps/testapp/ ~]# cp /etc/tomcat/web.xml WEB-INF/ ~]# vim WEB-INF/web.xml ... <distributable/> ... systemctl start tomcat.service ######创建session id探测页面###### ~]# vim testapp/index.jsp <%@ page language="java" %> <html> <head><title>TomcatA</title></head> <body> <h1><font color="red">TomcatA.magedu.com</font></h1> <table align="centre" border="1"> <tr> <td>Session ID</td> <% session.setAttribute("magedu.com","magedu.com"); %> <td><%=session.getId() %></td> </tr> <tr> <td>Created on</td> <td><%=session.getCreationTime() %></td> </tr> </table> </body> </html>
使用浏览器访问代理服务器,可以看到虽然会话被负载均衡到了后端两个节点上,但是session id并没有改变!
注意:请确保各节点时间保持一致,否则可能导致session id发生变化!
原创文章,作者:N26-西安-方老喵,如若转载,请注明出处:http://www.178linux.com/78412
评论列表(1条)
博客总结非常赞,尤其是对tomcat内部的架构和容器结构,对于配置来说其实倒不是很难,主要是理解里面的流程才是王道。