为什么这个ColdFusion 8应用程序会导致CPU峰值?



感谢您花时间看这个问题....听我说....

前几天,我们的一个网络服务器停止提供网页服务。Web服务器是一台运行Windows Server 2003 R2标准版Service Pack 2和IIS 6的物理服务器。它运行ColdFusion 8.0.1标准与Java 1.6.0_24。这个服务器有3个面向公众的网站,它们的使用率并不高。这三个网站的页面都超时或返回500个错误。

当我登录到服务器查看问题所在时,我期望看到JRUN服务使用了大量内存。内存很好,但是,我注意到CPU运行在或接近100%。大约50%由JRUN使用,另外50%由失控的备份进程使用,我杀死了它。但是JRUN很快就占用了CPU,使用率接近100%。

我查看了ColdFusion日志,注意到发生了几个Java堆空间错误。

我查看了IIS日志,注意到有一堆对应用程序的请求,该应用程序允许我们的一个客户使用uploadify为他们的产品上传多个图像文件。该应用程序是用ColdFusion编写的,并使用jQuery调用Web服务来处理上传和使用<CFIMAGE>调整上传图像的大小。

在日志中看到这些信息后,我认为这个应用程序的某些部分一定是罪魁祸首。

我似乎找不到导致Java堆空间错误和CPU峰值的确切原因。任何想法吗?

WebService CFC方法:

<cffunction
    name="uploadFile"
    access="remote"
    returntype="Struct"
    output="false"
    returnformat="JSON">
    <cfargument name="FileName" type="String" default="" />
    <cfargument name="FileData" type="String" default="" />
    <cfscript>
        var _response = NewAPIResponse();
        var _tempFilePath = APPLICATION.TempDir & "" & ARGUMENTS.FileName;
        var _qItem = QueryNew("");
        var _product = CreateObject("component", "cfc.Product");
        var _result = {};
        var _sku = "";
        /*
            Each file must be named [Part Number].[file extension], so, 
            parse the file name to get everything before the file extension
        */
        _sku =
            Trim(
                REQUEST.UDFLib.File.getFileNameWithoutExtension(
                    ARGUMENTS.FileName
                    )
                );
    </cfscript>
    <cfif Len(_sku) GT 20>
        <cfthrow
            message="#ARGUMENTS.FileName#: File Name does not correspond to an existing Part Number." />
    </cfif>
    <cfset _qItem = _product.readSKU(_sku) />
    <cfif NOT _qItem.RECORDCOUNT>
        <cfthrow
            message="#ARGUMENTS.FileName#: File Name does not correspond to an existing Part Number." />
    </cfif>
    <cfscript>
        FileCopy(ARGUMENTS.FileData, _tempFilePath);
        _aMessages =
            _product.setId(
                _qItem.SKU
                ).updateThumbnailImages(uploadFilePath = _tempFilePath);
    </cfscript>
    <cfif ArrayLen(_aMessages)>
        <cfthrow
            message="#ARGUMENTS.FileName#: #_aMessages[1].getText()#" />
    </cfif>
    <cfscript>
        _result["SKU"] = _product.getSKU();
        _result["SMALLIMAGESRC"] = _product.getSmallImageSrc();
        _result["LARGEIMAGESRC"] = _product.getLargeImageSrc();
        ArrayAppend(_response.data, _result);
    </cfscript>
    <cfreturn _response />
</cffunction>

图像大小调整功能:

<cffunction name="updateThumbnailImages" returntype="Array" output="false">
    <cfargument name="uploadFilePath" type="String" required="true" />
    <cfset var _image = {} />
    <cfif FileExists(ARGUMENTS.uploadFilePath)>
        <cfset _image =
            REQUEST.UDFLib.Image.scale(
                imagePath = ARGUMENTS.uploadFilePath,
                maxHeight = 500,
                maxWidth = 700
                ) />
        <cfimage
            action="write"
            source="#_image#"
            overwrite="true"
            destination="#getLargeImagePath()#" />
        <cfset _image =
            REQUEST.UDFLib.Image.scale(
                imagePath = ARGUMENTS.uploadFilePath,
                maxHeight = 300,
                maxWidth = 300
                ) />
        <cfimage
            action="write"
            source="#_image#"
            overwrite="true"
            destination="#getMediumImagePath()#" />
        <cfset _image =
            REQUEST.UDFLib.Image.scale(
                imagePath = ARGUMENTS.uploadFilePath,
                maxHeight = 50,
                maxWidth = 50
                ) />
        <cfimage
            action="write"
            source="#_image#"
            overwrite="true"
            destination="#getSmallImagePath()#" />
    </cfif>
