让tomcat使用强制ETag参数解除浏览器对静态文件的缓存

Etag在HTTP1.1中有介绍,主要的作用就是在(css file, image, javascript file)文件

请求返回的http头加入ETag参数,Etag有服务器端生成,并且随着文件的改变而改变,这样浏览器端就会只重新请求获取 Etag发生变化的文件,减少浏览器端数据的流量,加快浏览器的反应速度,重要的是减轻服务器端的压力,所以服务器端Etag的实现就比较重要了。

ETag有两种,一种是弱类型的(Weak ETag),一种是强类型的(Strong ETag),强类型格式为ETag=”文件长-最后修改时间”,弱类型是在前面加上W/如:W/”文件长-最后修改时间”,在浏览器中监控如下:

1.第一次请求一个静态文件返回:

HTTP/1.1 200 Ok
ETag: W/"1837-1431071955000"

2.第二次请求:

If-None-Match: W/"1837-1431071955000" 
If-Modified-Since: Fri, 08 May 2015 07:59:15 GMT

返回:

HTTP/1.1 304 Not Modified 
ETag: W/"1837-1431071955000" 
Date: Fri, 28 Oct 2016 02:47:04 GMT 

默认情况下使用弱类型的ETag浏览器会忽略设个机制,而且tomcat默认就是使用的这种机制,所以当你更新一个静态文件比如脚本啊或者一个样式文件,发现浏览器里面还是原来的文件,必须清理缓存或者在文件后面加上一个参数才能自动更新浏览器的缓存,而且tomcat也没有可配置的地方能够配置tomcat使用请类型的ETag,下面提供一个方法来修改这个机制,就是继承类org.apache.naming.resources.FileDirContext,重写doGetAttributes,在返回的属性中加入强类型ETag就可以了,代码如下:

package cn.fullstacks.tomcat;

import java.io.File;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

/**
 * 在http返回头中返回强类型ETag代替tomcat的弱类型ETag
 * 在context.xml中配置
 * <Resources className="cn.fullstacks.tomcat.ETagFileDirContext" />
 * @author Administrator
 *
 */
public class ETagFileDirContext extends org.apache.naming.resources.FileDirContext {

	@Override
	protected Attributes doGetAttributes(String name, String[] attrIds)
			throws NamingException {
		File file = file(name);

		if (file == null) {
			return null;
		}
		FileResourceAttributes fra = new FileResourceAttributes(file);
		fra.setETag("\"" + fra.getContentLength() + "-" +fra.getLastModified() + "\"");
		return fra;
	}

}

在tomcat的配置文件context.xml中加入配置如下:

<context>
    <Resources className="cn.fullstacks.tomcat.ETagFileDirContext" />
...
</context>

这样请求返回的ETag如下:

HTTP/1.1 200 Ok
ETag: "7664-1477637145682"

这样每次更新静态文件只要最后修改日期变更,那么浏览器必定会重新加载,这样就解决了浏览器静态文件缓存更新的问题。



nginx和tomcat集成后重定向引发的问题解决

nginx作为反向代理,监听端口非80端口比如使用88端口,tomcat监听的端口8080,这种情况下当发生302重定向的时候,tomcat默认会重定向到80端口,根本原因就是tomcat的repose的头部带的location的端口默认是80端口,这样nginx就会重定向到80端口导致系统无法访问。如果nginx监听的是80端口自然不会存在这样的问题。

知道问题的根本原因是头部的location不对导致的,那么处理办法就很简单了,这里有两种办法:

1.治标不治本的办法,配置nginx,修改location达到解决问题

proxy_redirect     http://host http://host:88;

2.从根本上解决问题,修改tomcat配置,配置代理的端口

在server.xml配置文件中http的connector节点加入了proxyPort="88"就可以了。

Tomcat在设计的时候是对这种代理服务器和Tomcat集成的情况做了考虑,80端口之所以没问题是因为port为空,浏览器会默认走80端口,如果nginx这代理服务器不是80这个端口应该需要配置proxyPort的属性的,这样就不会遇到这个问题。

Linux下安装Tomcat7与优化

默认情况下tomcat的配置适合开发模式或者比较小的系统应用,当访问量稍微多的时候比如1000人同时在线做一些频繁的业务操作的时候,可能性能方面就会存在问题,所以有必要在生产环境下对tomcat做一些优化。

tomcat 常用运行模式有3种,分别为 bio,nio,apr.生产环境建议用apr,从操作系统级别来解决异步的IO问题,大幅度的提高性能.

1.准备材料

apache-tomcat-7.0.65.tar.gz , 下载地址https://tomcat.apache.org/download-70.cgi ,下载apr 地址http://apr.apache.org/ ,下载两个文件apr-1.5.2.tar.gz和apr-util-1.5.4.tar.gz

2.安装

apr的安装

tar zxvf apr-1.5.2.tar.gz
cd apr-1.5.2
./configure --prefix=/usr/local/apr
make
make install

