tomcat一般部署都很简单,但是对于java程序来说性能优化、内存溢出问题比较多。现在容器化火热java程序与容器化结合问题又是一大堆。
1、探讨tomcat工作模式
Tomcat做为WEB服务器,OSI七层模型、TCP/IP四层大家要去了解熟悉一哈。三次握手(建立连接),四次握手(断开连接)。

  • A、Bio
    默认模式阻塞式IO,一个线程处理一个请求。并发量大的时候,创建的线程数就越多,浪费资源就越多。
  • B、Nio
    是Java SE 1.4以后续版本提供的一种新的I/O操作方式(即:java.nio包及其子包);是一个基于 缓存区、并提供非阻塞I/O操作的Java API,它拥有比传统的I/O操作(BIO)更好的并发运行性能。Tomcat8以上都是默认的nio模式,不需要修改。
    protocol="HTTP/1.1"修改成protocol=“org.apache.coyote.http11.Http11NioProtocol”
  • C、Arp
    简单来说,就是从操作系统级别解决异步IP问题,大幅度的提高服务器的处理和响应性能,也是tomcat运行高并发应用的首选模式。
    1、arp的安装
    Apr地址包http://apache.fayea.com/apr/
    #源码安装
    wget http://apache.fayea.com/apr/apr-1.6.3.tar.gz
    wget http://apache.fayea.com/apr/apr-util-1.6.1.tar.gz
    tar -zxvf apr-1.6.3.tar.gz -C /usr/local/ && mv apr-1.6.3 apr
    tar -zxvf apr-util-1.6.1.tar.gz -C /usr/local/ && mv apr-util-1.6.1 apr-util
    ## 安装
    ./configure --prefix=/usr/local/apr
    make && make install
    ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
    make && make install
    2、tomcat-native安装
    cd /usr/local/tomcat/bin tar -zxvf tomcat-native.tar.gz
    cd tomcat-native-1.1.22-src/jni/native
    ./configure --with-apr=/usr/local/apr
    make && make install
    3、arp环境变量
    vim /etc/profile
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib
    # 执行 source /etc/profile 立即生效
    4、修改http协议
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"/>
    5、修改AJP协议
    <Connector port="8109" protocol="org.apache.coyote.http11.Http11AprProtocol" redirectPort="8443" />
    

在catalina.out中启动日志查看使用那种运行模式:
Starting ProtocolHandler [“http-bio-8080”] ## BIO模式
Starting ProtocolHandler [“http-nio-8080”] ## NIO模式
Starting ProtocolHandler [“http-apr-8080”] ## APR模式

2、探讨tomcat性能优化
tomcat参数优化:server.xml(这里我拿线上环境的参数来讲解tomcat8.5.x版本)

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="30000"
               redirectPort="8443"
               maxConnections="20000" 
               maxThreads="1000"
               minSpareThreads="50"
               maxSpareThreads="200"
               acceptCount="1000"
               keepAliveTimeout="120000"
               enableLookups="false"
               compression="on"
               compressionMinSize="2048"
           	   maxKeepAliveRequests="1"
           	   compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,application/json,application/xml"
/>
第一个protocol="HTTP/1.1"这里默认是长连接,开启Connect:keep-alive。一个TCP连接可以传输多个HTTP请求和相应,减少了建立和断开连接的消耗和延迟。
connectionTimeout:Connector从接受连接到提交URI的等待的时间
maxConnections:tomcat最大连接数
maxThreads:客户端请求最大线程数,默认值200
minSpareThreads:tomcat初始化创建的socket线程数
maxSpareThreads:tomcat连接器的最大空闲socket线程数
acceptCount:tomcat启动线程数最大等待数,接受排队的请求个数默认值100
keepAliveTimeout:下一次请求到来,tomcat保持该连接时间
enableLookups:禁用DNS查询提高响应速度
Compression:是否开启网页压缩,提高网页加载速度
compressionMinSize: 压缩大小,自定义
maxKeepAliveRequests:连接支持最大请求数。超过被关闭。-1表示禁用。
compressableMimeType:压缩类型,自定义

tomcat参数优化catalina.sh(线上环境配置)
tomcat8.5.x+jdk1.8.191容器环境:

