CAE开发日志(7):动静分离

来源:互联网 发布:docker windows 编辑:程序博客网 时间:2024/06/05 04:32

1、为什么需要动静分离

目前所有的静态资源(css、js、图片、html文件)都是直接放在CAE的后台代码处的,也就是说客户端请求每个静态资源时,这个请求都是交给tomcat来处理的。

我认为这样做是一种不好的设计,因为tomcat并不是一个非常健全的服务器,它仅仅是一个轻量服务器,和jetty一样,甚至有人认为tomcat根本就不能称作是“服务器”,它只是一个servlet容器。

CAE是一个读远大于写的项目,其中静态资源的请求更是重中之重,因为最重要的call表就是html文件,歌曲的封面就是图片文件,而tomcat并不是专业的静态文件服务器,对于静态资源并没有一个很好的管理机制和性能表现。

针对以上的情况,现考虑将tomcat中的静态资源独立出去,使用专门的静态文件服务器来承担静态资源的请求,即动静分离。


2、静态文件服务器的选择

静态文件服务器的方案目前市场上已经有一些成熟的服务器了,如nginx、squid、varnish等,以下是我认为可以列入参考范围内的服务器以及我调查后对它们的一些感觉。

nginx更倾向于反向代理,它的优点在于高并发的支持以及模块化。由于nginx是多进程的方式进行工作的,所以它能承载的连接数会比较多(当然是硬件设备满足的情况下),模块化使得未来可以方便地对nginx进行扩展,但是这个扩展需要用C++,目前组内还没有C++工程师。

squid是一个比较老牌的缓存服务器,很多老的项目都会使用它,但是varnish貌似在性能上可以超过它了,而且它的配置听说也比较麻烦,这里就淘汰掉吧。

varnish更倾向于前端加速,虽然它也是反向代理但是我感觉它更强调“加速”的概念,varnish可以让静态资源访问的速度更快的原因在于它的操作大多都在内存完成,其实就是“Visual Page Cache”技术。

对于目前的需求来说,应该是varnish最适合,但是varnish我已经用过了啊,想学点新东西,于是我便选择了nginx,其实目前的请求负担也不重,所以实际上用哪个也没什么所谓。以后随着请求量的增大,有可能会演变成nginx做反向代理(用于分派请求到应用服务器)、varnish做静态文件缓存。


3、nginx架构

nginx是使用多进程的方式来工作的,这些进程分为两类,一类是管理进程,管理进程只有一个,而且是必须开启,无法关闭的;另一类的工作进程,工作进程至少有一个,这个可以配置,当然配太高的话内存就会跟不上,所以要根据实际的情况来。

nginx的配置文件位于conf/nginx.conf,因为要做静态资源缓存,所以重要的就是路径的配置了,路径的配置位于server块的location中,配置完location后访问图片成功,然后在http头部发现服务器是nginx即完成配置。

我还了解到nginx、操作系统以及事件驱动模型之间还存在关系,正常情况下,nginx应该是部署在linux上的(当然这是废话,一般的服务器应该都在unix类的操作系统上的),当部署到linux上时,就可以在nginx的配置文件中配置事件驱动模型为epoll,epoll可以使得并发量大大提高,顺便一提linux需要2.6内核版本才有。

但是目前CAE的服务器是windows server。。。所以没有epoll的支持,目前还是使用最差的select事件驱动模型,这是一个遗憾,希望以后能迁移到linux服务器上吧。。


4、gzip压缩

有了nginx来专门管理静态资源在一定程度上已经解决了需求,而且tomcat也不需要承担静态资源的请求压力了,tomcat就应该注重于后台逻辑的计算。但是目前还有一个问题,那就是在加载静态资源时,特别是call表的html文件,安卓端的流量总是比较大,如果是wifi环境倒是没什么所谓,但是如果开流量的话每个call表至少需要0.5M的流量,因为本身html的文件大小也是差不多这个大小,再加上传输时的各种协议的头部,流量的负担可能会比较大,虽然客户端已经采用了一定的缓存机制来缓解这个问题,但是流量本身依然在那里。

