Tomcat

post thumb
Ops
作者 Louis 发表于 2018年7月18日

摘要:

  • Tomcat相关的概念及安装
  • Tomcat的配置及解释
  • httpd/Nginx/Ajp下的tomcat集群实现
  • Mencached下的Tomcat会话存储

Tomcat相关概念

Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等。由于Tomcat本身也内含了一个HTTP服务器,它也可以被视作一个单独的Web服务器。但是,不能将Tomcat和Apache HTTP服务器混淆,Apache HTTP服务器是一个用C语言实现的HTTPWeb服务器;这两个HTTP web server不是捆绑在一起的。Apache Tomcat包含了一个配置管理工具,也可以通过编辑XML格式的配置文件来进行配置。Tomcat是Java 2 EE技术体系的不完整实现。

img

  • JDK:java工具箱
  • JRE:java运行时环境
  • JVM:C语言研发,java虚拟机
  • ajp:AJP13是定向包协议,httpd支持此协议,nginx不支持
  • jsp:java server page
  • jasper:负责将.jsp 转换为 .java
  • applet:Applet或Java小应用程序是一种在Web环境下,运行于客户端的Java程序组件
  • servlet:全称Java Servlet, 是用Java编写的服务器端程序,其主要功能在于交互式地浏览和修改数据,生成动态Web内容,将.java转换成字节码

安装Tomcat

yum包安装

# yum install java-1.8.0-openjdk
# yum install tomcat tomcat-webapps tomcat-admin-webapps tomcat-docs-webapp
# java -version  #查看java版本信息
# tomcat version  #查看tomcat版本信息

启动服务:

# systemctl start tomcat
# ss -tnl
LISTEN      0      1        ::ffff:127.0.0.1:8005  #管理端口,建议关闭
LISTEN      0      100        :::8009              #AJP协议默认监听端口
LISTEN      0      100        :::8080              #HTTP协议默认监听端口

tomcat的目录结构:

配置文件目录:/etc/tomcat/
主配置文件:server.xml
webapps存放位置:/var/lib/tomcat/webapps/
环境配置文件:/etc/sysconfig/tomcat

官方发行版安装

安装JDK:

下载地址:http://www.oracle.com/technetwork/java/javase/downloads/

# rpm -ivh jdk-8u25-linux-x64.rpm
# ll /usr/java/  #默认安装路径
lrwxrwxrwx 1 root root  16 Jul 17 19:46 default -> /usr/java/latest
drwxr-xr-x 9 root root 268 Jul 17 19:46 jdk1.8.0_25
lrwxrwxrwx 1 root root  21 Jul 17 19:46 latest -> /usr/java/jdk1.8.0_25
# vim /etc/profile.d/java.sh  #将java环境变量加入系统环境变量
export JAVA_HOME=/usr/java/latest
export PATH=$JAVA_HOME/bin:$PATH
# . /etc/profile.d/java.sh

安装Tomcat:

下载地址:http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.32/bin/apache-tomcat-8.5.32.tar.gz

# useradd tomcat
# tar xf apache-tomcat-8.5.32.tar.gz -C /usr/local/
# cd /usr/local/
local]# ln -sv apache-tomcat-8.5.32/ tomcat
local]# cd tomcat/
tomcat]# chgrp -R tomcat ./*
tomcat]# chown -R tomcat logs/ temp/ work/
tomcat]# chmod g+rx conf/
tomcat]# chmod g+r conf/*
# vim /etc/profile.d/tomcat.sh  #配置环境变量
export CATALINA_BASE=/usr/local/tomcat
export PATH=$CATALINA_BASE/bin:$PATH
# . /etc/profile.d/tomcat.sh
# su - tomcat -c 'catalina.sh start'

# ls -1 /usr/local/tomcat/ bin:脚本及启动时用到的类 conf:配置文件目录 lib:库文件,Java类库,jar logs:日志文件目录 temp:临时文件目录 webapps:webapp的默认目录 work:工作目录

# catalina.sh --help
commands:
  debug             #调试模式启动
  jpda start        #jpda的debug模式启动
  run               #前台启动
  start             #后台启动
  stop              #关闭
  stop n            #n秒后关闭
  stop -force       #强制关闭
  stop n -force     #n秒后强制关闭
  configtest        #测试配置文件语法
  version           #查看相关版本信息
