首页 > 代码库 > tomcat实践总结

tomcat实践总结

前言:

    常言道,实践出真知。其实懵懵懂懂看了好几章节对tomcat的介绍,真不如自己动手实践实践,从实践中理解tomcat的基本组建及相关配置。此篇主要记录博主使用tomcat的整个配置过程~

正文:

    先介绍环境,tomcat版本:7.0.54,java:openjdk version "1.8.0_65",系统:centos7.2

    作为一个java应用,第一步肯定先安装java环境,本次选择的是openjdk。

        yum install java-1.8.0-openjdk-devel -y

    虽说是开发组建,不过会安装依赖的openjdk。然后一次性安装上tomcat,tomcat-webapps,tomcat-admin-webapps,如果需要帮助文档也可安装上tomcat-docs-webapp。其中tomcat-webapps会生成一个tomcat的示例web程序,tomcat-admin-webapps就是一个主机管理界面之类的。

        yum install tomcat tomcat-webapps tomcat-admin-webapps -y
        systemctl start tomcat

    默认tomcat服务会监听在8080端口,我们在浏览器上用服务器ip加端口就可以访问tomcat的欢迎页了,我服务器的ip为172.16.53.100,即:http://172.16.53.100:8080/。

    在具体使用tomcat之前还是先来介绍介绍tomcat吧~一般而言,一个web服务器除了提供静态html页面以外,还能运行程序动态的响应用户请求,并将动态结果传送到用户浏览器上,像apache,nginx本身只能提供静态内容,动态内容就得由各种应用程序提供,比如php,jsp程序。而tomcat不仅包含了java servlet技术,而且还包含JSP基础,当然它也包含了各种编程语言编写的传统静态网页和外挂CGI程序。不过大多数时候我们还是把它作为一个Servlet和JSP引擎。

    首先我们来运行我们的第一个tomcat程序,新建一个目录存放jsp代码,然后通过tomcat加载。

    mkdir -pv /var/lib/tomcat/webapps/test/{classes,lib,WEB-INF}
    cd /var/lib/tomcat/webapps/test/
    vim index.jsp          #以下为文件内容
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
        <head>
                <title>Test Page</title>
        </head>
        <body>
                <% out.println("hello world");
                %>
</body>
</html>

    然后我们就可以直接访问这个页面了,http://172.16.53.100:8080/test。好啦这就是我们的第一个实践了。

    tomcat的主要配置文件为/etc/tomcat/server.xml,主要的核心如下:

<Server>

<Service>

<connector/>

<connector/>

...

<Engine>

<Host>

<Context/>

<Context/>

...

</Host>

<Host>

...

</Host>

...

</Engine>

</Service>

</Server>

    server表示一个tomcat实例,即表现出一个java进程,监听在8005端口,只接收"SHUTDOWN"。

    Service主要用于将一个或多个connector组建关联至一个engine组建

    Connector组建主要负责接收请求,常见的有三类http/https/ajp

    Engine组建就是Servlet实例,即servlet引擎,其内部可以一个或多个host组建来定义站点,通常需要通过defaultHost来定义默认的主机

    Host组建位于engine内部用于接受请求并进行响应处理的主机或虚拟主机。

    了解了基本组建,我们来建自己第一个虚拟主机把~在serer.xml修改增加如下:

        <Engine name="Catalina" defaultHost="xiaofengfeng.blog.51cto.com">
            ...
            <Host name="xiaofengfeng.cn" appBase="/appdata/webapps" unpackWARs="true" autoDeploy="true">
            </Host>
            ...
         <Engine>

    我们把Engine的默认主机改为我们新增的主机的名字,这样我们就直接可以通过ip访问到虚拟主机了。我们还得为Host创建工作目录,和jsp程序。

mkdir -pv /appdata/webapps/ROOT/{lib,classes,WEB-INF}
vim /appdata/webapps/ROOT/index.jsp
    <%@ page language="java" %>
    <%@ page import="java.util.*" %>
    <html>
        <head>
                <title>Test Page</title>
        </head>
        <body>
                <% out.println("hello world");
                %>
        </body>
    </html>

此处我们就得重启tomcat应用了。

systemctl restart tomcat

