高并发的大数据量查询导致系统频繁死机

高并发的大数据量查询导致系统频繁死机

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

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

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

抓取内存大对象的时候,常常发现数百个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,就是说:
Java代码 复制代码
  1. // 你可以写更多,这里函数用的jdk5缺省参数,它的意思是cache第一页,第二页,最后一页,假设每页显示200条数据,  
  2.  Cache.range(0200200400, 999800, 1000000);  
// 你可以写更多,这里函数用的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原则,仔细考虑一下。

想一下啊,你们谁见过哪一个数据库提供的查询工具,在做
Java代码 复制代码
  1. select * from table_with_huge_lines;  
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 2007-04-29
nihongye 写道
fins 写道
programmer 写道
解 决你的 excel问题,可以考虑生成csv。先在服务器生成一个临时文件来存放csv问题,然后查询数据,取数据放入stringBuffer 当此stringBuffer的数据大到一定程度时候就往文件里输出,然后清空StringBuffer 这样重复处理,直到查询出来的数据都写人文件。这样因该可以避免java的outofmemory。


类似的方法我们用过 我们是直接将 response.getOutputStream传入dao
在dao里生成 printwriter 然后直接 out.print
这个方法应该更好 避免了生成和修改文件

如果是直接使用response,这是不好的办法.可能因为io阻塞,导致对象不能及时释放。
Wrapper一个Response,写到自己实现的ByteArrayOuputStream


这样生成的ByteArrayOuputStream会不会也是大对象呢??
umbrella 2007-04-29
根据楼上的,是否可以这样做

每次打印都存在coolection内,重复的不加,不重复的加上,coolection对象有很多个,分组,分段,比如某个COOLECTION存第1-10000个对象,另一个存10001-20000的对象,根据打印哪些数据去从哪个COOLECTION内取数据。
lane_cn 2007-04-28
xly_971223 写道
lane_cn 写道
可以分析一下能不能在多个会话中共享一些对象,也许一个collection里面的元素和另一个collection的元素都是同一个,没必要建立一个新的,既浪费内存,又降低了效率。

想法不错 不过每个用户所需的数据可能不同 共享有些不太实际吧


collection是不能共享的,但是collection里面的元素应该是可以共享的。
比如用户A打印的报表上有一个合同,用户B打印的报表上也有这个合同,这个合同对象就可以共享了,每个collection里面只要有这个合同的引用就行了,节约内存40%以上。
nihongye 2007-04-28
fins 写道
programmer 写道
解 决你的 excel问题,可以考虑生成csv。先在服务器生成一个临时文件来存放csv问题,然后查询数据,取数据放入stringBuffer 当此stringBuffer的数据大到一定程度时候就往文件里输出,然后清空StringBuffer 这样重复处理,直到查询出来的数据都写人文件。这样因该可以避免java的outofmemory。


类似的方法我们用过 我们是直接将 response.getOutputStream传入dao
在dao里生成 printwriter 然后直接 out.print
这个方法应该更好 避免了生成和修改文件

如果是直接使用response,这是不好的办法.可能因为io阻塞,导致对象不能及时释放。
Wrapper一个Response,写到自己实现的ByteArrayOuputStream
nihongye 2007-04-28
del
xly_971223 2007-04-27
lane_cn 写道
可以分析一下能不能在多个会话中共享一些对象,也许一个collection里面的元素和另一个collection的元素都是同一个,没必要建立一个新的,既浪费内存,又降低了效率。

想法不错 不过每个用户所需的数据可能不同 共享有些不太实际吧
lane_cn 2007-04-27
可以分析一下能不能在多个会话中共享一些对象,也许一个collection里面的元素和另一个collection的元素都是同一个,没必要建立一个新的,既浪费内存,又降低了效率。
抛出异常的爱 2007-04-27
fins 写道
我们的大数据量查询是数据库分页的,
但是导出和打印功能是基于全部数据的.

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

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

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

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

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

4G内存的机器(当然java只用了2g) websphere 6.0的机器



