A good architecture and design are necessary for the development of a successful application. The success of an application lies in its robustness and maintainability. These qualities are governed by the design and architectural choices that you make at the start of the project. Using the correct architecture is a key to ensuring the performance and scalability of an application. However, most of the time, you must maintain a balance between performance and scalability, probably favoring one more than the other, depending on the requirements.
In this article, you will learn about the factors that will help you to determine whether to trade performance for scalability, or vice-versa. The overhead that is incurred when you provide the ability to scale a distributed application frequently leads to a decrease in performance. When you scale an existing application, you either scale up or scale out. Scaling up, which is most frequently used in client/server scenarios, is the process of adding hardware, such as more or faster RAM, disks, and processors; scaling out is the process of adding more servers. You can use a combination of the two mechanisms. However, if your applications are not designed for processing on multiple computers, you must scale up. Therefore, the issue you face when you design your distributed applications is whether to enable scaling or to focus on the performance of the application. The decision between performance and scalability is not a simple choice between one or the other: a correctly designed distributed application, designed to scale out, can perform better than traditional client/server applications. Generally, however, the more scalable an application is, the more the performance suffers. The hardware that you deploy has a big effect on the design and on the tradeoffs that you must consider.
Your design choices affect the scalability and performance of your application. To make the right choices, you must have a clear understanding of the application requirements and the features of .NET Remoting. Taking your requirements into consideration, you must make decisions about the following factors: activation model, channel and formatter, implementing the common assembly, synchronous or asynchronous calls, events, and the default object lifetime.
Stateful one object singleton
The manner in which a remote object is activated has a large effect on the affinity, state management, load balancing, performance, and scalability of your Remoting application. Based on these factors, and whether and how they apply to your architecture, you can implement either server-activated objects (SAO) or client-activated objects (CAO).
You use SAOs when you have more than one server providing services to clients. When you use SAOs, any one of the available servers that receives the request will be able to service the request. You can use either Single-Call SAOs or Singleton SAOs. You use Single-Call SAOs when you do not have to maintain the state of the objects. On the other hand, if you must perform state management, you use Singleton SAOs.
CAOs work well when you are using a single-server approach. When you are using a single-server approach, you do not provide load balancing or failover clustering, and you use components that maintain state for their specific client. With CAOs, you can obtain total control over object creation and the lifetime of the remote object.
Channel and formatter
Choosing the appropriate channel and formatter will affect the speed of message transfer and interoperability. The environment in which you want to deploy your Remoting application determines the channel and formatter that should be used.
In .NET Remoting, there are two channel types to choose from: Transmission Control Protocol (TCP) and Hypertext Transfer Protocol (HTTP).
- The TCP channel (
TCPChannel class) provides maximum performance for a Remoting solution. The TCP channel does not provide built-in authentication and authorization checks. Therefore, use the TCP channel if your Remoting solution is deployed in a trusted environment without any firewalls.
- Use the HTTP channel (
HTTPChannel class) when you need interoperability or when you need to allow communication through a firewall.
In .NET Remoting, you have the option of using either the SOAP formatter or the binary formatter. Like the binary formatter, both TCP and HTTP channels can work with SOAP. Choose SOAP when you need interoperability and in applications that cross platform boundaries. The SOAP formatter is not optimal in performance because it is based on XML. This adds a performance overhead because of XML's self-descriptive tags and metatags.
Both the TCP and HTTP channels support the binary formatter. Choose the binary formatter when performance is the priority. The binary formatter reduces the size of data transmitted and is therefore faster.
|HTTP channel||TCP channel|
|Used to communicate over the Internet||Used to communicate within an intranet|
|Able to access the existing security systems of the HTTP server||Must develop a security system based on the .NET Framework base classes|
|Is less efficient in communication||Is more efficient in communication|
|SOAP Formatter||Binary Formatter|
|Information is sent by using SOAP||Information is sent by using binary messages|
|Is ideal for communication between applications that use incompatible architectures||Can be read only by .NET Framework applications|
|Is text-based||Is binary and compact|
Implementing the common assembly
Using generic and reusable assemblies enables you to quicken the application development process and, to a degree, allows a successful architecture to be re-used. You can implement a common assembly either by deploying it locally as a private assembly or by embedding the assembly in the Global Assembly Cache (GAC). Choose to implement the common assembly in a GAC when you must provide compatibility between the various versions of your libraries. If both the server and the client use the common assembly, then you can implement it by using interfaces, abstract classes, stub base classes, or Soapsuds-generated proxies.
Interfaces are suitable for hiding the implementation from the definition and can be used to avoid deploying the common assembly for the client. Abstract classes have certain characteristics in common with interfaces. However, abstract classes cannot be instantiated, though they can and should contain implementation code. The difference between interfaces and abstract classes, however, is that abstract classes can be passed as parameters to methods in different application domains. Stub base classes are similar to interfaces and abstract classes in that stub base classes are used as the framework of the remote type. However, you can create an instance of a class from a stub base class. The Soapsuds-generated proxies are most frequently used with non-Microsoft Web services that you want to wrap in a proxy. As the name suggests, Soapsuds-generated proxies can be used only with SOAP calls.
Options for a Common Assembly:
- Interfaces: An interface defines a set of properties, methods, and events. Unlike classes, interfaces do not provide implementation. You define an interface as a separate entity from the classes that implement it. When a class implements an interface, it must implement all the methods that are declared in that interface. An interface must define the methods that set and get data. However, the interface will not implement these methods. You use an interface to define a protocol of behavior that any class can implement. Use interfaces to:
- Capture similarities among unrelated classes without artificially forcing a class relationship.
- Declare the methods that one or more classes are expected to implement.
- Reveal an object’s programming interface without revealing its class.
- Abstract base classes: An abstract class has one or more abstract methods. Abstract classes act as expressions of general concepts from which you can derive more classes that are specific. An abstract class serves as a base class from which other classes can inherit properties and methods. You cannot create an object of an abstract class type; however, you can pass references to abstract class types. You use abstract base classes to provide default behavior or to define families.
- Stub base classes: You cannot directly instantiate an abstract class or an interface. If you want to create your remote object on the client directly by using the
new operator, you can define the remote type in the common assembly as a non-abstract class. A stub class is intended as the framework of your remote type; using a stub class is much like using an interface or abstract class. You should still implement the remote type as a class, which is derived from the stub, in the server. Because the stub is not abstract, it is possible to accidentally create a local instance of the stub base class instead of a remote object.
- SOAPSuds-generated proxies: SOAPSuds is a command-line tool that generates an assembly containing a proxy class representing the remote object. The SOAPSuds tool can generate code in addition to an assembly. You can also use SOAPSuds to generate a proxy from a remote object hosted on another computer, provided the object is hosted using an HTTP channel. To use a SOAPSuds-generated proxy, your channel must use the SOAP formatter.
- Factory design pattern: Most implementations of the Factory pattern use two abstract classes,
Product, to provide the invariant interfaces. Although you could use pure interfaces to implement the factory pattern, the use of abstract classes enables you to place common instance behavior in the abstract class. In addition, abstract classes offer versioning benefits over pure interfaces.
When implementing the factory design pattern, follow these guidelines:
- Do not directly create an instance of the CAO on the server. Use an SAO instead, which acts like a factory and returns the actual CAO object to the client.
- Ensure that the SAO factory has one or more methods to create the CAO object.
- Do not expose the implementation of the CAO to the client. Create an interface and let the client use this interface to make calls on the CAO object.
- Do not expose the server code (remote object implementation) to the client. Distribute the interfaces.
Synchronous versus asynchronous calls
You can invoke remote calls by using synchronous or asynchronous calls. Choosing the most appropriate remote calling method lets you increase the responsiveness of your application and possibly improve performance.
Use synchronous calls when you do not need parallel processing of client requests. The advantage of using synchronous calls is that you catch return values and throw exceptions immediately. The disadvantage of using synchronous calls is that the responsiveness of the application is slower because the Remoting server has to wait until all clients acknowledge and then process the callback.
If you require good client responsiveness, consider invoking remote method calls asynchronously. For example, use asynchronous calls with Microsoft Windows Forms applications. However, if your client is an ASP.NET application, invoking methods asynchronously and then blocking the calling thread to pick up return values could lead to ThreadPool starvation. Also, if the server goes down, exceptions are thrown at the client. This is because the client is not aware of the state of the server. The only real solution to this problem is a periodic recycling of the client application.
Whether to use events
Use of events and callbacks can cause overhead on the server because the server holds references to all the clients that registered an interest in a published service. Regardless of whether you use synchronous or asynchronous calls to register events, problems can occur at either the client or the server. To improve responsiveness, you can use Message Queuing (also known as MSMQ). Message Queuing enables the server to send messages to clients without having to wait for an acknowledgement from the client.
Whether to use the default object lifetime
.NET Remoting uses the lease sponsor process to manage the lifetime of an object. The default lifetime of an object is set to five minutes. To determine the appropriate object lifetime for your application, you must strike a balance between the resource usage on the server and the performance implications of frequently destroying and re-creating objects. Following are the general guidelines that you can use when you must change the default lifetime of an object:
- Use a longer lease time for objects whose creation incurs a high performance overhead.
- If you use objects whose creation incurs a high performance overhead, increase the default lease timeouts so that the object remains longer.
- Use shorter lease times for objects that consume many shared resources.
- If you create objects that use shared resources, use a shorter lease time for the object. When you reduce the default lifetime, the object is destroyed and resources are released quickly.
Hosting remote applications on Microsoft Internet Information Services (IIS) involves less development work than hosting applications in Windows services. However, performance with IIS is slower than with Windows services because hosting applications in IIS adds the overhead of a Web server. Also, IIS supports only the HTTP protocol. Because of this limitation, you cannot take advantage of the performance of TCP, which is a protocol with far less overhead. Windows services are useful if the computer does not have an IIS Web server installed on it for security reasons. It is also easier for technical support personnel to manage Windows services and to make sure that the services are running as they should. Finally, if you do not have to host Web pages, using Windows services is a better option because you do not have to maintain a Web server, which requires specific product support knowledge and additional server resources.
|Quality||Command-line windows||Windows Forms||Windows Service||IIS|
|Recommended for prototyping||yes||yes, when using configuration files||no||no, requires virtual directory setup|
|Automatic start up with Windows||no||no||yes||yes, if IIS is set to start auto.|
|Recommended to be used for production||no||no||yes, when you want to have host constant availability||yes, when you want fast time production|
|Fault tolerant||no||no||yes, after shut down||no|
|Built-in security options||no||no||none||SSL, Certifications, built-in authentication|
Best Practices for Remoting:
Use Remoting for appropriate scenarios
.NET Remoting is the preferred communication mechanism for single process, cross– application domain communication. For communication across processes, across servers, or across deployment or trust boundaries, ASP.NET Web services are generally the recommended option because they are built on industry standards that make it easy to achieve interoperability. However, if state and raw performance—which can be achieved with the TCP channel and the binary formatter—are important, and if interoperability is not a concern, Remoting is a better choice.
Design chunky interfaces
Chatty interfaces result in multiple roundtrips to perform a single logical operation. To reduce the number of roundtrips and thereby increase performance, use chunky interfaces. In a chunky interface, you transfer the necessary data in a single roundtrip. In contrast, chatty interfaces are typically attributed by means of properties. This means that you set a number of properties and then run one or more methods. This is generally appropriate for Object Oriented Programming (OOP), but it is not a suitable option for Remoting.
Use efficient data types
It is important that you use the most efficient data types with Remoting. For example, if you use a
DataSet object to store data, the object can hold multiple tables and can be serialized and deserialized to Extensible Markup Language (XML) with a single method call. However, you must realize that using
DataSet objects can increase the network traffic because of the serialization and deserialization to XML.
Use SingleCall SAOs whenever possible
A Single-Call object has a unique instance for each client request. Therefore, Single-Call objects live only for the life of the method call. These objects do not maintain state information because they are destroyed after servicing the method. Because Single-Call objects do not store state information, they are free from synchronization code and therefore remove the overhead of state management. Single-Call objects hosted in IIS, using the HTTP channel, provide maximum scalability for your .NET Remoting solution.
Avoid blocking operations
In Remoting, blocking means that, while a process is running, other processes must wait until the running process finishes execution. Therefore, if many long-running operations are occurring in your application at the same time, many threads are blocked while waiting for the other processes to finish execution. This situation leads to low throughput and low CPU utilization. You must identify any potential tasks that can run at the same time and design your application to support these tasks. Designing your application in this way leads to better request/response performance for your Remoting servers.
In trusted server environments, use the TCP channel and the binary formatter
In trusted server environments, you do not have any firewalls. Therefore, for best performance, use the TCP channel with binary formatters. Also, because you have a trusted environment, you do not have to implement additional security mechanisms, such as encryption of data. For example, in an intranet, if all users authenticate against a domain, you could allow access to the Remoting application to all domain users.
Control object lifetime and avoid in-memory state management
You must control object lifetimes to be able to effectively manage the creation of objects and to release the resources associated with objects. Also, you must avoid storing state in memory. Poor in-memory state management hampers scalability and performance and might make failover support impossible.