performance - CFSpreadSheet 函数占用大量数据集的内存
问题描述
我们有一个 Coldfusion 应用程序,它正在运行一个大型查询(最多 100k 行),然后以 HTML 格式显示它。然后,用户界面提供了一个导出按钮,该按钮触发使用 cfspreadsheet 标记和电子表格函数将报告写入 .xlsx 格式的 Excel 电子表格,特别是用于构建行列值的电子表格SetCellValue、用于格式化的电子表格格式行和电子表格格式单元函数。然后使用以下命令将 ssObj 写入文件:
<cfheader name="Content-Disposition" value="attachment; filename=OES_#sel_rtype#_#Dateformat(now(),"MMM-DD-YYYY")#.xlsx">
<cfcontent type="application/vnd-ms.excel" variable="#ssObj#" reset="true">
其中 ssObj 是 SS 对象。我们看到文件大小约为 5-10 Mb。
但是...创建此报告和写入文件的内存使用量增加了大约 1GB。复杂的问题是,java GC 在导出完成后没有立即释放内存。当我们有多个用户运行并导出这种类型的报告时,内存不断攀升并达到分配的堆大小并杀死服务器的性能,从而导致服务器停机。通常需要重新启动才能将其清除。
这是正常/预期的行为还是我们应该如何处理这个问题?是否可以在导出完成后按需轻松释放此操作的内存使用量,以便运行报表的其他人轻松访问为他们的报表释放的空间?这种类型的内存使用对于 5-10Mb 文件是否常见于 cfspreadsheet 函数并写出对象?
我们已尝试暂时删除昂贵的格式化功能,但创建和写入 .xlsx 文件的内存使用量仍然很大。我们还尝试使用电子表格添加行方法和 cfspreadsheet action="write" query="queryname" 标记传入查询对象,但这也占用了大量内存。
为什么这些函数如此占用内存?在没有内存不足问题的情况下生成 Excel SS 文件的最佳方法是什么?
我应该添加服务器在 Windows 上的 Apache/Tomcat 容器中运行,我们使用的是 CF2016。
解决方案
- 您为 CF 实例分配了多少内存?
- 您正在运行多少个实例?
- 为什么你允许任何人在 HTML 中查看 100k 记录?
- 为什么你允许任何人即时导出这么多数据?
在我上一份工作中,我们遇到了这类问题(CF 和内存)。大文件上传消耗内存,大excel导出消耗内存,这就是会发生的。随着应用程序用户群的增长,您将遇到这些占用内存的请求会为其他用户杀死站点的地步。
从您的内存设置开始。通过将应用程序分配的内容增加一倍或三倍,您可能会得到全面提升。此外,请确保您使用的是最新版本的 CF 支持的 JDK。这也可以产生巨大的影响。
大文件上传会影响发出请求的实例的性能。这意味着同一实例上执行正常请求的其他人正在不必要地等待这些资源。我们专门使用一个实例池来处理文件上传。特定的 URL 通过负载均衡器路由到这些实例,应用程序对此更加满意。
该应用程序还处理了大量的数据,用户一直想要“全部”。我们不得不强制搜索结果和某些数据集来减少屏幕上显示的数量。DB 对这个决定非常满意。数据导出被移到队列中,因此他们可以在正常页面请求之外制作那些大型 Excel 文件。也许他们立即得到了他们的数据,也许等了一会儿才收到通知。无论哪种方式,该应用程序的整体表现都更好。
推荐阅读
- python - 使用 selenium 检查时,大多数 HTML 元素都是空的
- angular - 在获取模板驱动的 Angular 表单的值时出错
- sql - 多列 SQL 服务器(Aspen 中继数据库)上的 PIVOT
- excel - 获取 VBA 脚本的输入
- azure - Azure 堆栈硬件要求 - 提案
- python - 如何使用Python删除csv文件中的双引号
- python - Python 未知操作数类型 - 用于自定义类
- ruby-on-rails - 在 Rails 中验证 pdf 的数字签名时出现折纸和 OpenSSL 错误
- aem - EventHandler 未捕获 AEM 6.4 中的 resourceChangedAttributes 和 resourceAddedAttributes 过滤事件
- php - 如何通过动态内容(来自数据库的内容)在 laravel 5.4 中发送邮件