我们的大数据量查询是数据库分页的,
但是导出和打印功能是基于全部数据的.

系统投入使用后,对于导出和打印功能的使用远远要高于我们的预期.

而我们的系统的硬件设备是有限的 不能再升级了.

抓取内存大对象的时候,常常发现数百个5M以上的collection大对象

我们的这个系统不大,就是一个提供一些信息管理的,页面也不多(不到1000个 其中能有6 7百的页面是查询),但是并发访问量比较大,同时在线能有5000人,而并发的查询操作至少也有500了,其中大数据量(10万以上)的太多了.这个问题怎么办啊

哪位有好的解决办法 (不生成vo 和 vo的collection也许可以,但是这样改动太大了)
而且关键是 系统已经上线了, 不太可能重新开发所有的dao层 :'(

4G内存的机器(当然java只用了2g) websphere 6.0的机器
评论
liuwei2630 2007-07-12
我们3000多万条数据用的是预编译表,效率稍微好点
leadyu 2007-07-12
可以考虑采用流的方式,打印时不是把数据一次性全取出,而是分页取,然后不断往流里面写,类似Http Server的做法。这样内存占用较低,写个自己的BufferInputStream
lihy70 2007-05-25
fins 写道
其实这个问题的关键有3

1 导出/打印 都是全部数据,如果不把相关方法侵入到DAO里(我们没有用spring的jdbcTemplate),那么返回一个大的collection是必然的,此时会导致OOM.
2 导出使用的组件不管是 JXL也好POI也好,都会在内存中生成XSL文件的大对象,此时亦会导致OOM
3 这些操作常常是高并发,所以OOM产生的频率更是高的离谱



fins 写道
不行的 因为查询的条件不一样,每个人权限不一样
为每一种查询对应的结果都缓存,情况太多了

其实目前对于我们这种情况,没有完美解

我发这个帖子的目的 就是想集思广益 看看 到底有哪些方案,
当别人遇到问题的时候,希望这个帖子 以及帖子里各位朋友的回复能够提供一点点帮助

谢谢楼上的回复 :)



楼主说的没错。
以前我做过一个框架,
在这里就不再推广告叫lz去用了。
但可以谈一下我们怎么做cache,也许能(或缓解)lz的问题。
我们的cache是根据业务逻辑cache内容的。
例如,如果有个业务是list一个100万的表,
如果你cache所有的内容,机子内存肯定受不了,
如果不cache,每次到数据库去取,翻一页肯定很慢。

针对楼主的那些问题,我们一般有以下方案。
1, 如果list一个表,
可以用cache,我们的cache支持分段cache,就是说:
// 你可以写更多,这里函数用的jdk5缺省参数,它的意思是cache第一页,第二页,最后一页,假设每页显示200条数据,
 Cache.range(0, 200, 200, 400, 999800, 1000000);

导用一句话,就是“cache on need”,而不是cache所有你“可能”要用到的数据。


2,对于那些一次导出所有的数据,我们提供resultHandle,它保存一个结果集的handle,可以重复和共享使用,不占内存。

3,我们提供search操作一次可以返回所以结果,可以不组装对象,速度等同于jdbc。

你可以在下面得到我们的框架:
http://sourceforge.net/projects/dbcoat
unifly 2007-05-24
哈,给楼主提供一套方案吧,参考自我们系统内的一个全国性的大型项目……

主要思路是这样的:client通过Applet向server请求每页数据,然后通过Applet(利用jxl)写到Excel……
server端提供的是xml数据,这样还可以做到与后台无关……
对于较大量数据,将导出到n个Excel文件中,可以在client端指定每个Excel文件的最大记录数……

注意问题:由于受到安全沙箱的影响,需要给Applet签名,而JDK1.5以上需要创建可信任证书,JDK1.4利用自签名证书即可……

总结:优点是显而易见的,大幅减少对server的内存耗用,增加了系统的并发性……
缺点是对前台机器有较高要求,需要安装JRE……

btw:java还是很有搞头的啊……
fins 2007-05-20
不行的 因为查询的条件不一样,每个人权限不一样
为每一种查询对应的结果都缓存,情况太多了

其实目前对于我们这种情况,没有完美解

我发这个帖子的目的 就是想集思广益 看看 到底有哪些方案,
当别人遇到问题的时候,希望这个帖子 以及帖子里各位朋友的回复能够提供一点点帮助

谢谢楼上的回复
galaxystar 2007-05-20
缓存所有数据,文件可弄成字节码流,供下载!
然后,有数据更新时,在通知缓存重新load一遍数据!
其他方法,我感觉成本太昂贵了!
fins 2007-05-20
其实这个问题的关键有3