# catalina.sh version
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Server version: Apache Tomcat/8.5.32
Server built:   Jun 20 2018 19:50:35 UTC
Server number:  8.5.32.0
OS Name:        Linux
OS Version:     3.10.0-862.el7.x86_64
Architecture:   amd64
JVM Version:    1.8.0_25-b17
JVM Vendor:     Oracle Corporation

manager、host-manager和docs

依赖包:

  • tomcat-webapps
  • tomcat-admin-webapps
  • tomcat-docs-webapp

配置:manager管理webapps应用程序

# vim /etc/tomcat/tomcat-users.xml
<role rolename="manager-gui"/>
<user username="admin" password="adminpass" roles="manager-gui"/>
# systemctl restart tomcat

访问:http://192.168.0.8:8080/manager/进入管理页面

配置:host-manager管理虚拟主机

# vim /etc/tomcat/tomcat-users.xml
<role rolename="admin-gui"/> 
<user username="admin" password="admin" roles="manager-gui,admin-gui"/>
# systemctl restart tomcat

访问:http://192.168.0.10:8080/host-manager/进入管理页面

docs获取离线文档

访问:http://192.168.0.10:8080/docs/

Tomcat的配置参数

  • server.xml:主配置文件
  • web.xml:每个webapp只有“部署”后才能被访问,它的部署方式通常由web.xml进行定义,其存放位置为WEB-INF/目录中;此文件为所有的webapps提供默认部署相关的配置
  • context.xml:每个webapp都可以专用的配置文件,它通常由专用的配置文件context.xml来定义,其存放位置为WEB-INF/目录中;此文件为所有的webapps提供默认配置
  • tomcat-users.xml:用户认证的账号和密码文件
  • catalina.policy:当使用-security选项启动tomcat时,用于为tomcat设置安全策略
  • catalina.properties:Java属性的定义文件,用于设定类加载器路径,以及一些与JVM调优相关参数
  • logging.properties:日志系统相关的配置

tomcat的核心组件:server.xml

配置文件框架:

<Server>
    <Service>
        <connector/>
        <Engine>
            <Host>
                <Context>
                    <Valve/>
                </Context/>
            </Host>
        </Engine>
    </Service>
</Server>

每一个组件都由一个Java“类”实现,这些组件大体可分为以下几个类型:

  • 顶级组件:Server
  • 服务类组件:Service
  • 连接器组件:http, https, ajp(apache jserv protocol)
  • 容器类:Engine, Host, Context
  • 被嵌套类:valve, logger, realm, loader, manager, …
  • 集群类组件:listener, cluster, …

Tomcat的常用组件配置:

  • Server:代表tomcat instance,即表现出的一个java进程;监听在8005端口,只接收“SHUTDOWN”。各server监听的端口不能相同,因此,在同一物理主机启动多个实例时,需要修改其监听端口为不同的端口;
  • Service:用于实现将一个或多个connector组件关联至一个engine组件;
  • Connector组件:负责接收请求,常见的有三类http/https/ajp;
port="8080" 监听的端口
protocol="HTTP/1.1" 协议
connectionTimeout="20000" 连接超时时间,单位ms,2秒
address:监听的IP地址;默认为本机所有可用地址;
maxThreads:最大并发连接数,默认为200;
enableLookups:是否启用DNS查询功能;
acceptCount:等待队列的最大长度;
secure:安全相关;
sslProtocol:加密传输相关;
  • Engine组件:Servlet实例,即servlet引擎,其内部可以一个或多个host组件来定义站点; 通常需要通过defaultHost属性来定义默认的虚拟主机;
name=
defaultHost="localhost"
jvmRoute=
  • Host组件:位于engine内部用于接收请求并进行相应处理的主机或虚拟主机
<Host name="localhost"  appBase="webapps"
      unpackWARs="true" autoDeploy="true">
</Host>
appBase:此Host的webapps的默认存放目录,指存放非归档的web应用程序的目录或归档的WAR文件目录路径;可以使用基于$CATALINA_BASE变量所定义的路径的相对路径;
autoDeploy:在Tomcat处于运行状态时,将某webapp放置于appBase所定义的目录中时,是否自动将其部署至tomcat;
  • Context组件:相当于nginx中的alias的功能
<Context path="/PATH" docBase="/PATH/TO/SOMEDIR" reloadable=""/>
path:url路径
docBase:网页文件目录路径
  • Valve组件:
定义访问日志:org.apache.catalina.valves.AccessLogValve
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
       prefix="localhost_access_log." suffix=".txt"
       pattern="%h %l %u %t &quot;%r&quot; %s %b" />
定义访问控制:org.apache.catalina.valves.RemoteAddrValve
<Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="172\.16\.100\.67"/>

组件配置示例:

  • 配置示例:Host组件
[root@node1 ~]# vim /etc/tomcat/server.xml
<Engine>
  ...
  <Host name="node1.fenghong.tech" appBase="/web/apps" unpackWARs="true" autoDeploy="true"/>
</Engine>
[root@node1 ~]# mkdir -pv /web/apps/ROOT/
[root@node1 ~]# vim /web/apps/ROOT/index.jsp
<%@ page language="java" %>
<html>
    <head><title>TomcatA</title></head>
    <body>
        <h1><font color="red">TomcatA.fenghong.tech</font></h1>
        <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("fenghong.tech","fenghong.tech"); %>
                <td><%= session.getId() %></td>
            </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    </body>
</html>
[root@node1 ~]# systemctl restart tomcat
测试访问:http://node1.fenghong.tech:8080/
  • 配置示例:Context组件
[root@node1 ~]# vim /etc/tomcat/server.xml
<Engine>
  ...
    <Host name="node1.fenghong.tech" appBase="/web/apps" unpackWARs="true" autoDeploy="true">
      <Context path="/testapp" docBase="/web/testapp" reloadable=""/>
    </Host>
</Engine>
[root@node1 ~]# systemctl restart tomcat
[root@node1 ~]# mkdir -pv /web/testapp/ROOT
[root@node1 ~]# vim /web/testapp/index.jsp
...
测试访问:http://node1.fenghong.tech:8080/testapp/
  • 配置示例:Valve组件
[root@node1 ~]# vim /etc/tomcat/server.xml
<Host name="node1.fenghong.tech" appBase="/web/apps" unpackWARs="true" autoDeploy="true">
  <Context path="/testapp" docBase="/web/testapp" reloadable="">
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
      prefix="node1_test_access_" suffix=".log"
      pattern="%h %l %u %t &quot;%r&quot; %s %b" />
  </Context>
</Host>
[root@node1 ~]# systemctl restart tomcat
[root@node1 ~]# tail /var/log/tomcat/node1_test_access_2018-07-17.log
192.168.0.8 - - [17/Jul/2018:22:59:30 +0800] "GET /testapp/ HTTP/1.1" 200 334

JSP WebAPP的组织结构:

  • index.jsp:主页;
  • WEB-INF/:当前webapp的私有资源路径;通常用于存储当前webapp的web.xml和context.xml配置文件;
  • META-INF/:类似于WEB-INF/;
  • classes/:类文件,当前webapp所提供的类;
  • lib/:类文件,当前webapp所提供的类,被打包为jar格式;

webapp归档格式:

  • .war:webapp
  • .jar:EJB的类打包文件;
  • .rar:资源适配器类打包文件;
  • .ear:企业级webapp;

部署(deploy)webapp

  • deploy:将webapp的源文件放置于目标目录(网页程序文件存放目录),配置tomcat服务器能够基于web.xml和context.xml文件中定义的路径来访问此webapp;将其特有的类和依赖的类通过class loader装载至JVM;
  • undeploy:反部署,停止webapp,并从tomcat实例上卸载webapp;
  • start:启动处于停止状态的webapp;
  • stop:停止webapp,不再向用户提供服务;其类依然在jvm上;
  • redeploy:重新部署;

部署可分为自动部署和手动部署;手动部署又有冷部署和热部署:

  • 冷部署:把webapp复制到指定的位置,而后才启动tomcat;
  • 热部署:在不停止tomcat的前提下进行部署;部署工具有manager、ant脚本、tcd(tomcat client deployer)等;

示例:手动提供一测试类应用,并冷部署

[root@node1 ~]# mkdir -pv /var/lib/tomcat/webapps/test/{classes,lib,WEB-INF}
[root@node1 ~]# vim /var/lib/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<html>
    <head>
        <title>Test Page</title>
    </head>
    <body>
        <% out.println("hello world");
        %>
    </body>
</html>
访问:http://192.168.0.10:8080/test/

NT:nginx | httpd + tomcat

img

nginx和Tomcat通过http/https协议工作

配置Tomcat:

[root@tomcat ~]# mkdir -pv /data/webapp/ROOT/
[root@tomcat ~]# vim /data/webapp/ROOT/index.jsp  #提供jsp测试页
<%@ page language="java" %>
<html>
    <head><title>TomcatA</title></head>
    <body>
        <h1><font color="red">TomcatA.fenghong.tech</font></h1>
        <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("fenghong.tech","fenghong.tech"); %>
                <td><%= session.getId() %></td>
            </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    </body>
</html>
[root@tomcat ~]# vim /data/webapp/ROOT/test.html  #提供静态测试页
static page
[root@tomcat ~]# vim /etc/tomcat/server.xml  #修改Tomcat配置,如下
<?xml version='1.0' encoding='utf-8'?>
<Server port="-1" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- <Connector address="127.0.0.1" port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
    <Engine name="Catalina" defaultHost="node1.fenghong.tech">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <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 &quot;%r&quot; %s %b" />
      </Host>
      <Host name="node1.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="node1-dongfei-tech_access." suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
          </Host>
    </Engine>
  </Service>
</Server>
[root@tomcat ~]# systemctl start tomcat

配置nginx:

[root@tomcat ~]# vim /etc/nginx/conf.d/nginx_tomcat.conf
server {
        listen 80;
        server_name node1.fenghong.tech;
        index index.jsp index.html;
        location / {
                root "/data/webapp/ROOT/";
        }
        location ~* \.(jsp|do)$ {
                proxy_pass http://127.0.0.1:8080;
        }
}
[root@tomcat ~]# nginx

测试访问:

httpd和Tomcat通过http/https协议工作

[root@tomcat ~]# httpd -M |grep proxy
 proxy_module (shared) #代理模块
 proxy_ajp_module (shared) #适配ajp协议客户端
 proxy_balancer_module (shared)
 proxy_connect_module (shared)
 proxy_express_module (shared)
 proxy_fcgi_module (shared)
 proxy_fdpass_module (shared)
 proxy_ftp_module (shared)
 proxy_http_module (shared) #适配http协议客户端
 proxy_scgi_module (shared)
 proxy_wstunnel_module (shared)

配置Tomcat:如上

配置httpd:

[root@tomcat ~]# vim /etc/httpd/conf.d/http_tomcat.conf
<VirtualHost *:80>
    ServerName node1.fenghong.tech
    ProxyRequests Off  #关闭正向代理
    ProxyVia On
    ProxyPreserveHost On  #将请求头HOST发送给后端主机
    <Proxy *>
        Require all granted
    </Proxy>
    ProxyPass / http://127.0.0.1:8080/
    <Location />
        Require all granted
    </Location>
</VirtualHost>
[root@tomcat ~]# systemctl start httpd

http和Tomcat通过ajp协议工作

配置Tomcat:

[root@tomcat ~]# vim /etc/tomcat/server.xml
<Connector address="127.0.0.1" port="8009" protocol="AJP/1.3" redirectPort="8443" />
[root@tomcat ~]# systemctl restart tomcat

配置httpd:

[root@tomcat ~]# vim /etc/httpd/conf.d/http_tomcat.conf
<VirtualHost *:80>
        ServerName node1.fenghong.tech
        ProxyRequests Off
        ProxyVia On
        ProxyPreserveHost On
        <Proxy *>
                Require all granted
        </Proxy>
        ProxyPass / ajp://127.0.0.1:8009/
        <Location />
                Require all granted
        </Location>
</VirtualHost>
[root@tomcat ~]# systemctl restart httpd

nntm的会话保持实现

  • session sticky:会话绑定

    • source_ip:基于源地址做会话绑定;nginx: ip_hash,haproxy: source,lvs: sh
    • cookie:基于cookie做会话绑定;nginx:hash,haproxy: cookie

img

httpd + nginx + tomcat cluster:基于cookie实现会话绑定

前端httpd调度器:

[root@Director ~]# httpd -M |grep balancer
 proxy_balancer_module (shared)
[root@Director ~]# vim /etc/httpd/conf.d/httpd-tomcat.conf
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<proxy balancer://tcsrvs>
    BalancerMember http://192.168.0.10:80 route=TomcatA loadfactor=1
    BalancerMember http://192.168.0.11:80 route=TomcatB loadfactor=2
    ProxySet lbmethod=byrequests
    ProxySet stickysession=ROUTEID