安装在路径 /usr/local/apr

apr-util的安装

tar zxvf apr-util-1.5.4.tar.gz
cd apr-util-1.5.4
./configure --with-apr=/usr/local/apr/bin/apr-1-config 
make
make install

解压tomcat压缩包,并复制到/usr/local/tomcat7

tar zxvf apache-tomcat-7.0.65.tar.gz
cp -r apache-tomcat-7.0.65 /usr/local/tomcat7

安装tomcat-navtive

cd /usr/local/tomcat7/bin
tar zxvf tomcat-native.tar.gz //该文件在tomcat的bin目录下面
cd /usr/local/tomcat7/bin/tomcat-native-1.1.33-src/jni/native
./configure --with-apr=/usr/local/apr/bin/apr-1-config --with-java-home=/usr/java/jdk1.7.0_75/
make
make install

这里注意的地方就是系统一定要先安装好jdk,要不然会报错,确保环境变量echo $JAVA_HOME能够看到jdk的安装目录。

3.编辑文件bin/catalina.sh加载apr,在任意地方加入下面一行

CATALINA_OPTS="$CATALINA_OPTS -Djava.library.path=/usr/local/apr/lib"

4.编辑conf/server.xml使用apr运行模式

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" prestartminSpareThreads="true"
        maxThreads="1000" minSpareThreads="4" maxSpareThreads="500" acceptCount="700"/>
		
<Connector executor="tomcatThreadPool" URIEncoding="UTF-8" useBodyEncodingForURI="true" enableLookups="false"
               port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
               connectionTimeout="20000"
               redirectPort="8443" />

5.配置jvm运行参数,在bin目录下创建文件bin/setenv.sh

JAVA_OPTS="-Xms1024m -Xmx1024m -Xmn512m -Xss1024K -XX:PermSize=64m -XX:MaxPermSize=2048m -XX:+UseParallelGC"

jre版本不一样一些参数也不一样,可以参考详细的参数说明进行配置

6.配置数据库连接池,编辑文件conf/context.xml

 <Resource name="jdbc/fullstacks"
	author="Container"
	type="javax.sql.DataSource"
	username="root"
	password="123"
	driverClassName="com.mysql.jdbc.Driver"
	validationQuery="SELECT 1"
	logAbandoned="true"
	removeAbandoned="true"
	removeAbandonedTimeout="10"
	testOnBorrow="true"
	testWhileIdle="true"
	minIdle="1"
	maxIdle="20"
	maxWait="5000"
	maxActive="2000"
	initialSize="1"
	timeBetweenEvictionRunsMillis="10000"
	numTestsPerEvictionRun="10"
	minEvictableIdleTimeMillis="10000"
	url="jdbc:mysql://192.168.1.140:3306/fullstacks?useUnicode=true&amp;characterEncoding=UTF-8" />

数据库驱动程序需要复制到tomcat的lib目录下面才能使用。

7.spring中配置数据源

<bean id="dataSourceId" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName">
            <value>java:comp/env/jdbc/fullstacks</value>
        </property>
</bean>

8.优化网络参数,编辑文件/etc/sysctl.cnf

net.core.netdev_max_backlog = 32768 
net.core.somaxconn = 32768 
net.core.wmem_default = 8388608 
net.core.rmem_default = 8388608 
net.core.rmem_max = 16777216 
net.core.wmem_max = 16777216 
net.ipv4.ip_local_port_range = 1024 65000 
net.ipv4.route.gc_timeout = 100 
net.ipv4.tcp_fin_timeout = 30 
net.ipv4.tcp_keepalive_time = 1200 
net.ipv4.tcp_timestamps = 0 
net.ipv4.tcp_synack_retries = 2 
net.ipv4.tcp_syn_retries = 2 
net.ipv4.tcp_tw_recycle = 1 
net.ipv4.tcp_tw_reuse = 1 
net.ipv4.tcp_mem = 94500000 915000000 927000000 
net.ipv4.tcp_max_orphans = 3276800 
net.ipv4.tcp_max_syn_backlog = 65536

命令sysctl -p生效

9.配置linux打开文件和进程

编辑文件/etc/security/limits.conf ,在后面加入

* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535

以上需要重启机器才能生效,也可以使用命令行暂时配置

ulimit -u 65535
ulimit -n 65535

10.启动和关闭tomcat

bin/start.sh
bin/shutdown.sh

以上基本上就配置完了,大概1000的在用户没啥问题,根据服务器硬件配置可适当调整参数。

总结

性能的影响因素是多方面的,互相影响,首先是系统本身没问题,数据库的响应没问题,web容器顺畅,硬件顺畅,网络带宽足够,再使用一些小工具进行检测,只有在大量用户在实际的生产环境中使用系统,才能发现问题,找到问题的根源到底是哪一块引发的性能瓶颈,调整一下自然一切都变得顺畅。