</cffunction>

图像缩放udf:

<cffunction name="getDimensionsToEnlarge" returntype="Struct" output="false">
    <cfargument name="imageWidth" type="Numeric" required="true" />
    <cfargument name="imageHeight" type="Numeric" required="true" />
    <cfargument name="minWidth" type="Numeric" required="true" />
    <cfargument name="minHeight" type="Numeric" required="true" />
    <cfscript>
        var dimensions = {
            width = -1,
            height = -1
            };
        if  (
                ARGUMENTS.minHeight > 0
            &&  ARGUMENTS.minWidth > 0
            &&  imageHeight < ARGUMENTS.minHeight
            &&  imageWidth < ARGUMENTS.minWidth
            ) {
            dimensions.width = ARGUMENTS.minWidth;
            dimensions.height = ARGUMENTS.minHeight;
        }
        return dimensions;
    </cfscript>
</cffunction>
<cffunction name="getDimensionsToShrink" returntype="Struct" output="false">
    <cfargument name="imageWidth" type="Numeric" required="true" />
    <cfargument name="imageHeight" type="Numeric" required="true" />
    <cfargument name="maxWidth" type="Numeric" required="true" />
    <cfargument name="maxHeight" type="Numeric" required="true" />
    <cfscript>
        var dimensions = {
            width = -1,
            height = -1
            };
        if  (
                ARGUMENTS.maxHeight > 0
            &&  ARGUMENTS.maxWidth > 0
            &&  (
                    imageHeight > ARGUMENTS.maxHeight
                ||  imageWidth > ARGUMENTS.maxWidth
                )
            ) {
            dimensions.width = ARGUMENTS.maxWidth;
            dimensions.height = ARGUMENTS.maxHeight;
        }
        return dimensions;
    </cfscript>
</cffunction>
<cffunction name="getDimensionsToFit" returntype="Struct" output="false">
    <cfargument name="imageWidth" type="Numeric" required="true" />
    <cfargument name="imageHeight" type="Numeric" required="true" />
    <cfargument name="minWidth" type="Numeric" required="true" />
    <cfargument name="minHeight" type="Numeric" required="true" />
    <cfargument name="maxWidth" type="Numeric" required="true" />
    <cfargument name="maxHeight" type="Numeric" required="true" />
    <cfscript>
        var dimensions = {
            width = -1,
            height = -1
            };
        dimensions =
            getDimensionsToEnlarge(
                imageHeight = ARGUMENTS.imageHeight,
                imageWidth = ARGUMENTS.imageWidth,
                minWidth = ARGUMENTS.minWidth,
                minHeight = ARGUMENTS.minHeight
                );
        if (dimensions.width < 0 && dimensions.height < 0)
            dimensions =
                getDimensionsToShrink(
                    imageHeight = ARGUMENTS.imageHeight,
                    imageWidth = ARGUMENTS.imageWidth,
                    maxWidth = ARGUMENTS.maxWidth,
                    maxHeight = ARGUMENTS.maxHeight
                    );
        return dimensions;
    </cfscript>