为了减少流量,现在考虑在服务器响应静态资源前,先将静态资源压缩,然后客户端得到压缩包后解压来达到减少流量的效果。

那么目前最简单有效的压缩算法应该就是gzip了,nginx也原生支持了gzip算法,只需要在nginx.conf中进行配置即可启动。

客户端自然也需要支持gzip算法,目前从安卓那边了解到的情况来看,那边的框架也提供了gzip的支持。当然如果没有支持就要自己写了,java也提供了gzip的类来让开发者实现gzip。

使用压缩算法减少了传输文件的大小,但是它是建立在更多的内存和CPU消耗上的,但是目前这点消耗还不成问题,还不需要考虑。


5、tomcat的gzip

实际上在引入nginx之前已经有想过压缩的功能,而tomcat自己也提供了gzip的压缩,这个同样只需要在tomcat的配置文件中进行配置就可以开启。

但是经我实测后,得出一个结论,坑啊!

tomcat的gzip并不能对静态资源生效,我开启tomcat的gzip后,试着请求一个项目的主页,这个主页包含了很多图片,通过F12的network看到,只有主页的那个请求是gzip生效了的,但是图片并没有生效。

tomcat的连接器架构中,HttpConnector用来等待请求,HttpProcesser用来处理请求,HttpProcesser分为很多种类,但从大的方面来分的话就是两类,一类是servlet的HttpProcesser,另一类是静态资源的HttpProcesser。我的猜测是,当开启tomcat的gzip时,只有servlet的HttpProcesser才会进行gzip操作,而静态资源的HttpProcesser则是简单实现了事。

综上所述,还是不要指望tomcat的gzip了,老老实实用nginx吧。。


6、图片与gzip

使用nginx的gzip一段时间后,组内有人跟我说了一个奇怪的现象,图片的压缩反而变大了。

我不太相信,使用一些测试网站去进行gzip测试时发现确实出现了这种奇怪的现象,例如一张200K的文件,经过压缩不但没有变小,反而还增大了一点点,我开始还以为这是因为文件的大小太小了,所以不适合压缩,应该直接传输更好(学习的时候书上也的确给出了这样的建议),但是马上发现另外一个只有94K的js文件反而成功压缩了60%的大小。

同样的算法,为什么一个大文件经过压缩反而更大了,一个小文件经过压缩就能变小呢?好像并不是“文件太小不适合压缩”的问题。

后来查过资料后发现图片不应该被压缩,因为图片文件本身就是已经被压缩过的数据,数据压缩应该只针对文本文件,即js、html、css等,因此目前在nginx中图片那块location的gzip已经被关掉了。

后来我再稍微深入地了解了一下gzip算法的实现。gzip算法主要是由LZ77算法和哈夫曼树来实现的。

L7ZZ算法表达的意思就是,在一个文本中,总会有一些相同的字符串,只要将这些字符串都变成“<位置><长度>”(除了第一个以外)的形式,就可以使文本变短。例如现在有文本“aabbaaccaaddaa”,因为“aa”出现过多次,所以只需要记作“aabb(1,2)cc(1,2)dd(1,2)”就可以达到压缩的效果,当然,具体的算法还涉及到了最长字符串匹配等细节我就没有深入去了解了,但是这里已经可以基本解释为什么压缩图片反而会大了一些了,因为最长字符串匹配需要用一些辅助位来实现,但是图片的数据已经是压缩后的,所以并没有太多可以匹配成功的情况,所以这些辅助位反而变成了体积的一部分。

另外,哈夫曼树也可以用于压缩,扫描一个文件,根据一个字符串出现的频率来尽力一个哈夫曼树,因为树的结构比原本的文本更加纵向化,所以达到压缩的结果,具体的细节也没有深入去看了。

不得不说,数据压缩也是一个大坑啊,以后可以考虑新增一个专门研究数据压缩的位置,专门研究比gzip更厉害的压缩算法。

0 0
原创粉丝点击