日期:2014-05-16 浏览次数:20850 次
在java webapp开发过程中有很多需要下载图片的需求,一般情况下我们都是用tomcat/jetty等类似的java web 容器提供java web程序运行服务,由于web容器可以直接提供http服务,所以架构师往往就直接使用java容器来直接提供图片的下载服务,这种做法往往带来的大量用户下载是web容器运行效率不佳,有时会影响servlet页面的处理效率。尽管现代的web容器做了深度优化,处理效率比之以前大大提高,但是一旦用户数量上去后,依然存在进程假死,不提供服务的问题。
为什么使用java容器提供图片下载会出现这样的情况呢?我们首先需要看一下磁盘io的过程或者说步骤:
这样数据有一个复制的过程,会消耗更多的资源和时间,如果使用java.io话,jvm会把复制到用户态内存的数据切成小块在返回个java app,这样java处理文件的效率会更加低效。现在的操作系统提供了一种称之为“mmap”的技术,可以直接把内核态的内存地址映射成用户态的地址,这样减少了用户态和内核态内存拷贝的消耗,提高了性能。自从jdk1.4,java也引入了使用mmap的技术,提高了效率。一般情况下,web容器提供文件服务时首先需要读取文件数据到内存然后通过tcp发送个客户端浏览器,这个是通过jvm来处理的,一般情况下多了jvm这一层,效率并不会产生太大影响,但一旦用户数上来这看似很小的性能消耗会被无限放大,直接现象就是web容器不能提供服务。另一方面io本身就是一个相对慢的操作,即使是使用c开发,当用户量急剧上升时也可能会出现问题。所以现代操作系统提供了一个叫sendfile的技术,这是在操作系统级别做了优化的技术,可以提供高效的文件读取和传输,很多web服务器比如apache/nginx/lighthttpd都基于这个技术提供了组件,但遗憾的是无论是tomcat还是jetty都还不能提供这个支持。还有一个问题是java的tcp通讯模型问题,虽然java底层已经支持epoll模式,但jdk层的封装上还是selector模式,这与操作系统原生的epoll模式在网络接入和处理上存在差距。基于这3个方面的原因造成了java web容器的问题。
一般的解决方案的核心就是:让专业的人做专业的事。java web容器的作用是运行java web程序,运行动态页面,读取数据库,处理业务逻辑,对于一下静态的页面、图片、文件等直接让apache、nginx或者lighthttpd来提供服务。同时apache层还可以作为负载均衡,动态转发http请求到多个web 容器。