然后通过ip+端口访问就可以了。我们在安装tomcat-admin-webapps的时,会提供一个host的管理web界面,不过这个web需要认证,默认就是BASIC认证,我们只用额外增加一个用户及密码就好,而tomcat用于用户管理的在/etc/tomcat/server.xml中,配置如下:

<tomcat-users>
    <role rolename="admin-gui"/>
    <user username="tomcat" password="tomcat" roles="admin-gui"/> 
</tomcat-users>

重启tomcat我们就可以访问host管理页面了,还记得不记得我们在前面修改了Engine的defaultHost?我们得将其改回localhost才能访问控制页面。

一、nginx+tomcat

    nginx做反代到后端的tomcat,外部请求就可以通过80端口就可以经过nginx反代到后端的tomcat

yum install nginx
systemctl start nginx
vim /etc/nginx/nginx.conf
        location / {
                proxy_pass http://172.16.53.100:8080;
        }

   如过是实现动静分离,可以把jsp反代到tomcat,其他请求资源反代到静态web服务器上

location / {
    proxy_passhttp://url:port;
}
 
location ~* \.(jsp|do)$ {
    proxy_passhttp://tc1.magedu.com:8080;
}

当然apache(httpd)也可以作为前端的代理。而且apache可以通过模块,http和ajp反代到tomcat。

二、apache(httpd)+tomcat

systemctl stop nginx
yum install httpd
systemctl start httpd
vim /etc/httpd/conf.d/tomcat.conf
    <VirtualHost *:80>
        ServerName      www.xiaofengfeng.cn
        ProxyRequests Off
        ProxyVia        On
        ProxyPreserveHost On
        <Proxy *>
                Require all granted
        </Proxy>
        ProxyPass / http://172.16.53.100:8080/
        ProxyPassReverse / http://172.16.53.100:8080/ 
        <Location />
                Require all granted
        </Location>
    </VirtualHost>
systemctl restart httpd

    其中ProxyPass很好理解,就是把收到的请求反向代理到tomcat,那ProxyPassReverse这个是做什么的呢?如果你去掉这行,感觉也能正常运行,其实不然。举个例子,客户端访问http://www.xiaofengfeng.cn/test时,会被httpd反向代理到172.16.53.100:8000/test并处理请求,假如此程序会重定向到另一个login页面,如果用的是相对路径,就会重定向到172.16.53.100:8000/login,而这个地址只能反向代理服务器能访问,而配置ProxyPassReverse的作用就在于把172.16.53.100:8000/login转换为能被外部访问的http://www.xiaofengfeng.cn/login。

httpd还支持ajp的方式反代,和上面配置区别不大,只用改两个个地方,注意那么端口哦,改成8009

        ProxyPass / ajp://172.16.53.100:8009/
        ProxyPassReverse / ajp://172.16.53.100:8009/

三、tomcat集群

    我们直接演示httpd的负载均衡,我们开启一个新的centos系统,ip为172.16.53.101,装上java和tomcat,在172.16.53.100上用httpd做反向代理。

#172.16.53.100
vim /etc/httpd/conf.d/tomcat.conf
    <proxy balancer://tcsrvs>
            BalancerMember http://172.16.53.100:8080
            BalancerMember http://172.16.53.101:8080
            ProxySet lbmethod=byrequests
    </Proxy>
    <VirtualHost *:80>
            ServerName      www.xiaofengfeng.cn
            ProxyRequests Off
            ProxyVia        On
            ProxyPreserveHost On
            <Proxy *>
                    Require all granted
            </Proxy>
            ProxyPass / balancer://tcsrvs/
            ProxyPassReverse / banlancer://tcsrvs/
            <Location />
                    Require all granted
            </Location>
    </VirtualHost>

ProxyPass* 后面的url一定要加/哟,不然相对路径的资源会被解析成错误的链接。为了测试方便,我们在两台tomcat服务系统上用特殊的jsp代码。

