我们在 Windows Server 2003 VPS 上运行 ColdFusion 8,该程序使用一个 API 通过连接器将学生记录公开给合作伙伴 API。我们的 API 可以无缝返回大约 50k 个以 XML 格式序列化的学生记录。我的问题源于今天我们在测试与合作伙伴 API 的连接器时发生了一件非常可怕的事情。我们的整个网站和网络主机都瘫痪了。我们以为我们的主机只是出现了一些问题,经过 4 个小时的等待,他们的客户服务部门没有给出任何解决方案和回复,我们终于收到了他们的回复,声称他们的网络中有一个“未经授权的用户”。我们的服务器恢复后,我们无法连接到我们的网站,就好像网络服务或 ColdFusion 本身冻结了一样。这才是我真正担心的地方,因为我担心我们可能已经使网络服务超载了。
正如我之前提到的,我们尝试向我们的合作伙伴的 API 发送超过 50k 个 HTTP POST 请求,但是一切都在大约 1.6k 之后停止了
这是不好的做法吗?还是说在服务器配置中存在某种速率限制,我可以放宽?我们设法找到了一种解决方法,但它绕过了对我们的设计至关重要的连接器。
这本来是一次性交易,因为如此多请求的目的是用当前数据填充我们合作伙伴的网站,此后每小时同步将使请求数保持在每小时 100 个左右。
更新
我们的合作伙伴 API 由以下公司拥有和运营:帕多特。我们通过将学生数据传递到他们的 API 将学生转化为潜在客户,但不幸的是,该 API 似乎一次只能接受一名学生。因此,我们必须单独处理所有 50k 个请求。
我们的服务器有 4GB RAM、2.8GHz Intel Core 2 Duo 处理器并运行 Windows Server 2003 SP2。
我在 100 名学生同步、400 名学生同步和 1.4k 名学生同步期间监控了服务器,结果如下:
100 名学生 - 2.25GB 内存,30-40% CPU 利用率,0.2-0.3% 网络带宽
400 名学生 - 2.30GB 内存,30-50% CPU 利用率,0.2-1.0% 网络带宽
1.4k 名学生 - 2.30GB 内存,30-70% CPU 利用率,0.2-1.0% 网络带宽
我知道这与 5 万名学生相比相差甚远,但假设这是原因,我不想冒险再次关闭我们的 CMS 系统。
让您看一下我们的代码:
<cfif (#getStudents.statusCode# eq "200 OK")>
<cftry>
<cfloop index="StudentXML" array="#XmlSearch(responseSTUD,'/students/student')#">
<cfset StudentXML = XmlParse(StudentXML)>
<cfhttp
url="#PARDOT_CMS_UPSERT#"
method="post"
timeout="10000" >
<cfhttpparam type="url" name="user_key" value="#PARDOT_CMS_USERKEY#">
<cfhttpparam type="url" name="api_key" value="#api_key#">
<cfhttpparam type="url" name="email" value="#StudentXML.student.email.XmlText#">
<cfhttpparam type="url" name="first_name" value="#StudentXML.student.first.XmlText#">
<cfhttpparam type="url" name="last_name" value="#StudentXML.student.last.XmlText#">
<cfhttpparam type="url" name="in_cms" value="#StudentXML.student.studentid.XmlText#">
<cfhttpparam type="url" name="company" value="#StudentXML.student.agencyname.XmlText#">
<cfhttpparam type="url" name="country" value="#StudentXML.student.countryname.XmlText#">
<cfhttpparam type="url" name="address_one" value="#StudentXML.student.address.XmlText#">
<cfhttpparam type="url" name="address_two" value="#StudentXML.student.address2.XmlText#">
<cfhttpparam type="url" name="city" value="#StudentXML.student.city.XmlText#">
<cfhttpparam type="url" name="state" value="#StudentXML.student.state_province.XmlText#">
<cfhttpparam type="url" name="zip" value="#StudentXML.student.postalcode.XmlText#">
<cfhttpparam type="url" name="phone" value="#StudentXML.student.phone.XmlText#">
<cfhttpparam type="url" name="fax" value="#StudentXML.student.fax.XmlText#">
<cfhttpparam type="url" name="output" value="simple">
</cfhttp>
</cfloop>
<cfcatch type="any">
<cfdump var="#cfcatch.Message#">
</cfcatch>
</cftry>
</cfif>
更新2
我检查了 CF 日志并发现了以下几个:
"Error","jrpp-8","06/06/13","16:10:18","CMS-API","Java heap space The specific sequence of files included or processed is: D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm, line: 675 "
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2882)
at java.io.CharArrayWriter.write(CharArrayWriter.java:105)
at coldfusion.runtime.CharBuffer.replace(CharBuffer.java:37)
at coldfusion.runtime.CharBuffer.replace(CharBuffer.java:50)
at coldfusion.runtime.NeoBodyContent.write(NeoBodyContent.java:254)
at cfapi2ecfm292155732._factor30(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:675)
at cfapi2ecfm292155732._factor31(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:662)
at cfapi2ecfm292155732._factor36(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:659)
at cfapi2ecfm292155732._factor42(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:657)
at cfapi2ecfm292155732._factor37(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm)
at cfapi2ecfm292155732._factor44(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:456)
at cfapi2ecfm292155732._factor38(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm)
at cfapi2ecfm292155732._factor46(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:455)
at cfapi2ecfm292155732._factor39(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm)
at cfapi2ecfm292155732._factor47(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:453)
at cfapi2ecfm292155732.runPage(D:\Clients\www.xxx.com\www\dev.cms\api\v1\api.cfm:1)
at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:192)
at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:366)
at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65)
at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:279)
at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)
at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
at coldfusion.filter.PathFilter.invoke(PathFilter.java:86)
at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.CfmServlet.service(CfmServlet.java:175)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
看起来我可能已经使 CF 中的 JVM 崩溃了,有没有更好的方法可以做到这一点?我们正在考虑最初将所有记录导出为 CSV 文件,然后将其导入 Pardot,因为我们再也不需要执行这么大的请求了。
答案1
您是否监控过服务器上的 CPU、磁盘和带宽使用情况?我要做的第一件事就是确保这些资源都没有超载。Perfmon 是一个明显的起点,可以检查您的 CF 日志。
您是连续发出 50K 个 post 请求(即单独的请求)还是这是针对 XML 文件中的 50K 条记录的单个请求?如果是前者,那么您为什么要发出 50K 个请求?是否可以一次性请求所有 50K 条记录,因为这样只需要 1 个请求和 1 次文件传输?如果 50K 个请求是连续的(即在当前请求完成之前不会发出下一个请求),那么这似乎是发出大量请求的一种温和方式。
答案2
我找到了一个解决方案,它几乎绕过了这个问题,而且更符合“最佳实践”
我决定采用将数据导出到 CSV 文件的方法,因为这个问题源于最初尝试填充数据库。CSV 导入工作完美无缺,之后同步仅发出约 0-1000 个请求,通过进一步优化和调度,我的请求数降至每 30 分钟 0-50 个,这是理想的。