Tomcat 动态资源服务器部署及应用
Java 2 EE 计数体系包含如 Serverlet , JSP , JMX 等等。
以OpenJDK为例,当前比较常用的有1.6.0、1.7.0、1.8.0等版本,当一台主机上有多个OpenJDK时,可使用 “alternatives” 命令设定默认使用的版本。
Java代码的运行:.java(source code) –> javac –> .class(bytecode)
JSP :Java Server Page
JSP Container : JSP + Servlet Container
基于jasper将静态输出的数据转为java代码进行输出,结果为servlet规范的代码
.jsp –>jasper–> .java –> javac –> .class –> jvmtomcat 是JSP Container的开源实现,tomcat是 Java 2 EE 技术体系的不完整实现,tomcat在使用前需要部署Java环境。
JSP Container 技术的商业实现包括:WebSphere, WebLogic, Oc4j, Glassfish, Geronimo, JOnAS, JBoss等等
JSP Container 技术的开源实现包括:Tomcat, Jetty, Resin
安装tomcat及软件依赖环境
- 使用rpm包方式安装,在Base仓库中
yum install -y java-1.8.0-openjdk tomcat tomcat-webapps tomcat-admin-webapps tomcat-docs-webapp
- 如果使用非yum方式安装完成后,要配置JAVA_HOME环境变量,指向java的安装路径
vim /etc/profile.d/java.sh
export JAVA_HOME=/usr
source /etc/profile.d/java.sh
echo $JAVA_HOME
Tomcat默认配置文件及结构框架:html语言嵌入式风格
tomcat的配置文件:
server.xml:主配置文件
web.xml:每个webapp只有“部署”后才能被访问,它的部署方式通常由web.xml进行定义,其存放位置为WEB-INF/目录中;此文件为所有的webapps提供默认配置
context.xml:每个web都可以专用的配置文件,它通常由专用的配置文件context.xml来定义,其存放位置为WEB-INF/目录中;此文件为所有的webapps提供默认配置
tomcat-users.xml:用户认证的账号和密码文件
==tomcat的主配置文件及各组件的框架结构详解==
tomcat主配置文件的默认配置实例:
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
组件详解:每个组件都由一个Java“类”实现,这些组件大体可分为以下几个类型:
顶级组件:Server
一个Server可包含多个Service
代表tomcat instance,即表现出的一个java进程;监听在8005端口,只接收“SHUTDOWN”。各server监听的端口不能相同,因此,在同一物理主机启动多个实例时,需要修改其监听端口为不同的端口;
服务类组件:Service
一个Service中仅能有一个Engine
一个Engine可对应多个Connector,但一个Connector仅能对应一个Engine
用于实现将一个或多个connector组件关联至一个engine组件
连接器组件:http, https, ajp
负责接收请求,常见的有三类http/https/ajp;
进入tomcat的请求可分为两类:
- standalone : 请求来自于客户端浏览器;
由其它的web server反代:来自前端的反代服务器;
- nginx –> http connector –> tomcat
- httpd(proxy_http_module) –> http connector –> tomcat
- httpd(proxy_ajp_module) –> ajp connector –> tomcat
Connector属性
port=”8080”
protocol=”HTTP/1.1”
connectionTimeout=”20000”
address:监听的IP地址;默认为本机所有可用地址
maxThreads:最大并发连接数,默认为200
enableLookups:是否启用DNS查询功能
acceptCount:等待队列的最大长度
容器类:Engine, Host, Context
一个Engine中可包含多个Host,一个Host中可包含多个Context
Engine组件:Servlet实例,即servlet引擎,其内部可以一个或多个host组件来定义站点,通常需要通过defaultHost来定义默认的虚拟主机
- Engine属性
name=” “
defaultHost=”localhost”
jvmRoute=” “
Host组件:位于engine内部用于接收请求并进行相应处理的主机或虚拟主机
Host属性
- appBase:此Host的webapps的默认存放目录(/var/lib/tomcat/webapps),指存放非归档的web应用程序的目录或归档的WAR文件目录路径;可以使用基于$CATALINA_BASE变量所定义的路径的相对路径
- autoDeploy:在Tomcat处于运行状态时,将某webapp放置于appBase所定义的目录中时,是否自动将其部署至tomcat
主配置文件==配置示例==:
#提供webapp和测试页面
mkdir -pv /appdata/webapps/ROOT/{lib,classes,WEB-INF,META-INF}
vim /appdata/webapps/ROOT/index.jsp
#增加以下内容
<%@ page language="java" %>
<html>
<head><title>TomcatA</title></head>
<body>
<h1><font color="red">TomcatA.achudk.com</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("achudk.com","achudk.com"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
#修改主配置文件
<?xml version='1.0' encoding='utf-8'?>
<Server port="-1" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="tomcat.achudk.com" appBase="/appdata/webapps" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="node1_access" suffix=".log" pattern="%h %l %u %t "%r" %s %b" />
<Context path="/tc1" docBase="/" reloadable="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="node1_test_access_" suffix=".log" pattern="%h %l %u %t "%r" %s %b" />
</Context>
</Host>
</Engine>
</Service>
</Server>
被嵌套类:valve, logger, realm, loader, manager, …
集群类组件:listener, cluster, …
tomcat安装完成后可通过本机的8080端口访问tomcat默认页面。
设置tomcat的manager和host-manager的用户配置文件
vim /etc/tomcat/tomcat-user.xml
#增加下面三条
<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="admin-gui,manager-gui"/>
#重启tomcat服务
systemctl restart tomcat
重启tomcat服务后,测试使用默认页,可以试用tomcat的两个管理工具:”Manager Apps” 和 “Host-Manager”
JSP Webapp的组织架构
/: webapps的根目录
index.jsp:主页
WEB-INF/:当前webapp的私有资源路径;通常用于存储当前webapp的web.xml和context.xml配置文件
META-INF/:类似于WEB-INF/
classes/:类文件,当前webapp所提供的类
lib/:类文件,当前webapp所提供的类,被打包为jar格式
部署webapps及部署工具
热部署:在实际生产环境中如果采用非灰度发布的形式,无论是部署新的webapps或者发布更新原有的webapps,在上述过程中tomcat服务不能中断,所以可能需要专业的部署工具来实现持续发布的效果
冷部署:在灰度发布的生产环境或在实验环境中,tomcat服务重启后,各webapps加载因需重新加载JRE,整个过程会非常慢,此时也需要部署工具来加速发布过程
冷部署示例
mkdir /var/lib/tomcat/webapps/test/{WEB-INF,META-INF,lib,classes}
vim /test/index.jsp
#增加如下内容
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<% out.println("Test : Hello world"); %>
</body>
</html>
重启tomcat服务后,测试访问 URL/test 页面是否显示 Test : Hello world
使用部署工具进行热部署
布置新的webapps相关文件,此处为了方便演示,将test复制重命名为test2后演示热部署过程
cd /var/lib/tomcat/webapps
cp -a test/ test2/
#修改下index.jsp文件,使其与test的index.jsp文件内容不同,以示区别
vim /var/lib/tomcat/webapps/test2/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<% out.println("Test2 : Hello world");
%>
</body>
</html>
在Tomcat默认页面上,使用”Manager Apps”工具,可在Deploy一段的 “Context Path (required):” 中填写 test2 ,点击deploy即完成部署。
负载均衡tomcat响应动态资源
使用nginx实现负载均衡
角色及IP分配:
负载均衡器:nginx :172.16.50.2/16(公网) 192.168.50.12/24(内网)
动态资源服务器1 :tomcat1 :192.168.50.13/24
动态资源服务器2 :tomcat2 :192.168.50.14/24
- 先配置两台动态资源服务器并启动服务
#准备webapps
cd /var/lib/tomcat/webapps/
mkdir test/{WEB-INF,META-INF,lib,classes}
vim test/index.jsp
<html>
<head><title>TomcatA</title></head>
<body>
<h1><font color="red">TomcatA.achudk.com</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("achudk.com","achudk.com"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
#修改tomcat主配置文件
vim /etc/tomcat/server.xml
<?xml version='1.0' encoding='utf-8'?>
#将8005的连接器的端口改为-1,关闭内置的管理端口8005,能加快tomcat服务启动或停止的速度
<Server port="-1" shutdown="SHUTDOWN">
</Server>
- 配置负载均衡器并启动服务
cd /etc/nginx
vim nginx.conf
#在http {}中增加以下指令
upstream tcsrvs {};
server 192.168.50.13:8080;
server 192.168.50.14:8080;
#在server {} 配置段中,增加以下内容
proxy_pass http://tcsrvs;
- 测试负载调度结果
访问172.16.50.2,两个服务器交替响应。
使用httpd实现负载均衡
- 后端服务器不做任何修改,仅修改前端负载均衡器
vim /etc/httpd/conf.d/tomcat.conf
<Proxy balancer://tcsrvs>
BalancerMember http://192.168.50.13:8080
BalancerMember http://192.168.50.14:8080
ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
ServerName tc1.achudk.com
ProxyRequests off
ProxyVia on
ProxyPreserveHost on
<Proxy *>
Require all granted
</Proxy>
Proxypass / balancer://tcsrvs/
ProxyPassReverse / balancer://tcsrvs/
<Location />
Require all granted
</Location>
</VirtualHost>
- 测试结果
访问172.16.50.2,两个服务器交替响应。
负载均衡中会话保持的实现
session sticky
原理:通过标记等方式来识别请求报文,将请求相同资源的请求调度至同一台动态资源服务器
特性:每台后端服务器保存的会话各不相同,使每个服务器在保存会话方面成为单点session replication cluster
原理:每台服务器保存会话后,向同一组播域中的其他主机同步保存的会话信息
特性:每台后端服务器保存的会话信息相同,单个组播域内仅能存在少数几台主机,否则会话信息同步效率会很低session server
原理:在动态资源服务器后端设置一台会话存储服务器,专用于保存会话信息,多个动态资源服务器可同时向该存储中写入数据
特性:每台后端动态资源服务器不保存会话信息,共享会话存储服务器的内容,会话存储服务器为避免成为单点,要设置多个,多个session server之间为主从关系
1. session sticky的实现
- 方法一 :使用httpd作为负载均衡调度器,配置如下
vim /etc/httpd/conf.d/tomcat.conf
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy balancer://tcsrvs>
BalancerMember http://192.168.50.13:8080 route=TomcatA loadfactor=1
BalancerMember http://192.168.50.14:8080 route=TomcatB loadfactor=2
ProxySet lbmethod=byrequests
ProxySet stickysession=ROUTEID
</Proxy>
<VirtualHost *:80>
ServerName tc1.achudk.com
ProxyRequests off
ProxyVia on
ProxyPreserveHost on
<Proxy *>
Require all granted
</Proxy>
Proxypass / balancer://tcsrvs/
ProxyPassReverse / balancer://tcsrvs/
<Location />
Require all granted
</Location>
</VirtualHost>
- 方法二 :使用nginx作为负载均衡器实现会话粘性
vim /etc/nginx/nginx.conf
#增加以下内容
upstream tcsrvs {
hash $request_uri consistent; //根据uri来调度
# hash $cookie_name consistent; //根据cookie来调度
server 192.168.50.13:8080;
server 192.168.50.14:8080;
}
启用httpd的banalancer-manager的管理接口
vim /etc/httpd/conf.d/tomcat.conf
#增加一个Location
<Location /balancer-manager>
SetHandler balancer-manager
ProxyPass !
Require all granted
</Location>
- 访问172.16.50.2/balancer-manager
2. session replication cluster 的实现
配置启用集群,修改各台服务器tomcat服务的配置文件,将下列配置放置于或中;
- 在
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
<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.10.10.10"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="192.168.50.13"
port="4000"
autoBind="100"
selectorTimeout="5000"
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"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<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.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
配置webapps
编辑WEB-INF/web.xml,添加元素
注意:CentOS 7上的tomcat自带的文档中的配置示例有语法错误
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
- 绑定的地址为auto时,会自动解析本地主机名,并解析得出的IP地址作为使用的地址
解决办法1:将auto修改为指定的IP地址
解决办法2:修改/etc/hosts文件,将localhost修改为指定IP