Copy link to clipboard
Copied
I currently have an application that trades virtual items and is making at least 40 CFHTTP requests per second to the host's server.
The issue I'm encountering is that it's taking anywhere from 400ms+ for my CFHTTP call to return a response which means my application is missing out on 99% of the deals it finds, as there are lots of other competiting applications out there that are getting a faster response.
I've struggled to find a cause and/or a solution to this situation so I wrote a script in both CF and C# that makes 10 http requests timing each one which resulted in the following response times:
In CF using the following browsers:
IE9: 384, 444, 302, 570, 535, 317, 510, 349, 357, 467 - Average 423.5ms
Firefox 27.0.1: 354, 587, 291, 480, 437, 304, 537, 322, 286, 652 - Average 425ms
Chrome: 300, 328, 328, 639, 285, 259, 348, 291, 299, 414 - Average 349.7ms
In C# Console Application:
597, 43, 96, 52, 44, 305, 67, 91, 54, 270 - Average 161.9ms
As you can see there is a big performance difference when making an HTTPWebRequest in a C# Console Application which is making me think that perhaps the CFHTTP requests are being throttled? Or could it maybe be something to do with the browsers?
Any help would be greatly appreciated!
Copy link to clipboard
Copied
You might be worrying for nothing. There are apparently 2 different processes at work here:
1) CFHTTP is itself a browser! It interacts with the host server;
2) IE, Firefox and Chrome each interacts with ColdFusion, via the web server, to get the result of the CFHTTP action.
Your priority is of course for process 1 to be as fast as possible. It is indeed possible that process 1 is super fast, and that process 2 is causing most of the delay that you observe.
To verify this, go to the Debugging page of the ColdFusion Administrator and check the options Enable Request Debugging Output and Report Execution Times. Then examine the execution times of the page containing the CFHTTP code.
In use-cases where reaction speed is critical, one technology comes to mind, push technology. You could redesign your application to use websockets. It would then be possible to get the response from the host server as soon as ColdFusion receives it.
Copy link to clipboard
Copied
Thanks for your reply.
Below is a screen dump of the test page I set up which makes 10 requests to a test function. The test function makes a standard CFHTTP call. Each request is timed and the time output on the page.
From what's there it gives no insight to me of what is actually happening or causing the requests to take so long to complete.
I've had a look around online the last few hours for web socket example but can find nothing other than creating a chat room! Do you have a link to any material or pseudo code that would allow me to create a test page that used web sockets so I could make a comparison between the request times?
Copy link to clipboard
Copied
I thought your application involved just CFM pages that implement CFHTTP. Hence my suggestion to enable Debugging Output in the Administrator.
From the look of it, your application involves invoking CFCs. This calls for a change of plan. You should de-activate Debugging Output. It is a very blunt instrument in the circumstances.
The cftimer tag or getTickCount function are more appropriate. I guess you are using them already.
The question remains how to crank up the speed in this new setting. Invoking a function in a CFC to interact with a remote server can be costly in CPU terms. I'll have a think.
Copy link to clipboard
Copied
Thanks, you have no idea how much I appreciate your help with this
Copy link to clipboard
Copied
I have tested a number of CFHTTP scenarios. There is good news and bad news.
Firstly, the bad news. It seems that CFHTTP is sluggish by design. No amount of refactoring or code-efficiency that I implemented could get it to run faster than a modest threshold.
To emulate your scenario, I did the following tests:
TestComp.cfc
cfcomponent>
<cffunction name="getURL" returntype="struct">
<cfhttp method="get" url="http://www.myDomain.com">
<cfreturn cfhttp>
</cffunction>
</cfcomponent>
Test scenario 1
The following CFM page invokes the CFC 10 times. Each invocation creates an instance of the component, then calls a method that makes a CFHTTP Get request and returns the result as a struct. The result is stored as an array element. Each such invocation is timed.
cfhttpTest1.cfm
<cfset arr=arrayNew(1)>
<!--- <cfset obj=createobject("component","TestComp")> --->
<cfloop from="1" to="10" index="i">
<cfset start = getTickCount()>
<cfset obj=createobject("component","TestComp")>
<cfset arr = obj.getURL()>
<cfoutput>count #i#: #getTickCount() - start# milliseconds<br></cfoutput>
</cfloop>
Scenario 1 result
count 1: 1665 milliseconds
count 2: 1774 milliseconds
count 3: 1634 milliseconds
count 4: 1771 milliseconds
count 5: 1667 milliseconds
count 6: 2045 milliseconds
count 7: 1645 milliseconds
count 8: 3004 milliseconds
count 9: 1656 milliseconds
count 10: 1844 milliseconds
Instantiating the component object outside the loop made no difference in the execution times.
Test scenario 2
Here the CFHTTP tag comes in as an included CFM file, rather than via a method in a CFC. The hope is that this will be much faster than the above scenario, as there is no object creation and no method invocation. As before, the CFHTTP Get request is run 10 times and the resulting struct is stored as an array element.
cfhttpRequest.cfm
<cfhttp method="get" url="http://www.myDomain.com">
cfhttpTest2.cfm
<cfset arr=arrayNew(1)>
<cfloop from="1" to="10" index="i">
<cfset start = getTickCount()>
<cfinclude template="cfhttpRequest.cfm">
<cfset arr = cfhttp>
<cfoutput>count #i#: #getTickCount() - start# milliseconds<br></cfoutput>
</cfloop>
Scenario 2 result
count 1: 1678 milliseconds
count 2: 1740 milliseconds
count 3: 1894 milliseconds
count 4: 1695 milliseconds
count 5: 1769 milliseconds
count 6: 1721 milliseconds
count 7: 1538 milliseconds
count 8: 1683 milliseconds
count 9: 1569 milliseconds
count 10: 1795 milliseconds
Scenario 2 is faster than scenario 1, but only marginally. So, sadly, I have to confirm your findings. I cannot think of any other way to make the CFHTTP requests faster in these scenarios. CFHTTP seems to be slow by design. That was then the bad news.
On to the good news. I found a much faster alternative to CFHTTP, namely, Curl.
Test scenario 3
My Operating System is 64 Bit Windows 7. I downloaded the latest Curl file curl-7.35.0-win64.zip and extracted it to c:\curl-7.35.0-win64. I then ran Curl in ColdFusion, using cfexecute. The loop runs 10 times, as before, each result, being stored as a text file.
curlTest.cfm
<cfset outputPath=arrayNew(1)>
<cfloop from="1" to="10" index="i">
<cfset start = getTickCount()>
<cfset outputPath= "C:\Temp\output#i#.txt">
<cfexecute name = "C:\curl-7.35.0-win64\bin\curl.exe"
arguments = "http://www.myDomain.com"
outputFile = "#outputPath#">
</cfexecute>
<cfoutput>count #i#: #getTickCount() - start# milliseconds<br></cfoutput>
</cfloop>
Scenario 3 result
count 1: 392 milliseconds
count 2: 128 milliseconds
count 3: 119 milliseconds
count 4: 191 milliseconds
count 5: 49 milliseconds
count 6: 12 milliseconds
count 7: 24 milliseconds
count 8: 23 milliseconds
count 9: 6 milliseconds
count 10: 21 milliseconds
Evidently, Curl is faster than CFHTTP is this scenario, by several orders of magnitude!
Copy link to clipboard
Copied
Wow!! Thanks very much for this!
I'll have a look into cURL and see how customisable it is (to pass in custom header values) and report back.
Copy link to clipboard
Copied
I've always thought that CFHTTP had alot of overhead. a year or two ago we were looking at switching to php (have since dropped that in favor of .NET), and had a php programmer convert one of our really slow CFHTTP laden scripts. The php script used curl for all of the HTTP handling. It ran so fast I didn't think it did anything. We're talking about going from hours of processing to a minute or so, doing around 100,000 calls to a google API.
One of the nice things about curl is that if you have problems with ssl sites you can set an option to ignore certificate errors.
The .NET rewrite also saw gains in performance over CFHTTP in CF, but not quite to the level of what we saw above.