#172.16.53.100
vim /var/lib/tomcat/webapps/test/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>
#172.16.53.101
mkdir /var/lib/tomcat/webapps/test/{classes,lib,WEB-INF}
vim /var/lib/tomcat/webapps/test/index.jsp
    <%@ page language="java" %>
    <html>
            <head><title>TomcatB</title></head>
            <body>
            <h1><font color="blue">TomcatB.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来标记同一个客户端,但是在集群中,保存在A中的session,B肯定是不知道的。所以我们就要进行session绑定,当一个用户第一访问的是A服务器,那么她以后就都访问A服务器,这样他的session就不会丢失了。我们可以通过源地址绑定和基于cookie绑定,nginx中用ip_hash,haproxy中用source,lvs中用sh。此处演示apache上的基于cookie的绑定。基于cookie的绑定主要分为两个部分,当用户第一次请求时,我们给他加一条cookie,用来标记它,然后第二次访问时,检查其携带的cookie,以代理的后端与cookie对应的服务器。在http中配置如下:

Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED           #加一条cookie,cookie值为下面route对应的值。

<proxy balancer://tcsrvs>
        BalancerMember http://172.16.53.100:8080 route=TomcatA loadfactor=1
        BalancerMember http://172.16.53.101:8080 route=TomcatB loadfactor=2
        ProxySet lbmethod=byrequests
        ProxySet stickysession=ROUTEID   #用ROUTED来绑定会话。
</Proxy>
<VirtualHost *:80>
        ServerName      www.xiaofengfeng.cn
        ProxyRequests Off
        ProxyVia        On
        ProxyPreserveHost On
        <Proxy *>
                Require all granted
        </Proxy>
        ProxyPass / balancer://tcsrvs/
        ProxyPassReverse / banlancer://tcsrvs/
        <Location />
                Require all granted
        </Location>
</VirtualHost>

所以就加入了三个东东。第一个是客户端第一次访问加入cookie,并给每个后端服务器加一个route来标记,然后在把此标记绑定到会话上。这样我们发出请求后每次都是第一次访问的后端服务器为我们处理请求。

    除了在代理上的实现,我们还有其他的方法。我们把后端的tomcat构建成一个集群,然后所有主机共同监听同一个端口,然后周期性的将包括自己的状态,比如健康信息,或者自己的每一个会话通过多播的方式通告给同一个集群的其他主机。这样每个主机就能得到其他主机上的session 会话信息了。 

我们先把httpd基于cookie的会话绑定配置去掉,/etc/httpd/conf.d/tomcat配置如下:

<proxy balancer://tcsrvs>
        BalancerMember http://172.16.53.100:8080
        BalancerMember http://172.16.53.101:8080
        ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
        ServerName      www.xiaofengfeng.cn
        ProxyRequests Off
        ProxyVia        On
        ProxyPreserveHost On
        <Proxy *>
                Require all granted
        </Proxy>
        ProxyPass / balancer://tcsrvs/
        ProxyPassReverse / banlancer://tcsrvs/
        <Location />
                Require all granted
        </Location>
                <Location /balancer-manager>
                SetHandler balancer-manager
                ProxyPass !
                Require all granted
        </Location>
</VirtualHost>

systemctl restart httpd

然后在tomcat两个服务加上集群。需要完成三个部分:

一、加入集群配置,二、在Engine上加入jvmRoute属性。如下

<Engine name="Catalina" defaultHost="localhost" jvmRoute="TomcatA">
<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.0.53.4"
						port="45564"
						frequency="500"
						dropTime="3000"/>
		<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
				address="172.16.53.100" ######此处为各自提供服务的ip
				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>
...

三、配置web.xml,给我们的test测试程序加上web.xml,并在里面添加上<distributable/>元素

cp /etc/tomcat/web.xml /var/lib/tomcat/webapps/test/WEB-INF
vim /var/lib/tomcat/webapps/test/WEB-INF/web.xml
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
  <distributable/>  #在web-app标签里面加入此标签。

两个tomcat的配置如上,除了######标记处不一样,其他都一样

然后重启两个tomcat服务

systemctl restart tomcat

测试时就会发现,TomcatA与TomcatB来回切换,但是sessionID却不改变。



当然出了上面的方法,我们还可以把session会话保存到数据库中,比如memcached~当然这都是后话!

本文出自 “机制小风风” 博客,请务必保留此出处http://xiaofengfeng.blog.51cto.com/8193303/1896525

tomcat实践总结