JAVA_OPTS="$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMPercentage=90.0 -Xss1024K -XX:NewRatio=2 -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/home/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/my.dump -XX:MaxDirectMemorySize=2G -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:CompressedClassSpaceSize=256m -XX:-ReduceInitialCardMarks -Djava.awt.headless=true -Dfineio.read_mem_limit=2 -Dfineio.write_mem_limit=1 -Duser.timezone=GMT+08"
这里我没有使用下面两个参数对tomcat内存限制,因为参数不可控不适用于容器
-Xmx 参数:最大堆内内存
-Xms 参数:初始化内存大小
-XX:+UnlockExperimentalVMOptions:解锁实验参数,允许使用实验性参数
-XX:+UseCGroupMemoryLimitForHeap:自动JVM检测去容器中最大堆的大小
-XX:MaxRAMPercentage:采用 0.0100.0 之间的值。这允许对允许 JVM 分配的 RAM 量进行细粒度控制。
上面参数要jdk版本最好java8u191以上版本使用,配合上面参数在外面进行cgroup限制,把资源控制的很稳定。
-Xss:单线程使用栈空间
-XX:MetaspaceSize:元数据缓存空间最小值
-XX:MaxMetaspaceSize:元数据缓存空间最大值
在java8+中已经没有Permsize永久代这个参数。
-XX:+PrintGCDateStamps:GC时打印日期信息
-XX:+PrintGCTimeStamps:GC打印时间戳信息
-XX:+PrintGCDetails:GC时打印更多详细信息
-Xloggc:发生GC时gc日志存储信息位置
-XX:+HeapDumpOnOutOfMemoryError:抛出内存溢出错误时导出堆信息到指定文件
-XX:HeapDumpPath:当HeapDumpOnOutOfMemoryError开启时候,dump文件的保存路径
-XX:NewRatio:堆内老年代和新生带大小比列
-XX:MaxDirectMemorySize:堆外内存参数设置
-XX:+UseParallelGC:并行收集器 
#补充:CMS收集器(并发收集器):暂停时间优先-XX:+UseConcMarkSweepGC
Parallel收集器(并行回收):吞吐量优先-XX:+UseParallelGC
-XX:UseParallelOldGC:老年代使用并行收集器
-XX:+UseAdaptiveSizePolicy:并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等。
-XX:+UseCompressedOops:普通对象指针压缩
-XX:+UseCompressedClassPointers:类指针压缩
##补充:UseCompressedClassPointers的开启是依赖于UseCompressedOops的开启,作用在于间接提高内存的利用率。
-XX:CompressedClassSpaceSize:设置块的空间大小
-XX:-ReduceInitialCardMarks:解决gc bug将性能优化策略关闭
-Djava.awt.headless:headless 模式是系统的一种工作模式,如果系统属性 java.awt.headless被设置true,那么headless工具包就会被使用
-Dfineio.read_mem_limit:fileIO读内存,建议读内存为写内存的2-3倍,缓存大小建议与写内存一致
-Dfineio.write_mem_limit:fileIO写内存,建议读内存为写内存的2-3倍,缓存大小建议与写内存一致
-Duser.timezone=:设置系统使用时区。

3、找到适合自己JVM参数配置方法
JVM参数配置方法
随着JAVA版本不同,处理方法也不同,见下表:
在这里插入图片描述
JDK8版本小于131时,启动JAVA程序时,添加参数 -Xms64m -Xmx128m;java 8u131+和java 9+版本,添加两个参数-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap;JDK8版本高于191时,可以使用 MaxRAMPercentage,MaxRAMPercentage 值介于 0.0 到 100.0 之间,默认值为 25.0。

4、tomcat关于session会话共享
nginx方向代理/负载均衡多个tomcat集群,存在会话失效,数据丢失。我这里redis用的一主二从三哨兵,来存储sesssion信息,达到session的作用。
一般常用的三个依赖包
tomcat-redis-session-manager
jedis
commons-pool
在这里插入图片描述
配置文件tomcat/conf/context.xml

<Context>
    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
    <Valve className="com.naritech.nicole.gump.RedisSessionHandlerValve" />
    <Manager className="com.naritech.nicole.gump.RedisSessionManager"
    maxInactiveInterval="1800"
    sentinelMaster="mymaster" 
    password="xxxxx"
    sentinels="172.18.5.105:26379,172.18.5.106:26379,172.18.5.105:26379"/>
    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
</Context>

配置后,重启tomcat刷新页面会发现SessionID不会变,就达到session会话持久性,session共享目的。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