Problem: My web service calls only open a single connection to the web service machine

S

Scott Baierl

I've got a web application that makes web service calls to a J2EE back-end
server farm. It appears that the .NET runtime is setting up a single
connection to one of the J2EE servers on the back-end, and sends all the web
service calls over this connection. We have a CISCO CSM between the .NET
server and the J2EE back-end server farm to network load balance the .NET
calls between 1 of 4 nodes in the server farm. The problem is that the CSM
balances at the connection level, and since my .NET application is only
opening a single connection and keeps that connection open, no load
balancing occurs. I noticed that the .NET runtime will create a maximum of
2 connections by default, but I'm only getting a single connection. That
indicates to me that the amount of traffic I'm generating on the .NET
machine isn't enough to cause .NET to create more than one connection. Is
there a way to force the .NET runtime to create and use more than a single
connection, or is there a way to time that connection out and cause it to
close between web service calls to the back-end, so I can use the full
horsepower of my back-end server farm?
 
S

Scott Baierl

Well, I figured out the answer to my problem, so I figured I'd post it here
in case someone else has to deal with this.

One way to handle this is to turn keep alives off in the web service proxy.
This will cause .NET to use a new connection for each web service request,
effectively allowing the CSM to balance each request to a different server
in the server pool. I added the following code to my proxy class:

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.Http.WebRequest webRequest =
(System.Net.Http.WebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
return webRequest;
}

This also fixed an issue I was having where I'd get the following error:
"The underlying connection was closed" The one drawback of this solution is
that it doesn't allow .NET to use persistent connections, so you have a
little extra overhead to setup and tear down a connection for each web
service call. However, in my case, the extra overhead is minor compared to
the performance benefits of being able to fully utilize my server farm.

The other solution again, requires modifying the proxy, and entails using
connection groups. Basically, you leave keepalives on, but have the proxy
alternate it's requests to different connection groups. When you use
connection groups, .NET will create one or more connections per group.
Then, when you create an instance of the proxy, you just specify a different
group for each request. To make this happen, I did the following:

//Added an array of connection group names to use
private static string [] sConnGroups = {"CONNGRP1", "CONNGRP2", "CONNGRP3"};

// Created a function to randomly give out a name from the above array
private string GetConnectionGroupName()
{
Random rand1 = new Random();
return sConnGroups[rand1.Next(sConnGroups.GetUpperBound(0))];
}

// Add the following to your proxy class constructor
public MyProxyClass()
{
this.ConnectionGroupName = GetConnectionGroupName();
}

By specifying a different group name, .NET will create the group if it
doesn't exist, and if there's an open connection it will use that
connection, or create one if one isn't open. The above code will randomly
select one of the three connection groups, and thus will randomly use one of
the three connections. If more connections are needed .NET will create more
up to the maximum that you've set in your machine.config. The advantage of
this method is that persistent connections will continue to be used, so you
have that efficiency. The disadvantage for me, is that .NET is now
controlling the load balancing, rather than my switch. Also, I still have
the problem with .NET closing the connection, and I get the error I
mentioned previously in this response. The above is for illustration
purposes only. Since turning keepalives off fixes my problem, and also
fixes a bug, I've decided not to use this method myself. But, if you don't
get the error I was getting, there's no reason you couldn't achieve greater
efficiency by using this technique. A couple of improvements to the above
would be to make the number of connection groups externally configurable,
and making the GetConnectionGroupName() function round-robin the group
names.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top