</Proxy>
<VirtualHost *:80>
    ServerName www.fenghong.tech
    ProxyVia On 
    ProxyRequests Off
    ProxyPreserveHost On
    <Proxy *>   
        Require all granted 
    </Proxy>    
    ProxyPass / balancer://tcsrvs/
    ProxyPassReverse / balancer://tcsrvs/
    <Location />
        Require all granted 
    </Location> 
</VirtualHost>
[root@Director ~]# systemctl start httpd

tomcat-node-1:

[root@tomcat-node-1 ~]# vim /etc/nginx/conf.d/nginx_tomcat.conf 
server {
    listen 80 default_server;
    server_name node1.fenghong.tech;
    index index.jsp index.html;
    location / {
        root "/data/webapp/ROOT/";
    }
    location ~* \.(jsp|do)$ {
        proxy_pass http://127.0.0.1:8080;
    }
}
[root@tomcat-node-1 ~]# vim /etc/tomcat/server.xml
<Server port="-1" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Engine name="Catalina" defaultHost="node1.fenghong.tech" jvmRoute="TomcatA">
      <Host name="node1.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="node1-dongfei-tech_access." suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
          </Host>
    </Engine>
  </Service>
</Server>
[root@tomcat-node-1 ~]# vim /data/webapp/ROOT/index.jsp
<%@ page language="java" %>
<html>
    <head><title>TomcatA</title></head>
    <body>
        <h1><font color="red">TomcatA.fenghong.tech</font></h1>
        <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("fenghong.tech","fenghong.tech"); %>
                <td><%= session.getId() %></td>
            </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    </body>
</html>
[root@tomcat-node-1 ~]# systemctl start nginx tomcat

tomcat-node-2:

[root@tomcat-node-2 ~]# vim /etc/nginx/conf.d/nginx_tomcat.conf
server {
    listen 80 default_server;
    server_name node2.fenghong.tech;
    index index.jsp index.html;
    location / {
        root "/data/webapp/ROOT/";
    }
    location ~* \.(jsp|do)$ {
        proxy_pass http://127.0.0.1:8080;
    }
}
[root@tomcat-node-2 ~]# vim /etc/tomcat/server.xml
<Server port="-1" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Engine name="Catalina" defaultHost="node2.fenghong.tech" jvmRoute="TomcatB">
      <Host name="node2.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="node2-dongfei-tech_access." suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
          </Host>
    </Engine>
  </Service>
</Server>
[root@tomcat-node-2 ~]# vim /data/webapp/ROOT/index.jsp 
<%@ page language="java" %>
<html>
    <head><title>TomcatB</title></head>
        <body>
        <h1><font color="blue">TomcatB.fenghong.tech</font></h1>
        <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("fenghong.tech","fenghong.tech"); %>
                <td><%= session.getId() %></td>
            </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
        </body>
</html>
[root@tomcat-node-2 ~]# systemctl start nginx tomcat

测试访问:http://www.fenghong.tech/;实现同一cookie的客户端调度到同一后端server上

  • httpd反代启用管理接口:
<Location /balancer-manager>
	SetHandler balancer-manager
	ProxyPass !
	Require all granted
</Location>

nginx + nginx + tomcat cluster:基于源地址hash调度

前端nginx调度器:

[root@Director ~]# vim /etc/nginx/conf.d/nginx_tomcat.conf
upstream tcsrvs {
        ip_hash;
        server 192.168.0.10:80;
        server 192.168.0.11:80;
}
server {
        listen 80;
        server_name www.fenghong.tech;
        location / {
                proxy_pass http://tcsrvs;
        }
}
[root@Director ~]# nginx

tomcat-node-1和tomcat-node-2:参考以上配置

测试访问:http://www.fenghong.tech/;实现同一IP的客户端调度到同一后端server上

Tomcat的会话集群

  • session cluster:delta session manager;会话集群,对带宽消耗较大,集群规模建议3-5台
  1. 默认多播地址:228.0.0.4
  2. 多播通信使用的端口:45564
  3. IP广播的方式来实现获取主机名,主机IP地址等,不能是监听在127.0.0.1
  4. 侦听复制消息的TCP端口是范围:4000-4100
  5. 必须配置集群会话监听器
  6. 各集群时间必须同步

img

前端nginx配置:

upstream tcsrvs {
        server 192.168.0.10:80;
        server 192.168.0.11:80;
}
server {
        listen 80;
        server_name www.fenghong.tech;
        location / {
                proxy_pass http://tcsrvs;
        }
}

tomcat-node-1:

[root@tomcat-node-1 ~]# vim /etc/tomcat/server.xml
      <Host name="node1.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">
#channelSendOptions:发送消息的信道选项,0-15
          <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>
#Manager:定义新的会话管理器DeltaManager
#expireSessionsOnShutdown:一旦把当前Tomcat节点关闭,是否将这节点的Tomcat会话失效,false表示不失效
#notifyListenersOnReplication:现在如果要发送资源同步给其他节点,是否通知侦听器资源变动,必须打开
          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
             #McastService:多播通信
             #address:多播通信地址
             #port:端口
             #frequency:每隔多长时间发送一次自己的心跳信息,单位ms
             #dropTime:在3000ms内没有收到对方的心跳信息表示已经不是集群成员了
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="192.168.0.10"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>
             #NioReceiver:异步IO
             #address:监听地址,需要修改为集群成员通信的网卡
             #port:端口,如果不指定则自动选择4000-4100内从4000开始选择一个没有被占用的端口
             #autoBind:自动绑定
             #selectorTimeout:挑选器的超时时长
             #maxThreads:最大线程数,集群成员节点数 - 1
            <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>
#Channel:定义多播集群通信信道
#Membership:定义成员关系
#Receiver:接受器
#Sender:将自己的会话资源变动同步给其他节点
          <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>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="node1-dongfei-tech_access." suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
          </Host>
[root@tomcat-node-1 ~]# mkdir /data/webapp/ROOT/WEB-INF
[root@tomcat-node-1 ~]# cp /etc/tomcat/web.xml /data/webapp/ROOT/WEB-INF/
[root@tomcat-node-1 ~]# vim /data/webapp/ROOT/WEB-INF/web.xml
    <distributable/>  #添加到web-app内
[root@tomcat-node-1 ~]# systemctl restart tomcat

tomcat-node-2:

[root@tomcat-node-2 ~]# vim /etc/tomcat/server.xml
      <Host name="node2.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
        <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.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="192.168.0.11"
                      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>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="node2-dongfei-tech_access." suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
          </Host>
[root@tomcat-node-2 ~]# mkdir /data/webapp/ROOT/WEB-INF
[root@tomcat-node-2 ~]# cp /etc/tomcat/web.xml /data/webapp/ROOT/WEB-INF
[root@tomcat-node-2 ~]# vim /data/webapp/ROOT/WEB-INF/web.xml
    <distributable/>  #添加到web-app内
[root@tomcat-node-2 ~]# systemctl restart tomcat

需要在前端调度器做将会话绑定,配置后端的Tomcat会话集群一同使用

使用mencached保存Tomcat会话信息

  • session server:redis(store), memcached(cache);利用会话服务器保存会话信息

img

mencached配置:

[root@mem-1 ~]# yum install memcached -y
[root@mem-1 ~]# systemctl start memcached
[root@mem-1 ~]# ss -tnl |grep 11211
LISTEN     0      128          *:11211                    *:*
LISTEN     0      128         :::11211                   :::*

msm配置:在tomcat服务器中配置

项目地址:https://github.com/magro/memcached-session-manager