1 导出/打印 都是全部数据,如果不把相关方法侵入到DAO里(我们没有用spring的jdbcTemplate),那么返回一个大的collection是必然的,此时会导致OOM.
2 导出使用的组件不管是 JXL也好POI也好,都会在内存中生成XSL文件的大对象,此时亦会导致OOM
3 这些操作常常是高并发,所以OOM产生的频率更是高的离谱
davexin 2007-05-20
楼主可能有点没考虑好性能瓶颈的问题,如果并发是在查询,考虑改善查询性能,可以考虑作数据库群集,如果是由于webapp不能撑住的话,可以做webapp群集,如果是打印性能瓶颈,可以考虑采用打印的单独处理,不知道是否能解决你的问题,我以前做过2000多万用户量的系统,就是采用群集的方式,最大的时候每秒钟30万访问量。我没有遇到打印的问题,但是数据库问题和你的相似,可以分多个数据库,并且采用数据库的群集。不知道这个建议是否适合你的问题。
eonhy 2007-05-16
把WAS 6.0换成轻量级容器?节省一部分内存开销?
既然不想大改代码,这些东西总可以动吧?
eonhy 2007-05-16
换用JRockit JVM
可以改善和调整GC的性能,不妨试验一下
seadog 2007-05-14
如果瓶颈在xls的话,我有个比较简化的方法。比如你就用你的struts生成的html在最后输入的时候。在response里边设置一个输入参数。这样就能直接生成xls了。不要用java掉用操作xls的包
tangchao 2007-05-12
使用Cache服务器吧;将一些实时性不强的数据采取缓存策略。
比较常用的Cache服务器有负载均衡服务器F5带的RAMCache。
或者使用squid 来做缓存服务器。效果很好的。
luogl 2007-05-11
ahuaxuan 写道
fins 写道
打印就是用的浏览器的,但是也是打印全部(在隐藏帧里显示一个简单的表格,然后调用window.print 我也知道这方案不好,但是还有别的方法吗?)

这种打印挺好的,其他方法比如jasperreport生成pdf打印,或者applet打印,但是我觉得js打印是最好的

好象不能控制范围吧,java控制的打印方式是什么呢?
jimmy.shine 2007-05-10
对于打印,建议使用jasper report,在collection中放入大量数据是会让垃圾回收器回收不到。应当强制手动的进行垃圾收集。
frankies 2007-05-10
对于excel文件导出生成的问题,我建议不要用poi或jxl之类的工具包去生成文件,我们可以用xml+xsl->xml->把生成的xml另存为excel文件的形式。大家知道office2000之后的版本都支持xml格式.
xly_971223 2007-05-07
langds 写道
嘿,本人在些论坛已潜水多年,今天也来凑个热闹.
我个人认为,楼上的兄弟些提出了如此多的思路,虽然很开阔,但不真正实用.正如楼主所说,导致OutOfMemory的问题其实并非技术因素,而是需求和设计上的缺陷.事实上,楼上已经有一位兄弟给出了一个较实用且常用的方案:用时间换空间.
诸如电信及银行这样的海量数据应用中,几乎没有任何一个系统是真正做到了实时下载的.且不说OutOfMemory,当下载该文件的工作就是一个大问题,每个Server上所能接受的并发线程是有限的,如果太多用户在下载资源,就必然会导致系统的吞吐率极巨下降,这导致其它用户连一个简单的请求也都做不了,甚至如果这其中出现了锁表或线程挂起的情况将会使整个系统停止服务,这是致命的.
而事实上,或许用户并非真的就非常迫切地要求实时下载,往往一种更常见的作法就是在查询出结果后,通过将结果进行保存后,再稍后下载即可.换句话说就是用户在界面上点击"导出到文件"时,并非真正执行下载,而是将任务加入一个队列,由后台异步地并限制并发量地执行,将结果文件产生后存于文件系统,当文件生成完毕后,用户便可在界面上点击下载文件了.且该文件下载功能最好单独开启一个Server,该Server就只负责文件下载任务,这样就不会影响到系统的正常服务了.对于资源紧缺的用户来说,可以在一台机器上启动两个Server,也可以是垂直集群的方式.不用担心CPU的瓶颈,大多数的应用其实如果只跑一个Server,那么该台机器的CPU事实上是非常闲的.

