I'm fortunate enough to work with some pretty sophisticated developers.
We have a .NET team with a diverse background; some, like myself, come
from the VB6.0 / Windows DNA school and have been going through the OOP
.NET learning curve and have become proficient in C# as their preferred
.NET language of choice. Others came from the JAVA space - they already
were well - schooled in OOP principles (sometimes I think too much, since
in .NET, it's possible to flatten out the object model considerably and
still achieve OOP-oriented objectives). There is a pretty good interchange
of ideas, and developers help each other. A highly productive environment
in which to learn, work and grow.
One of the things I've noticed, especially from the former JAVA guys,
is that they come from an environment (not usually on the Win32 platform)
where they are used to having the kind of application servers that scale
with multiple instances of components acting as a monolithic instance.
This is done both for failover reasons as well as to have more computing
power handling large amounts of traffic. Naturally, their first look at
Windows Component Load Balancing tells them it's analogous to this stuff
they are accustomed to from the JAVA space, and that's where the problems
Application Center Server 2000 (ACS) is designed to handle component
load balancing (CLB), monitoring, and automated application deployment
(not just CLB). There are probably cheaper ways to do load balancing,
but when you add in the management features, some companies find that
they save money and time by using ACS.. ACS, as opposed to Windows 2000
DataCenter Edition, which requires a minimum of 8 processors, works just
fine with commodity single - and dual-proc servers. It also allows you
to configure NLB on Windows 2000 Server. For some companies, this could
save some costs over the licensing costs of Windows 2000 Advanced Server,
depending on your server environment configuration.
I've seen at least one situation where the ex - JAVA guys believed (understandably)
that if they made their .NET components Enterprise Services components,
installed them in the GAC and had them run in COM+ Services, that they
would be able to use this environment in the same way as they did with
their Beans and other JAVA stuff through IBM WebSphere or whatever - like
Component Load Balancing. I've railed continuously about the overhead
of COM+ and how by using Network Load Balancing (NLB), which comes with
Windows Advanced Server and higher (or can be configured on Windows 2000
Server using ACS as mentioned above), you can have multiple copies
of the application running on a web farm and achieve similar
scalability results, and you don't need COM+, as long as your calls are
being made over the web, or via TCP, which these days is more often than
not the case. And, let's not forget that TCP can be remoting framework
calls over the TCP Channel into the NLB "Farm" that have nothing
to do with the web at all.
Throughput performance declines when making any kind of call across
a network. Using CLB always incurs this cost and this needs to be accounted
for in making cluster architecture decisions. To give some perspective
on this, the following data (from one of the CLB Whitepapers) shows the
number of calls per second on a single threaded Visual Basic 6 COM component
that returns “Hello, world” as a string property. The client
is early bound and doesn’t release references between calls to retrieve
||Calls per Second
|COM+ Server Application, run over a 10BaseT network
|COM+ Server Application, Out Proc, same box
|COM+ Library Application, In Proc, same box
It’s clear that calls over the network yield slower throughput
than calls to software installed on the same computer. For this reason,
CLB does not make a great solution where throughput is the most important
consideration. In this case it is better to install the COM+ components
locally on the Web-tier cluster members, avoiding cross-network calls.
CLB support is lost but load balancing is still available through NLB.
And as we will see in a moment, in the case of a .NET - based solution,
careful consideration should be given to whether the components should
be installed in COM+ at all, since NLB could care less whether your components
are in COM+. With NLB, we can have cookieless sessions via ASP.NET and
we can also use the SQL Server Session State service with a simple web.config
entry and a database script. In addition, it is possible to pass credentials
data to our Remoting Framework components over NLB.
Network Load Balancing (NLB) distributes IP traffic to multiple copies
(or instances) of a TCP/IP service, such as a Web server, each running
on a host within the cluster. Network Load Balancing transparently partitions
the client requests among the hosts and lets the clients access the cluster
using one or more “virtual” IP addresses. From the client’s
point of view, the cluster looks like a single server. As enterprise traffic
increases, network administrators can simply plug another server into
the cluster. Provided that DTC - type transactionality across components
is not absolutely necessary and the components are written to be stateless,
great economies of scale can be obtained at a much lower cost using relatively
inexpensive 2 or 4 proc boxes for the farm.
In my article about
Implementing .NET Role-based security without COM+ , I showed how
it is possible to eliminate the overhead of COM+ in order to achieve role-based
security with pure .NET code by using the LogonUser API in combination
with attribute-based or imperative security checks. And, contrary to what
some may believe, it is possible to make such calls via the Remoting Framework
over the TCP Channel by employing the CallContext Class, deriving from
ILogicalThreadAffinative, to pass out-of-band credentials parameters such
that the LogonUser API can even be called on the remote server without
messing up interface or method signatures. I had read enough articles
by some of the pros on MSDN to convince me that my suspicions about COM+
overhead were correct, and so I stand by my position:
Unless your .NET application needs intra-component
transactions, or has components that are very expensive to instantiate,
you don't need COM+ services. If all you need is role-based security,
consider using the LogonUser API.
In fact, most of what you would want to achieve by calling LogonUser()
could be accomplished, much more simply and with less overhead, in the
<identity> section of web.config. Just use Windows authentication
and impersonate, or - now you can even configure the identity under which
aspnet_wp will run using Microsoft's new security enhancement tool (more
on this one soon!).
NOTE: If you are using the System.Data.SqlClient namespace,
be aware that this class already uses System.EnterpriseServices.ResourcePool
internally for connection pooling, so unless your component is very complex
or needs transaction services, installing it in COM+ may be, well - kind
The Common Language Runtime can instantiate 10 million objects a second
on a typical machine. The jury may still be out, but I doubt you need
"Just in Time Activation", and you certainly don't need "Object
Pooling" with fast, lightweight .NET assemblies. If your components
use transactions, you can control these off the Connection Object in ADO.NET,
or handle it directly in Sql Server with BEGIN TRAN / COMMIT TRAN, etc.
Enough said; you are free to disagree, this is just my opinion. My point
is: do your homework, get the facts, figures and arithmetic, and make
informed architectural decisions as a developer. Do some tests, and evaluate.
Make sure you're comparing apples to apples. Above all, don't accept marketing
"hype" as gospel.
With that in mind, I decided to write a small DB Component that did nothing
but run the CustOrderHist stored procedure in Sql Server against the ever-popular
Northwind sample database, and return a SqlDataReader. I created a Winforms
Test app that calls into the DB component 10,000 times and records the
elapsed time for the run. I compiled a version of the component deriving
from Enterprise Services with AutoDual and Autocomplete, and installed
it in the GAC and COM+ as a Library Application. I compiled a separate
version of the component with no COM+ attributes, just pure C# .NET code.
Aside from these differences, the components are identical. I thought
readers might be interested in my results. As you can see in the chart
below, I did three runs on each test component, and averaged the results.
Serviced Component, GAC'ed Installed as Library in COM+ : 10,000
||Elapsed Time (Sec.)
Only, No COM+ Attributes in classes, 10,000 Calls:
||Elapsed Time (Sec.)
|Performance Cost, COM+:
overhead nearly doubles execution time.
While this cannot be considered to be an authoritative test scenario,
the difference is so dramatic that it's sufficient to confirm my own belief
that COM+ Services is something most developers really don't need. I might
add that the above represents the best times I have obtained for the COM+
installation; subsequent tests with various settings such as Object Pooling
and Just In Time Activation gave even worse results for COM+.
Those readers who are still using VB 6.0 might be interested to know
that an equivalent component and Forms-based test app I wrote in VB 6.0
with the component being a COM DLL, averaged 38.5 seconds for the above
test run. Comments and criticism are always welcome here at our Eggheadcafe.com
forums. In particular, I would be interested in hearing from other developers
who have actually conducted their own test scenarios, since aside from
an excellent piece by Shannon Pahl of MS, "Understanding
Enterprise Services in .NET", and the articles I quote in my
previous article referenced above, all of which more or less confirm the
information I present here, there is literally NO documentation about
this in any of the literature that I've been able to find.
As is my custom, I have provided a downloadable ZIP file containing the
full solutions for both the NETDBComponent and the COMPlusDBComponent,
each with its own Winforms test harness that kicks off the 10,000 call
test and records the elapsed time in seconds, using the System.DateTime.Now.Tick
which records time in 100 nanosecond resolution. There are two batch files
in the bin/Release folder for the COM+ solution "Regme.bat"
and "UnRegme.bat" which will do (or undo) your Gacutil.exe and
your Regsvcs.exe installations for convenience.
COM+ Services is a sophisticated COM - based infrastructure whose primary
value to the developer lies in multi-component transaction control with
object instantiation and pooling services. There is ample support for
these COM+ services in the .NET Framework through the System.EnterpriseServices
namespace as well as attributed programming features. Component Load Balancing
(CLB), available on Application Center Server, enables you to run COM+
Services components on multiple machines with failover and have the components
both appear and function as a single "machine". However, because
of the overhead of COM+ and the fact that expensive cross network calls
are necessary with CLB, it is probably best advised to be used for Database
and other back-end applications. If your objective is speed and scalability,
and you do not need transactions, it would be wise to compare the throughput
using a pure .NET solution, even if you need role - based security in
your application. Such solutions can be hosted through Network Load Balancing
for cost - efficiency and the best possible throughput and scalablity,
and COM+ is neither necessary nor particularly desirable in such configurations.
the code that accompanies this article
|Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform. |