[root@tomcat-node-1 ~]# mkdir msm
[root@tomcat-node-1 ~]# cd msm
[root@tomcat-node-1 msm]# wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager/2.3.0/memcached-session-manager-2.3.0.jar
[root@tomcat-node-1 msm]# wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager-tc7/2.3.0/memcached-session-manager-tc7-2.3.0.jar
[root@tomcat-node-1 msm]# wget http://repo1.maven.org/maven2/net/spy/spymemcached/2.12.3/spymemcached-2.12.3.jar
[root@tomcat-node-1 msm]# mkdir kryo
[root@tomcat-node-1 msm]# cd kryo/
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/de/javakaffee/msm/msm-kryo-serializer/2.3.0/msm-kryo-serializer-2.3.0.jar
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/de/javakaffee/kryo-serializers/0.42/kryo-serializers-0.42.jar
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/com/esotericsoftware/kryo/4.0.2/kryo-4.0.2.jar
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/com/esotericsoftware/minlog/1.3.0/minlog-1.3.0.jar
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/com/esotericsoftware/reflectasm/1.11.7/reflectasm-1.11.7.jar
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/org/ow2/asm/asm/6.2/asm-6.2.jar
[root@tomcat-node-1 kryo]# wget http://repo1.maven.org/maven2/org/objenesis/objenesis/2.6/objenesis-2.6.jar
[root@tomcat-node-1 ~]# tree msm/
msm/
├── kryo
│   ├── asm-6.2.jar
│   ├── kryo-4.0.2.jar
│   ├── kryo-serializers-0.42.jar
│   ├── minlog-1.3.0.jar
│   ├── msm-kryo-serializer-2.3.0.jar
│   ├── objenesis-2.6.jar
│   └── reflectasm-1.11.7.jar
├── memcached-session-manager-2.3.0.jar
├── memcached-session-manager-tc7-2.3.0.jar
└── spymemcached-2.12.3.jar
[root@tomcat-node-1 ~]# cp msm/*.jar /usr/share/java/tomcat/
[root@tomcat-node-1 ~]# scp msm/*.jar 192.168.0.11:/usr/share/java/tomcat/
[root@tomcat-node-1 ~]# scp msm/kryo/*.jar 192.168.0.11:/usr/share/java/tomcat/

tomcat-1配置:

[root@tomcat-node-1 ~]# vim /etc/tomcat/server.xml
<Host name="node1.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
  <Context path="/" docBase="ROOT" reloadable="">
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
      memcachedNodes="n1:192.168.0.12:11211,n2:192.168.0.13:11211"
      failoverNodes="n2"
      requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
      transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
      />
  </Context>
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
         prefix="node1-dongfei-tech_access." suffix=".log"
         pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
[root@tomcat-node-1 ~]# cat /data/webapp/ROOT/index.jsp 
<%@ page language="java" %>
<html>
        <head><title>TomcatA</title></head>
        <body>
                <h1><font color="red">TomcatA.fenghong.tech</font></h1>
                <table align="centre" border="1">
                        <tr>
                                <td>Session ID</td>
                        <% session.setAttribute("fenghong.tech","fenghong.tech"); %>
                                <td><%= session.getId() %></td>
                        </tr>
                        <tr>
                                <td>Created on</td>
                                <td><%= session.getCreationTime() %></td>
                        </tr>
                </table>
        </body>
</html>

tomcat-2配置:

[root@tomcat-node-2 ~]# vim /etc/tomcat/server.xml
<Host name="node2.fenghong.tech" appBase="/data/webapp" unpackWARs="true" autoDeploy="true">
  <Context path="/" docBase="ROOT" reloadable="">
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
      memcachedNodes="n1:192.168.0.12:11211,n2:192.168.0.13:11211"
      failoverNodes="n2"
      requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
      transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
      />
  </Context>
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
         prefix="node2-dongfei-tech_access." suffix=".log"
         pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
[root@tomcat-node-2 ~]# cat /data/webapp/ROOT/index.jsp 
<%@ page language="java" %>
<html>
        <head><title>TomcatB</title></head>
                <body>
                <h1><font color="blue">TomcatB.fenghong.tech</font></h1>
                <table align="centre" border="1">
                        <tr>
                                <td>Session ID</td>
                        <% session.setAttribute("fenghong.tech","fenghong.tech"); %>
                                <td><%= session.getId() %></td>
                        </tr>
                        <tr>
                                <td>Created on</td>
                                <td><%= session.getCreationTime() %></td>
                        </tr>
                </table>
                </body>
</html>

测试:

访问www.fenghong.tech查看会话是否会变动

将memcached-1停止会话是否正常保持

Tomcat的常用优化配置

  • /etc/sysconfig/tomcat, /etc/tomcat/tomcat.conf

内存空间:

JAVA_OPTS="-server -Xms32g -Xmx32g -XX:NewSize= -XX:MaxNewSize= "
	-server:服务器模式
	-Xms:堆内存初始化大小;
	-Xmx:堆内存空间上限;
	-XX:NewSize=:新生代空间初始化大小;					
	-XX:MaxNewSize=:新生代空间最大值;

线程池设置:

<Connector port="8080" protocol="HTTP/1.1"  connectionTimeout="20000" redirectPort="8443" />
	maxThreads:最大线程数;
	minSpareThreads:最小空闲线程数;
	maxSpareThreads:最大空闲线程数;
	acceptCount:等待队列的最大长度;
	URIEncoding:URI地址编码格式,建议使用UTF-8;
	enableLookups:是否启用dns解析,建议禁用; 
	compression:是否启用传输压缩机制,建议“on";
	compressionMinSize:启用压缩传输的数据流最小值,单位是字节;
	compressableMimeType:定义启用压缩功能的MIME类型;
		text/html, text/xml, text/css, text/javascript

