润乾报表性能管理之单用户缓存原理
功能背景:
由于WEB服务器与浏览器之间无连接的特性,导致B/S方式下服务器端实体(在我们报表系统中主要是指报表模板、报表及报表分页)的生命周期无法完全与浏览器端保持一致。
举例来说,客户端访问了一张报表,报表计算且向客户端输出完毕后,是否应当从内存中清除报表对象呢?服务器无法判断客户端是否还需要使用这个对象,事实上,客户端往往
还需要翻页、打印、导出等操作,此时还需要使用报表对象;而客户端也完全有可能关闭浏览器,不再访问了。因此,如果服务器端清除了报表对象,则客户端进行翻页、打印、
导出等操作时,不得不重新进行计算,浪费cpu;如果客户端不再访问了而服务器端却保留着报表对象,则会浪费内存。
为了解决这个问题,我们对这些实体采取了带时间管理的缓存策略
只要通过tag标签访问,自动会缓存报表,不能通过配置关闭。
调用API接口计算报表,如果没有调用缓存管理器的API,则不会进行报表缓存。
实现原理:
缓存管理器在响应用户报表运算或分页请求后,首先会计算报表或分页,然后把生成的报表或分页保存到硬盘,同时将当前报表或分页所对应的一些信息作为缓存项保存在内存中
以方便快捷访问,这些信息中包含参数及宏信息或分页信息,实体对应的文件名,以及对实体的软引用 (SoftReference),对象的软引用意味着它何时回收由JVM决定,这样做的好
处是内存够用时对象不会被回收,可以提高访问效率,内存不够时会被回收,以释放更多的内存让其它任务使用。
缓存项通过一个缓存项id进行识别,目前tag标签可以包含缓存项id,因此tag接到访问报表请求时,先检查请求指令中是否存在缓存项id的信息,若有,则先读取缓存,如果缓存
不存在,则重新计算,而在没有缓存项id时,直接开始计算。
缓存管理器每隔5分钟对缓存项进行一次检查,如果超过最大未访问时长,则会将缓存项从内存和硬盘上完全清除,此时如果想通过缓存项id请求,发现缓存不存在,会重新进行计
算。
当缓存过期被清除时,只好重新计算报表。对于有参数的报表,系统还对参数进行了缓存,参数是缓存在内存中的,缓存时间由参数的最大未访问时长控制。缓存参数的目的是为
了重新计算报表时,不要重新输入参数,方便用户。因此,一般来说,参数的最大未访问时长应当比报表的最大未访问时长更长,否则没有意义。
相关配置包括:
<config> <!– 配置缓存报表目录 –>
<name>cachedReportDir</name>
<value>c:\runqian\cached</value>
</config>
<config> <!– 配置报表最大未访问时长,以分钟为单位 –>
<name>cachedReportTimeout</name>
<value>120</value>
</config>
<config> <!– 配置参数最大未访问时长,以分钟为单位 –>
<name>cachedParamsTimeout</name>
<value>120</value>
</config>
需要注意的是:
1、 如果通过tag标签访问报表,自动会缓存,无法关闭。如果用户不需要翻页等二次客户端操作,且往硬盘写缓存这个操作占用了较大内存的话,建议写API计算报表,不要
使用tag标签
2、 缓存id是tag标签自动处理的,自动拼到url上,因此如果自己写API进行报表计算的话,请求指令里没有这个id,系统就变成每次重新计算。所以,如果自己写API进行报
表计算且需要翻页、打印、导出的话,需要自己调用API接口进行报表缓存,并自行使用和保存缓存id。
3、 往硬盘写缓存这个操作有时候比较慢,尤其是报表较大或者硬盘转速较小的时候,只要没有写完,内存中的报表对象就不会变成软引用,就不会被JVM回收。
4、 引擎每隔5分钟扫描一次缓存,清除超时缓存。因此,如果上一次扫描刚结束时才到达缓存期限的报表,得到下一次扫描时才会被清除,等于延长了4.999…..分钟,这里
的9理论上可以无穷多,接近5分钟。举例来说,缓存期限为2分钟的报表,如果在扫描结束后才到2分钟,那么下一次扫描时相当于已经缓存了6.999….分钟;再举例,缓存期限为
6分钟的报表,如果在扫描结束时才到6分钟,那么下一次扫描时可能已经缓存了10.999….分钟了。