润乾报表并发数解读
润乾报表提供了两种并发控制方式,静态并发控制和动态并发控制。静态并发以控制同时运算的报表个(张)数避免内存溢出;动态并发则是控制同时运算的单元格数,避免内存溢出的同时又能够让服务器资源得到高效利用。以下将是对这两种并发控制方式的详细解读。
静态并发控制
原理
当用户访问时,首先检查当前任务数是否超过最大并发任务数,若没有,则允许任务运行,否则进行等待。同时系统还需设定任务的最大等待数,在允许该任务等待之前,还会判断一下最大等待数是否超标,如果没有超标才能等待,如果超标了,则直接返回错误信息。
静态并发控制所控制的是同时计算的报表个数,其中包括:数据集运算、报表运算、分页三种,但是分页结束后往硬盘写缓存以及展现输出的过程没有算在并发内。
由于数据集取数已经算进并发了,所以最大等待数可以设置的大一些,因为不用再担心数据库连接池个数问题了。
但由于分页结束后往硬盘写缓存以及展现输出(生成HTML)的过程没有算在并发内,那在这两个阶段可能会出现内存溢出的情况,当有某个任务导致内存溢出时,理论上JVM会立即释放这个任务占用的内存,但是别的任务还可以继续计算。此时如果新任务继续访问,又会导致内存溢出,因此我们设置了一个内存溢出后的最大等待时间,一旦有内存溢出,必须等待这个时间后才能允许下一个任务访问。
配置
相关配置包括:
<config> <!– 最大并发数 –>
<name>maxConcurrentForReport</name>
<value>9</value>
</config>
<config> <!– 最大等待数 –>
<name>maxWaitForReport</name>
<value>99</value>
</config>
<config> <!– 内存溢出后等待多长时间才允许新任务访问,以秒为单位 –>
<name>maxWaitTimeForReport</name>
<value>30</value>
</config>
遗留问题
1. 当用户发送了一个请求并等待时,如果此时把ie关闭或者转到其它网页,该任务还会继续等待,并最终执行运算,不会自行终止或关闭
2. 往硬盘写缓存的操作没有算进并发,因此如果出现这种情况:即某个报表的计算时间较短,但是写缓存的时间较长,此时如果模拟很多并发访问,会出现最终由于写缓存而导致的内存溢出,且极有可能由于JVM来不及回收而导致最终需要重起才能恢复。(原理是:缓存没写完,entry就还不是软引用,不会被JVM回收)不过正常情况下,写缓存的时间和报表计算时间是成正比的,不会出现两者差距太大的情况。
3. 静态并发数是一个无法精确控制的数据,当所有任务访问的报表正好都非常巨大时,很可能还没达到最大并发数,就已经内存溢出了;当所有任务访问的报表正好都非常小时,很可能服务器资源很空闲。
动态并发控制
原理
由于静态并发数是一个无法精确控制的数据,因此引入最大单元格数。这个数据是根据服务器内存能支撑最大的格子数来设定的。通过它,可以灵活地改变并发数控制,如果报表都很小,则允许更多的并发数,如果报表都很大,则只允许很少的并发数。
在配置文件中配置一个最大格子数,然后在报表模板中有一个格子数的定义,该定义是个表达式,可以利用数据集写一个表达式,该表达式会算出报表扩展后可能有的最大格子数。
于是引擎在计算报表时,先算出数据集,然后计算这个表达式,得出该报表的最大格子数,然后和系统目前已存在的格子数相加,再和系统的最大格子数进行对比,看有没有超标,如果没有超标,则继续计算,如果超标了,则返回错误信息,直接终止该任务。
当报表计算结束时,会从系统的当前格子数里把这个报表的格子数减去;当报表进行分页之前,又会把报表的格子数和分页可能产生的格子数追加到系统当前格子数中,分页结束时,再减去。
配置
<config><!– 最大单元格数 –>
<name>maxCellNum</name>
<value>100000</value>
</config>
遗留问题
1. 报表计算结束时,结果报表还在内存中(还要进行分页等),此时却把报表的格子数从系统中减去了。因此报表运算结束和分页之前的时间段没有进行控制
2. 分页结束后,分页后的报表还在内存中(还要往硬盘写缓存以及展现输出),此时却把分页格子数从系统减去了。因此往硬盘写缓存和展现输出这段时间没有进行控制
3. 有些单元格非常大,比如统计图单元格、子报表单元格等,普通单元格都比较小,因此如果运气不好,正好某个报表里含有很多个统计图单元格或者子报表单元格,则极有可能还没到最大格子数就已经内存溢出了。