用数据挖掘技术进行一定量的数据整理。
每台打印机不可能打5M左右的东西的。。。
放心吧总有能轧出来的性能的。

刚刚想点上一页
点了新手贴。。。
十二万分的抱歉。。。
权重太大了。。。
抛出异常的爱 2007-04-27
maoone2003 写道
如果无法提升硬件配置可以在导出或打印时控制每次打印或导出的行数,这个很容易做到的,我们以前是导出数据只要超过10W行就宕机,后来索性就只让每次导出1W行,如果客户觉得操作不便让他们内部协调提升硬件配置,要不好像没有别的解决办法啊.....


作程:定时器,延时器,多事务,哪个不能用?非要用户自己解决么?
pufan 2007-04-27
真是奇怪,不就是并发造成大对象过多引起out of memory error吗,最直观的方法就是控制并发数量了。
给你段代码:
Java代码 复制代码
  1. final int limit=10;  
  2. final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(limit, limit, 1 * 60, TimeUnit.SECONDS, new LinkedBlockingQueue());  
  3. public void outputExcel(HttpServletResponse rs,HttpServletRequest rq)  
  4. {  
  5. threadPool.execute(new Runnable() {  
  6.     public void run() {  
  7.          读取数据库;  
  8.                    生成xsl;  
  9.                    输出到response;  
  10.             }  
  11.     });  
  12.   
  13. }  
final int limit=10;
final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(limit, limit, 1 * 60, TimeUnit.SECONDS, new LinkedBlockingQueue());
public void outputExcel(HttpServletResponse rs,HttpServletRequest rq)
{
threadPool.execute(new Runnable() {
public void run() {
读取数据库;
生成xsl;
输出到response;
}
});
}

你只需根据内存大小改变limit值即可。
maoone2003 2007-04-27
如果无法提升硬件配置可以在导出或打印时控制每次打印或导出的行数,这个很容易做到的,我们以前是导出数据只要超过10W行就宕机,后来索性就只让每次导出1W行,如果客户觉得操作不便让他们内部协调提升硬件配置,要不好像没有别的解决办法啊.....
fins 2007-04-27
Lucas Lee 写道
fins 写道

我说的不太准确 其实是两个瓶颈 一个是 collection对象 一个是jxl生成的xls大对象
郁闷中 我打算研究一下excel的生成原理 自己做一个合并xls文件的程序
把多个文件 合并成一个有多个sheet页的xls文件 (用jxl poi做这类操作还是会生成很大很大的对象)


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


2.
csv是简单文本格式,内存占用量必定比xls少很多倍,但是他基本上无法表达格式。实在不行就用csv好了。


3.
还有一个曲线救国的方法,就是用html格式,技巧是,将html文件保存成xls后缀文件(假装为xls),excel是可以自动识别为 html并打开,也可以保存格式。唯一的不同是,用户需要“真实”的xls格式的话,需要用Excel打开后另存为xls格式。其实用户不就是打印么,那 么应该没有区别。


1 3 策略我们现在的系统都用到了
问题就是老系统 我主贴中提到的是一个老系统 郁闷啊

不过还是谢谢大家提供的方案
其实仔细看看,可以说,楼上各位的方案基本上已经涵盖了 所有的 xls的解决方法
我可以把这个帖子作为一个 方法的汇总帖了 呵呵

谢谢各位!!!
如果我们老大允许我们大刀阔斧的改造代码 一切就都OK了
现在也许问题已经不是出在方法和技巧上 而是人的问题了

以前系统设计的不够好 ,让现在的人为过去埋单,似乎也是天经地义的.毕竟我也从前辈那学到过太多的东西
呵呵

再次谢谢大家
fins 2007-04-27
programmer 写道
解 决你的 excel问题,可以考虑生成csv。先在服务器生成一个临时文件来存放csv问题,然后查询数据,取数据放入stringBuffer 当此stringBuffer的数据大到一定程度时候就往文件里输出,然后清空StringBuffer 这样重复处理,直到查询出来的数据都写人文件。这样因该可以避免java的outofmemory。