禁用8005端口;

<Server port="-1" shutdown="SHUTDOWN">

隐藏版本信息:

<Connector port="8080" protocol="HTTP/1.1"  connectionTimeout="20000" redirectPort="8443" />
	Server="SOME STRING"

JVM

内存分配参数:

-Xmx:堆内存(新生代和老年代)的最大空间;
-Xms:初始分配内存空间;
-XX:NewSize:新生代空间大小;
    -Xms-(-XX:NewSize)
-XX:MaxNewSize:新生代的最大空间;
    -Xmx-(-XX:MaxNewSize)

指定垃圾收集器:-XX:

UseSerialGC:运行于Client模式下,新生代是Serial, 老年代使用SerialOld
UseParNewGC:新生代使用ParNew,老年代使用SerialOld
UseParalellGC:运行于server模式下,新生代使用Serial Scavenge, 老年代使用SerialOld
UseParalessOldGC:新生代使用Paralell Scavenge, 老年代使用Paralell Old
UseConcMarkSweepGC:新生代使用ParNew, 老年代优先使用CMS,备选方式为Serial Old
    CMSInitiatingOccupancyFraction:设定老年代空间占用比例达到多少后触发回收操作,默认为68%;
    UseCMSCompactAtFullCollection:CMS完成内存回收后是否要进行内存碎片整理;
    CMSFullGCsBeforeCompaction:在多次回收后执行一次内存碎片整理;
ParalellGCThreads:并行GC线程的数量;

JVM常用的分析工具:

  • jps:用来查看运行的所有jvm进程;
  • jinfo:查看进程的运行环境参数,主要是jvm命令行参数;
  • jstat:对jvm应用程序的资源和性能进行实时监控;
  • jstack:查看所有线程的运行状态;
  • jmap:查看jvm占用物理内存的状态;
  • jhat:+UseParNew
  • jconsole:
  • jvisualvm:

jps:Java virutal machine Process Status tool

jps [-q] [-mlvV] [<hostid>]
	-q:静默模式;
	-v:显示传递给jvm的命令行参数;
	-m:输出传入main方法的参数;
	-l:输出main类或jar完全限定名称;
	-V:显示通过flag文件传递给jvm的参数;
	[<hostid>]:主机id,默认为localhost;

jinfo:输出给定的java进程的所有配置信息

jinfo [option] <pid>
	-flags:to print VM flags
	-sysprops:to print Java system properties
	-flag <name>:to print the value of the named VM flag

jstack:查看指定的java进程的线程栈的相关信息

jstack [-l] <pid>
jstack -F [-m] [-l] <pid>
	-l:long listings,会显示额外的锁信息,因此,发生死锁时常用此选项;
	-m:混合模式,既输出java堆栈信息,也输出C/C++堆栈信息;
	-F:当使用“jstack -l PID"无响应,可以使用-F强制输出信息;

jstat:输出指定的java进程的统计信息

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
-option:
	-class:class loader
	-compiler:JIT
	-gc:gc
		YGC:新生代的垃圾回收次数;
		YGCT:新生代垃圾回收消耗的时长;
		FGC:Full GC的次数;
		FGCT:Full GC消耗的时长;
		GCT:GC消耗的总时长;
	-gccapacity:统计堆中各代的容量
	-gccause:
	-gcmetacapacity
	-gcnew:新生代
	-gcnewcapacity
	-gcold:老年代
	-gcoldcapacity
	-gcutil
	-printcompilation
interval:时间间隔,单位是毫秒;
count:显示的次数;

jmap:Memory Map, 用于查看堆内存的使用状态

jhat:Java Heap Analysis Tool

jmap [option] <pid>
jmap -heap <pid>  #查看堆空间的详细信息
jmap -histo[:live] <pid>  #查看堆内存中的对象的数目,live:只统计活动对象
jmap -dump:<dump-options> <pid>  #保存堆内存数据至文件中,而后使用jvisualvm或jhat进行查看
	dump-options:
		live       
		format=b
		file=<file>

感谢阅读!

上一篇
Varnish