</cffunction>
<cffunction name="scale" returntype="Any" output="false">
    <cfargument name="imagePath" type="String" required="true" />
    <cfargument name="action" type="String" default="fit" hint="shrink, enlarge, or fit"/>
    <cfargument name="minWidth" type="Numeric" default="-1" />
    <cfargument name="minHeight" type="Numeric" default="-1" />
    <cfargument name="maxWidth" type="Numeric" default="-1" />
    <cfargument name="maxHeight" type="Numeric" default="-1" />
    <cfscript>
        var scaledDimensions = {
                width = -1,
                height = -1
            };
        var scaledImage = ImageNew();
        scaledImage = ImageNew(ARGUMENTS.imagePath);
        switch (ARGUMENTS.action) {
            case "shrink":
                scaledDimensions =
                    getDimensionsToShrink(
                        imageHeight = scaledImage.getHeight(),
                        imageWidth = scaledImage.getWidth(),
                        maxWidth = ARGUMENTS.maxWidth,
                        maxHeight = ARGUMENTS.maxHeight
                    );
                break;
            case "enlarge":
                scaledDimensions =
                    getDimensionsToEnlarge(
                        imageHeight = scaledImage.getHeight(),
                        imageWidth = scaledImage.getWidth(),
                        minWidth = ARGUMENTS.minWidth,
                        minHeight = ARGUMENTS.minHeight
                    );
                break;
            default:
                scaledDimensions =
                    getDimensionsToFit(
                        imageHeight = scaledImage.getHeight(),
                        imageWidth = scaledImage.getWidth(),
                        minWidth = ARGUMENTS.minWidth,
                        minHeight = ARGUMENTS.minHeight,
                        maxWidth = ARGUMENTS.maxWidth,
                        maxHeight = ARGUMENTS.maxHeight
                    );
                break;
        }
        if (scaledDimensions.width > 0 && scaledDimensions.height > 0) {
            // This helps the image quality
            ImageSetAntialiasing(scaledImage, "on");
            ImageScaleToFit(
                scaledImage,
                scaledDimensions.width,
                scaledDimensions.height
                );
        }
        return scaledImage;
    </cfscript>
</cffunction>

下面是我在评论部分提到的示例代码。这提高了我们的可靠性,但在极端负载下,我们发现这个问题仍然存在,这就是为什么我们迁移到Java 1.7。然而,1.7有它自己的问题,性能急剧下降,如下所述。希望能有所帮助。

<cffunction name="init" access="private" output="false" returntype="void">
    <cfset variables.instance = StructNew() />
    <!--- create object and set to variables.instance --->
    <cfset setProductObject()>
</cffunction>
<cffunction name="setProductObject" access="private" returntype="void" output="false">
    <!--- create object once and set it to the variables.instance scope --->
    <cfset var product = createObject("component","cfc.Product")>
    <cfset variables.instance.product = product/>
    <cfset product = javacast('null', '')>
</cffunction>
<cffunction name="getProductObject" access="private" returntype="cfc.Product" output="false">
    <!--- instead of creating object each time use the one already in memory and duplicate it --->
    <cfset var productObj = duplicate(variables.instance.product)>
    <cfreturn productObj />
</cffunction>
<cffunction name="uploadFile" access="remote" returntype="struct" returnformat="JSON" output="false">
    <cfargument name="FileName" type="String" default="" />
    <cfargument name="FileData" type="String" default="" />
        <cfscript>
            var _response = NewAPIResponse();
            var _tempFilePath = APPLICATION.TempDir & "" & ARGUMENTS.FileName;
            var _qItem = QueryNew("");
            var _product = "";
            var _result = {};
            var _sku = "";
            //check init() function has been run if not run it
            if NOT structKeyExists(variables,'instance') {
                init();         
            }
            _product = getProductObject();
            /*
                Each file must be named [Part Number].[file extension], so, 
                parse the file name to get everything before the file extension
            */
            _sku =
                Trim(
                    REQUEST.UDFLib.File.getFileNameWithoutExtension(
                        ARGUMENTS.FileName
                        )
                    );
        </cfscript>
        <cfif Len(_sku) GT 20>
            <cfthrow
                message="#ARGUMENTS.FileName#: File Name does not correspond to an existing Part Number." />
        </cfif>
        <cfset _qItem = _product.readSKU(_sku) />
        <cfif NOT _qItem.RECORDCOUNT>
            <cfthrow
                message="#ARGUMENTS.FileName#: File Name does not correspond to an existing Part Number." />
        </cfif>
        <cfscript>
            FileCopy(ARGUMENTS.FileData, _tempFilePath);
            _aMessages =
                _product.setId(
                    _qItem.SKU
                    ).updateThumbnailImages(uploadFilePath = _tempFilePath);
        </cfscript>
        <cfif ArrayLen(_aMessages)>
            <cfthrow
                message="#ARGUMENTS.FileName#: #_aMessages[1].getText()#" />
        </cfif>
        <cfscript>
            _result["SKU"] = _product.getSKU();
            _result["SMALLIMAGESRC"] = _product.getSmallImageSrc();
            _result["LARGEIMAGESRC"] = _product.getLargeImageSrc();
            ArrayAppend(_response.data, _result);
        </cfscript>
        <cfreturn _response />
</cffunction>

最新更新