类似的方法我们用过 我们是直接将 response.getOutputStream传入dao
在dao里生成 printwriter 然后直接 out.print
这个方法应该更好 避免了生成和修改文件
Lucas Lee 2007-04-27
fins 写道

我说的不太准确 其实是两个瓶颈 一个是 collection对象 一个是jxl生成的xls大对象
郁闷中 我打算研究一下excel的生成原理 自己做一个合并xls文件的程序
把多个文件 合并成一个有多个sheet页的xls文件 (用jxl poi做这类操作还是会生成很大很大的对象)


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


2.
csv是简单文本格式,内存占用量必定比xls少很多倍,但是他基本上无法表达格式。实在不行就用csv好了。


3.
还有一个曲线救国的方法,就是用html格式,技巧是,将html文件保存成xls后缀文件(假装为xls),excel是可以自动识别为 html并打开,也可以保存格式。唯一的不同是,用户需要“真实”的xls格式的话,需要用Excel打开后另存为xls格式。其实用户不就是打印么,那 么应该没有区别。
programmer 2007-04-27
解 决你的 excel问题,可以考虑生成csv。先在服务器生成一个临时文件来存放csv问题,然后查询数据,取数据放入stringBuffer 当此stringBuffer的数据大到一定程度时候就往文件里输出,然后清空StringBuffer 这样重复处理,直到查询出来的数据都写人文件。这样因该可以避免java的outofmemory。
fins 2007-04-26
sorphi 写道
fins,写完之后才发现你也提到了xls的写入才是瓶颈。

而且我刚才想了一下,我的方法中callback导致第2/3三条和第1条是冲突的。

既然方法被驳回了,那也说得过去。那就集中解决xls的生成问题吧

刚才google了一下csv -> xls的东西,虽然没找到什么有效的java代码,但是发现一个有趣的事情,有网站专门提供在线的转换。继而想到,何不单独提供一个应用来干这个事情呢?

不过用java来做这种转换,仍然摆脱不了内存占用较大的问题,看poi的API。jxl的我不清楚,照你说的,跟poi的差不多。

既然客户比较“变态”(查询这么贼多数据),那么何不让这种转换拿到client端来做呢?哈哈

继续google,activex+csv+xls

http://www.softinterface.com/Convert-Excel-ActiveX/Convert-Excel-ActiveX.htm



我说的不太准确 其实是两个瓶颈 一个是 collection对象 一个是jxl生成的xls大对象
郁闷中 我打算研究一下excel的生成原理 自己做一个合并xls文件的程序
把多个文件 合并成一个有多个sheet页的xls文件 (用jxl poi做这类操作还是会生成很大很大的对象)
nihongye 2007-04-26
考虑生成跟下载分成两个步骤。 另外既然内存占用那么多,jvm的内存调优也要考虑
sorphi 2007-04-26
fins,写完之后才发现你也提到了xls的写入才是瓶颈。

而且我刚才想了一下,我的方法中callback导致第2/3三条和第1条是冲突的。

既然方法被驳回了,那也说得过去。那就集中解决xls的生成问题吧

刚才google了一下csv -> xls的东西,虽然没找到什么有效的java代码,但是发现一个有趣的事情,有网站专门提供在线的转换。继而想到,何不单独提供一个应用来干这个事情呢?

不过用java来做这种转换,仍然摆脱不了内存占用较大的问题,看poi的API。jxl的我不清楚,照你说的,跟poi的差不多。

既然客户比较“变态”(查询这么贼多数据),那么何不让这种转换拿到client端来做呢?哈哈

继续google,activex+csv+xls

http://www.softinterface.com/Convert-Excel-ActiveX/Convert-Excel-ActiveX.htm
fins 2007-04-26
to sorphi:
谢谢你提供的方案
事实上类似的方案我也提了 但是由于系统中根本就没考虑到callback的设计 现在的dao都是写死的
改动比较大 已经被我们老大驳回了 :'(
pufan 2007-04-26
内存爆掉很好解决,使用线程池限制生成xls的并发数量不就得了。