单独开启一台服务器的方式 可以避免生成文件下载文件是对其他服务的影响 可以参考, 不过会增加企业的成本
ps:这种横向服务转纵向服务的方式可以解决很多webserver的问题
langds 2007-05-05
嘿,本人在些论坛已潜水多年,今天也来凑个热闹.
我个人认为,楼上的兄弟些提出了如此多的思路,虽然很开阔,但不真正实用.正如楼主所说,导致OutOfMemory的问题其实并非技术因素,而是需求和设计上的缺陷.事实上,楼上已经有一位兄弟给出了一个较实用且常用的方案:用时间换空间.
诸如电信及银行这样的海量数据应用中,几乎没有任何一个系统是真正做到了实时下载的.且不说OutOfMemory,当下载该文件的工作就是一个大问题,每个Server上所能接受的并发线程是有限的,如果太多用户在下载资源,就必然会导致系统的吞吐率极巨下降,这导致其它用户连一个简单的请求也都做不了,甚至如果这其中出现了锁表或线程挂起的情况将会使整个系统停止服务,这是致命的.
而事实上,或许用户并非真的就非常迫切地要求实时下载,往往一种更常见的作法就是在查询出结果后,通过将结果进行保存后,再稍后下载即可.换句话说就是用户在界面上点击"导出到文件"时,并非真正执行下载,而是将任务加入一个队列,由后台异步地并限制并发量地执行,将结果文件产生后存于文件系统,当文件生成完毕后,用户便可在界面上点击下载文件了.且该文件下载功能最好单独开启一个Server,该Server就只负责文件下载任务,这样就不会影响到系统的正常服务了.对于资源紧缺的用户来说,可以在一台机器上启动两个Server,也可以是垂直集群的方式.不用担心CPU的瓶颈,大多数的应用其实如果只跑一个Server,那么该台机器的CPU事实上是非常闲的.
SteveGY 2007-05-01
什么啊?这样的问题,呵呵,你们居然一定要在内存中解决所有的数据吗?无论如何,这个思路,都会遇到out of memory问题的。

1. 修改查询方式,不要生成collection,因为无论你的内存多大,随着业务的增长,数据量只会变大,内存是永远不够的。

2. 如果可以使用简单的流式文件格式生成输出,尽可能使用流式文件,什么是“流”式文件?就是不可逆向移动文件指针的字节流,这样的流可以很少使用内存,stdout, response就是典型的流式文件。对你现在的问题,csv, XLS的html格式都很合适。

3. 我曾经输出过一些大量数据行的报表,查询时,直接使用jdbc,循环fetch一行rowset,然后把数据填到格式化的htmlString中,response.write(htmlString); 再fetch下一行,这是最基本的jdbc fetch循环,好像这里每一个人都忘记了最基本的技能,这样的查询加输出根本不需要应用服务器的内存(当然还是要一点点的,基本上只有那一行rowset的内存就够了)。你甚至可以把response的buffer关掉,这样你的客户端,就可以看到类似行打印机一样的输出效果,呵呵,我的客户还比较喜欢这个效果,她说看着数据一行一行的输出比坐等5分钟白屏幕,然后瞬间看到结果更有安全感和成就感

现在,问题的关键就是,你能不能使用流式的输出字节流了,不使用字节流,这样的大量数据,逻辑上是没有一个简单的解决办法的。前面有人提了n个复杂的方法,疯掉了,还是KISS原则,仔细考虑一下。

想一下啊,你们谁见过哪一个数据库提供的查询工具,在做
select * from table_with_huge_lines;

的时候是在内存中把数据格式化好了再输出的??开玩笑
zerozone 2007-05-01
Lucas Lee 写道

1.
对于生成xls文件,我有一些经验。我用的POI。我发现,对于同样是将2万行的数据写入一个文件,放在一个sheet里和两个sheet里,内存占用能相差一倍,后者少。经过我的试验,一般一个sheet里1万行(一行有10几列)比较合适,多的就分sheet保存,可以有效的降低内存占用,约1--n倍。虽然不是终极的解决方案,也是一个可行的方案,不妨试试。


Lucas Lee说的有道理。我以前做HR产品,也有过类似经历。当从花名册导出XLS时,有时表格CELL超过100万,极易内存溢出。

改进途径:
1.修改Java Plugin 内存参数,效果不大;
2.当要导出的数据单元格超过10万时,输出不是一个而是多个XLS文件,也就是一拆多(以10万单元格为一单位),可有效避免大对象。

对极占用资源(如内存)的任务,应考虑“生产者-消费者模型+内存池”模型。数据由生产者(查询过程)从服务器端查询到内存池,消费者处理完数据从内存池移除旧数据...循环往复直到处理完毕。
nihongye 2007-04-30
可以算...,并发数量是500,每个大小是1m的话,那是500 * 1m = 500m。而如果io阻塞,每个请求都得不到释放。每个请求的临时对象是5m,那就,垃圾回收又不停在浪费cpu,继续导致。。我说的好象很象真的一样。试试才知道咯...
fins
  • 浏览: 743432 次
  • 性别: Icon_minigender_1
  • 来自: 小胖儿的大城
  • 详细资料
搜索本博客
我的相册
89757367-bcf7-3449-ae1d-31a5a2021dd7-thumb
customHead
共 76 张
其他分类
存档
最新评论