暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Tomcat中的compression压缩属性

中间件技术讨论圈 2016-06-22
1398

带宽是比较宝贵的资源,而作为web服务器传输的内容的多少,直接影响到网站的上行和下行带宽,因此对传输的文本进行压缩,这是一个非常明智的选择。

本文将会带您探讨Tomcat中的compression相关的压缩属性,http响应头,和senfile的互斥性。


1.http响应头中压缩相关属性

http的响应头中,已经对压缩进行了定义,是Content-Encoding属性:

传输内容编码:Content-Encoding
内容编码,即整个数据信息是在数据器端经过怎样的编码处理,然后客户端会以怎么的编码来反向处理,以得到原始的内容。这里的内容编码主要是指压缩编码,即服务器端压缩,客户端解压缩。
可以参考的值为:gzip,compress,deflate和identity。

通常压缩方式都是gzip格式的,当选择gzip的时候,整个html文本会被进行一次gzip格式的压缩:


从上图的分析可以看出来,java版本的实现有GZIPOutputstream可以进行gzip的实现了,并且对于servlet可以查看通过查看httprequest来看这个属性是否支持gzip,如果支持的话,那么浏览器端也会进行gzip相应的解压。

除了这个Content-Encoding属性,其实还有两个比较重要的属性,容易和Content-Encoding属性混淆:

传输数据编码:Transfer-Encoding
数据编码,即表示数据在网络传输当中,使用怎么样的保证方式来保证数据是安全成功地传输处理。可以是分段传输,也可以是不分段,直接使用原数据进行传输。
有效的值为:chunked和Identity.
传输内容格式:Content-Type
内容格式,即接收的数据最终是以何种的形式显示在浏览器中。可以是一个图片,还是一段文本,或者是一段html。内容格式额外支持可选参数,charset,即实际内容的字符集。通过字符集,客户端可以对数据进行解编码,以最终显示可以看得懂的文字(而不是一段byte[]或者是乱码)。

上述的属性,可以有下面的图来进行解释:


Content-Type是代表着格式,这个一般不会混淆,

而Content-encoding这个是内容编码格式,实际上就是压不压缩传输,

Trandfer-encoding这个是传输的方式,大白话也就是分不分块,

上述的三个属性就是http响应头中的格式,我们主要关注的是Content-encoding,当然我们在解析Tomcat的代码时,还会看到其余的两个属性的踪影。


2.Tomcat中的压缩实现

对于压缩的处理,是在Tomcat中的响应头中,也就是Response的commit的时候,开始对输出流进行处理,而如果Content-encoding是gzip的话,那么会在Http11Processor中的输出流filter链条中,加上一个GzipOutputFilter:


Http11Processor是Tomcat前端比较重要的处理类,Work工作线程将任务交给Http11Processor开始继续干活,Http11Processor接着会攒出Request和Response,并基于Mapper进行调用,从而进入容器中。

而XXXFilter这里的filter不是容器端的filter,而是在Response进行commit提交的时候,基于响应头的Tomcat的配置,是否执行相关的处理。

以这个compression为例,当在Tomcat中配置了compression的话,GzipOutputFilter就开始自动执行过滤,从上面的代码逻辑可以看到,实际上就是基于流的包装机制,使用GzipOutPutStream来再对当前的流进行一次包装,然后在OutputBuffer最终commit的时候,调用这个GzipOutputFilter,最终执行doWrite方法,让输出流中的字节进行压缩。

从上述的分析可以看出,Tomcat的压缩实现实际上就是GzipOutputStream,只不过采用了GzipOutputFilter责任链的模式,通过流的一层一层的包装,将输出的字节进行了压缩。


3.Tomcat中的压缩配置与实现

我们再看看Tomcat中的关于压缩的配置,主要是三个属性,每一个通道都可以配置:


compression:这个属性是开启压缩属性(默认就是开的),也可以设置关闭和强制压缩(当然你浏览器端要是不支持解压缩会报错);

compressableMimeType:对什么格式的文本执行压缩

compressionMinSize:当发送的文件的大小大于多少时候,才进行压缩,小于这个配置数不进行压缩,默认为2048。

我们来看看这三个属性是怎么实现的,还是回到Http11Processor类中的action方法:


当为commit的时候,一共有两步的操作,第一步是准备一个Response,第二步是调用OutputBuffer进行commit;

对于第二步前面已经讲过,如果是gzip的话,会调用GzipFilter进行GzipOutputStream的包装,这样输出流自动就是压缩的;

第一步,我们在sendfile的实现中也接触过,prepareResponse方法,就是通过Tomcat的配置,对响应头进行解析并设置,我们来仔细分析一下这个prepareResponse方法中涉及compression的部分代码


其中主要有两个标识比较关键,

一个标识是isCompressable,这个标识对应的方法也是isCompressable方法,该方法主要是解析上面的几个配置,判断是否满足当前响应头的压缩的条件;

第二个标识是useCompression,这个标识对应的方法也是useCompression方法,该方法主要是通过Request来查找accept-encoding,use-agent等几个属性,来判断浏览器端是否支不支持压缩;

这两个条件都满足的话,可以看到最后一步,OutputBuffer加入GzipOutputFilter,然后设置响应头的Content-Encoding为gzip。


这个就是整个Tomcat的压缩部分的全部实现。


4.与sendfile的互斥性


sendfile我们了解,实际是一种操作系统级别的优化手段,直接跳过内存转接,直接从内核缓冲区到网卡缓冲区,相当于高效;

但是我们在查询Tomcat文档的时候,发现sendfile和compression是不兼容的,也就是上图中的红色字体部分,这个是为什么呢?

可以这么来理解,对于compression必然需要在内存转接中进行操作,也就是下图中用户空间部分:


而我们了解到senfile实际是将这部分给省略掉了;

因此,就会出现上述的英文了:

There is a tradeoff between using compression (saving your bandwidth) and using the sendfile feature (saving your CPU cycles). 

是一个tradeoff(妥协),如果你使用compression,带宽是省了,但是cpu是浪费了,如果你使用sendfile,cpu是省了,但是带宽你是浪费了,

总结下来,就是天下没有完美的午餐。


总结:

当配置Compression为gzip时,在Tomcat中是采用GzipOutputStream来实现的,而更要记住的是,Sendfile和Compression这两个优化选项只能选择其一来使用!



文章转载自中间件技术讨论圈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论