sorphi 2007-04-26
抛个砖:

先确定几个可行的原则:
1、尽早的释放数据库连接
2、尽可能少的创建对象
3、用临时文件来代替jvm中的临时对象,缩短值对象的生命周期
4、缓存

ResultSet循环取值的时候,调用一个callback接口,该接口负责将各字段值直接放入到临时文件中。

interface ResultSetPersistCallback {
void appendRow(rs);
}

TextPersistCallback的具体实现是将每一行以csv的格式append到临时的文本文件中,这个没啥好说的,直接使用append模式的File即可

XlsPersistCallback的具体实现是每一行附加到临时的Excel中,这个比较麻烦了(POI的实现中,仍然在jvm中构建 HSSFWorkbook对象图,最后一次性写入xls文件,并且每个sheet还有65536的最大行限制),貌似没有好的方案能够缩短值对象的生命周 期。


rs循环完毕,释放数据库资源,关闭临时文件,维护缓存池,文件流发送到客户端。


缓存池结构:
key: sql key
value: CachedFile

class CachedFile{
String filepath;
long creationTime;
long period;
}

当然还少不了一个scheduler去掉过期的缓存和临时文件。
yeshucheng 2007-04-26
难道大对象都要一并的打印出来吗?
如果不是的话,我想还是要把大对象给单独提出来和你现有的表做个分割处理,毕竟大对象并不是大家所见既所得的东西,所以我的意见是把大对象单独做一个表来存储,可以和你现有的表做个一对一的关联而已,在不需要的时候并不需要带出来,这样可以很好的减轻服务端的负担
xly_971223 2007-04-26
fins 写道
瓶颈在
写xls文件 那里
由于xls文件的特殊性 他必须要在内存中形成一个完整的对象 然后再输出

分页只解决了 大的collection问题 但是解决不了jxl的问题

文件不能追加吗? 如果可以追加的话 还可以解决:创建文件关闭后 再打开追加数据
真要是必须一次创建完整文件的话 那就没什么招了
yiqing1982 2007-04-26
呵呵,其实也就是要么你苦一点,在你这边尽量优化;要么让用户麻烦点,让他们做点事情,腾出时间来给你们!
fins 2007-04-26
瓶颈在
写xls文件 那里
由于xls文件的特殊性 他必须要在内存中形成一个完整的对象 然后再输出

分页只解决了 大的collection问题 但是解决不了jxl的问题
xly_971223 2007-04-26
fins 写道
谢谢大家的回复 我再详细说说我的情况.

数据库使用 jdbc
现象就是内存耗尽
导出的文件格式 有xls csv
确实是所有结果都放入collection
打印就是用的浏览器的,但是也是打印全部(在隐藏帧里显示一个简单的表格,然后调用window.print 我也知道这方案不好,但是还有别的方法吗?)

文件导出xls格式可以用分页的方式, 可以避免一次从数据库中查询出所有对象:
Java代码 复制代码
  1. int pages = computePages();//查出页数  
  2. for(int i = 0; i < pages; i++){ //循环查询每页数据  
  3.     List records = findRecordByPageNo(i); //查询某页记录  
  4.     for(int j = 0; i < records.size(); i++){  
  5.         //写xls文件  
  6.     }  
  7. }  
int pages = computePages();//查出页数
for(int i = 0; i < pages; i++){ //循环查询每页数据
List records = findRecordByPageNo(i); //查询某页记录
for(int j = 0; i < records.size(); i++){
//写xls文件
}
}
ahuaxuan 2007-04-26
fins 写道
预生成 和 分页打印都不太可行
业务比较特殊

简单点说吧

假设某省联通客户数有1000万
就一个业务 查询 导出 打印 详单(就是这个客户呼出或接收的所有的电话短信),时间段分别是入网至今所有的 本月 上月 或者历史上的某一月

打印是使用的那种 特殊的连打的打印机,就是不接受换页指令的 放入的纸是那种一个筒的

如果可以的再搞一个应用,专门负责打印功能,在was上同时部署这两个应用,两应用访问同一个db,打印的应用只读。
fins 2007-04-26
预生成 和 分页打印都不太可行
业务比较特殊

简单点说吧

假设某省联通客户数有1000万
就一个业务 查询 导出 打印 详单(就是这个客户呼出或接收的所有的电话短信),时间段分别是入网至今所有的 本月 上月 或者历史上的某一月

打印是使用的那种 特殊的连打的打印机,就是不接受换页指令的 放入的纸是那种一个筒的
myreligion 2007-04-26
打印不可以使用全部的数据吧?一页几十条也就足够了,如果有许多页的话可以考虑打印一页读一次请求一次。

导出的话,如果一下子导出很多的话,楼上楼上的预生成应该是个不错的办法。

业务的逻辑是什么?
dennis_zane 2007-04-26
ahuaxuan 写道
fins 写道
打印就是用的浏览器的,但是也是打印全部(在隐藏帧里显示一个简单的表格,然后调用window.print 我也知道这方案不好,但是还有别的方法吗?)

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


是很好,可需要DTO填充Collection,生成大对象显示到页面,还是建议使用报表工具,比如jasperreport。
另外,如果查询结果改动频率小,可以考虑查询缓存
nihongye 2007-04-26
或者考虑是否适合预生成...
ahuaxuan 2007-04-26
fins 写道
打印就是用的浏览器的,但是也是打印全部(在隐藏帧里显示一个简单的表格,然后调用window.print 我也知道这方案不好,但是还有别的方法吗?)

这种打印挺好的,其他方法比如jasperreport生成pdf打印,或者applet打印,但是我觉得js打印是最好的
winterwolf 2007-04-26
先保证不拓机. 用iptable限定最大并发保护服务器

然后用集群顶顶看,再不行就慢慢改程序吧.
fins 2007-04-26
谢谢大家的回复 我再详细说说我的情况.

数据库使用 jdbc
现象就是内存耗尽
导出的文件格式 有xls csv
确实是所有结果都放入collection
打印就是用的浏览器的,但是也是打印全部(在隐藏帧里显示一个简单的表格,然后调用window.print 我也知道这方案不好,但是还有别的方法吗?)
Lucas Lee 2007-04-26
现在看起来导出和打印是瓶颈?
那么详细描述一下上述功能所用的技术、方法。
比如,导出为什么格式?用什么类库完成?导出的文件一般有多大?
打印是直接用浏览器的功能么?

另,数据库分页是JDBC层面还是SQL层面的?

找准瓶颈,深入细节,办法会有的。
taya 2007-04-26
我现在的项目也遇到类似问题了,而且情况更为复杂
不仅要导出,有时还需要大数据量(50万以上)的数据库update操作
暂时只能弄个列表将需要执行的部分command记下来,然后晚上没人的时候执行...
bilo 2007-04-26
我也遇到过这种问题,后来的解决办法就是用时间换空间,更改业务算法,让数据分次加载,控制大对象(1M以上)生成。效果还是比较明显的
chenqj 2007-04-26
1,查询的时候不要一次加载全部数据
2,对查询的结果进行缓存
3,建立集群
Readonly 2007-04-26
导出和打印的操作是怎么进行的?从数据库里面先全部抓出对象塞到某个collection,然后再丢给处理导出/打印的功能?
数据库交互用的是什么工具?hibernate? ibatis? jdbc?
宕机时候的现象是什么?out of memory?

补充一些具体信息吧,要不然,在论坛上这种问题没有人能解的...
downpour 2007-04-26
某些业务操作做人工的并发控制,不能同时多人访问一个业务模块?大的业务模块在每次做完以后都强制GC?

都是一些不成熟的想法,这种问题的确很头痛。



本人喜交朋友,欢迎扫描博客公告处个人二维码交流进步

 

posted @ 2008-04-01 13:56  hq5460  阅读(3558)  评论(0编辑  收藏  举报