Christoph Schittko is an architect for Microsoft, based in Texas. His focus is to work with customers to build innovative solutions that combine software + services for cutting edge user experiences and the leveraging of service-oriented architecture (SOA) solutions. Prior to joining Microsoft, Christoph assisted companies with the adoption of service orientation and the delivering of Software-as-a-Service (SaaS) solutions. Christoph holds an advanced degree in Electrical Engineering from the Friedrich-Alexander University Erlangen-Nürnberg. His extensive experience in developing and architecting software solutions in a wide variety of industries allows him to write and to speak at various conferences on Web services and XML.
Service Performance Optimization Techniques for .NET - Part II Published: February 27, 2013 • Service Technology Magazine Issue LXX PDF
Abstract: This is the second article in a two-part article series. Read the first part of this article here.
Coarse-Grained Service Contracts
The capability granularity and constraint granularity of a service contract can greatly impact performance of the service architecture. A service consumer communicating over a network connection can experience significant latency between request and response when exchanging large messages over poor network connections. Network latency is often beyond your control, especially when you consume third party services over a public network. Nevertheless you can architect your services to minimize the performance impact of remote service interactions.
The key consideration to keep in mind is to "make it worth the trip across the network". In other words, keep the ratio of processing time greater than the time it takes to establish the network connection and transmit the data. Figures 14 and 15 compare the performance models for these two scenarios. Figure 14 shows the model for a chatty contract design with very fine grained capabilities. The impact of the message transmission increases relative to the execution time the consumer observes for invoking a service capability.
Figure 8 - The transmission of a message across the wire can result in a substantial piece processing.
In the next scenario (Figure 9), the service is architected to reduce the number of calls across the network. Fewer calls reduce the overhead of managing network connections and should produce capabilities that take longer to process than the message transmission.
Figure 9 - Lightweight protocols and better execution-time-to-transmission time ratios improve performance of remote service invocations.
Scaling out is another common approach to reduce contention and decrease the average time it takes for a service to handle concurrent service requests. Several servers handle requests sent to a single service endpoint, thereby increasing the number of messages a service can handle concurrently without increasing contention on a single server.
Selecting Application Containers
The choice of a service’s hosting model can greatly impact its performance because of the differences in the processing that occur for incoming and outgoing messages. Usually you see a trade-off between robustness and a rich feature set on one hand and high performance on the other. Many features require additional layers of processing between the service endpoint and the service implementation. Each layer adds time and decreases performance.
Let's take a look at four specific hosting models:
BizTalk Server offers numerous features to increase reliability, availability and scalability. Unfortunately, many of these features require a fair amount of additional processing and thus, decrease performance because each extra processing step adds to the duration of the execution of a service capability. Figure 15 shows the processing steps of a standard BizTalk request.
Figure 10 - BizTalk Server's scalability, robustness and fault tolerance features add overhead to the performance model.
Notice not only the sheer number of steps that occur, but also that state is saved to a database between these steps. Database read and write functions are typically several orders of magnitude slower than in-process memory access. For simple service capabilities, the duration may increase significantly when you host a service inside BizTalk Server. The additional overhead may be negligible for long-running transactions where the execution time of a process depends on humans or other systems and thus, may not cause a noticeable performance impact.
WAS and IIS perform far less processing steps than BizTalk Server. ASMX services, for example, perform authentication, authorization and, in some cases, parse HTTP cookies to get the service's session state identifier. Those steps may include database lookups or validating user credentials against an Active Directory server, but the message is never stored to a database between those steps. Web services hosted in BizTalk Server perform all the steps for ASMX service plus the steps shown previously in Figure 10.
Request processing in WAS can be even leaner than ASMX, when ASP.NET compatibility is disabled and all policy processing is delegated to WCF. If runtime service performance is a high priority, then you can further reduce the latency to a minimum by investing in very fast servers and high-bandwidth network infrastructure.
Properly architected solutions with high performance WCF bindings hosted in highly scalable containers such as WAS can drastically reduce the processing overhead compared to BizTalk Server and thus provide better performance. Your decision for one hosting model or another always depends on your unique set of functional and non-functional requirements. BizTalk's architecture also provides several features to scale out different processing tasks to increase overall system throughput. However, that's not the primary metric used to define performance in this article.
The previous section touched on the performance impacts of different service containers due to the differences in how they process messages. The actual processing effort doesn't just depend on the container; it also depends on the policies you apply to a service endpoint. WCF and BizTalk Server platforms do a great job to reduce the development effort of applying and changing policies, but it's still crucially important to understand the performance differences of different policies.
WCF abstracts policies into bindings that you can apply to a service endpoint, which somewhat obscures the processing steps for these policies. Figure 16 illustrates the high-level stages of processing in a binding.
Figure 11 - WCF Bindings can apply policies for transactions, reliable messaging, security as well as custom policies.
Let's compare the BasicHttpBinding and WsHttpBinding, as shown in Figure 12 and Figure 13.
Figure 12 - The policies included in BasicHttpBinding do not add significant processing.
Figure 13 - The default security policies in WsHttpBinding add a considerable amount of extra message processing.
Both bindings communicate via SOAP and XML over HTTP and both rely on DataContractSerializer to serialize message objects into XML messages. However, their performance is very different.
WsHttpBinding is configured for secure message transmission by default, so that messages are signed, encrypted, and the signature is further encrypted as well. This approach achieves high security, but it also introduces burden with respect to performance. WCF allows you to turn off message security for the WsHttpBinding, which makes performance between the BasicHttpBinding and WsHttpBinding comparable again.
Security isn't necessarily an all or nothing requirement. Sometimes you can find a middle ground, for example by being selective about where and how much message security you'd like to apply. This decision depends on the data you're transmitting. If data is sensitive and confidential, then you may have no other option than signing and encrypting the messages. Your only means of tuning performance in this case is the encryption algorithm you apply and whether you choose to involve special devices to perform encryption in hardware.
In other cases, the data may not be confidential, but you still care about possible attacks. You can reduce the processing overhead of the default setting in WsHttpBinding by avoiding the final step of encrypting the signature or by avoiding encryption altogether. You can still sign messages to guarantee that they were not tampered with; however, you are avoiding the costly steps of encrypting messages and signatures.
Another option that you may consider is to sign only the WS-Addressing headers to protect your service from spoofing.
Security is not only costly because of the additional computing overhead, but also because it increases message size. Table 1 illustrates the differences in message size between various unsecured and secured messages.
Table 1 - Message size increases considerably when adding WS-Addressing and even more by adding encryption. The actual message body is only 597 characters.
WCF allows you to specify increasing levels of message security at different levels of granularity. Attributes, such as the ServiceContract, CapabilityContract and several others, expose a ProtectionLevel property that controls security policies at a fine-grained level. You can set the property to None, Sign or SignAndEncrypt. However, ProtectionLevel only specifies the minimum level.
REST Service Message Sizes
Selecting REST over SOAP as the message format can reduce message size even further. REST does not require a SOAP envelope, which shaves off at least 107 protocol-related bytes of each transmitted message.
REST can also provide performance benefits related to caching; however, you need to evaluate requirements for other service policies and transmitted content before selecting REST as an approach solely for performance improvement reasons. REST intentionally restricts services to HTTP transports, which also limits options for security, durable messaging, and other requirements.
Delegating encryption to dedicated hardware is an interesting option to help boost performance. Encryption in hardware is generally much faster than software-based encryption solutions.
There are several hardware architectures for encryption acceleration:
Again, it's important to understand the trade-offs between these solutions.
Transport encryption can leverage SSL accelerators, which are readily understood, widely deployed, and transparent to the services that they protect. The accelerator handles all encryption and decryption of outgoing and incoming messages.
However, SSL is designed for point-to-point HTTP communication, which is not suitable for service composition architectures that require multi-hop scenarios with routers and intermediaries. SSL servers always decrypt messages before passing them on, regardless of whether they carry SOAP, REST, or other types of messages. This leaves them vulnerable on intermediary servers as illustrated in Figure 14.
Figure 14 - Transport-layer security with hardware accelerators does not provide end-to-end security.
The common belief is that you trade increased risk for performance and well understood infrastructure with transport-layer encryption. In this case, the performance hit of decrypting and re-encrypting messages along a multi-hop chain negates some, if not all of the advantages of a hardware accelerated SSL-solution. A message-layer security framework would encrypt the message at the originating server (hosting the initial sender) and then decrypt only at the ultimate receiver. Therefore, message-layer security provides an end-to-end solution without gaps and therefore does not require decryption and encryption cycles within each intermediary along a message path.
Message encryption is the result of applying the Data Confidentiality pattern. It is carried out with devices that encrypt messages compliant with WS-Security standards and the WS-I Basic Security Profile. This industry standards-based approach provides interoperability with contemporary Web service platforms. In contrast to SSL devices, dedicated Web service devices do not have to decrypt and re-encrypt on intermediaries. As a result, performance and security are higher compared to an SSL solution in environments where SOAP routers and intermediaries exist.
Also noteworthy is that these differences increase with the number of intermediaries. Figure 15 depicts a solution with appliances for encryption and decryption of messages.
Figure 15 - Web service appliances provide encryption along the entire transmission path.
Custom Encryption Solution
A custom encryption approach relies on a utility encryption service to encrypt sensitive parts of a message. Ideally, the utility service front-ends a hardware solution, such as a server with custom encryption hardware or a special appliance that performs all the cryptographic capabilities (Figure 16).
Figure 16 - Custom encryption combined with encryption appliances provides a fast, but proprietary solution.
This utility service handles all performance intensive encryption and decryption algorithms and thus boosts overall performance. It does so at the expense of an additional remote service interaction and does not rely on open WS-Security industry standards.
While this approach allows for end-to-end encryption, you can't easily articulate which message parts are encrypted using WSDL or WS-Policy. Service and service consumer have to communicate to understand when and how to encrypt and decrypt messages. The benefit of this architecture is the reuse provided by the encryption utility service.
Whether or not a custom solution provides benefits for you depends on how frequently you perform encryption capabilities and if you can reuse an encryption utility service for other scenarios.
Table 2 summarizes the key arguments for the three architecture options.
Table 2 - A comparison of three performance solutions for encryption.
High Performance Transport
WCF, and therefore by extension BizTalk Server, offer alternative, more efficient transports than SOAP over HTTP. Bindings with names beginning with Net, such as NetTcpBinding or NetNamedPipesBinding provide efficiencies on the network by formatting messages in a binary format rather than text-based XML.
The performance advantages come from the binary representation of the message and more efficient connection management. However, the performance gain in situations where messages are secured can be small compared to the hardware-assisted solutions.
More importantly, bindings like the NetTcpBinding recognize that TCP is originally intended for stateful connections, not the single-call model associated with HTTP over TCP. NetTcpBinding includes optimizations to reduce the number of times connections between the service and the consumer are closed to avoid the performance hit of establishing a new connection for every service capability.
The impacts of this optimization are tighter coupling, a proprietary communication protocol, and the loss of the ability to load balance service calls across multiple servers. You can work around these issues by, for example, implementing the Dual Protocol pattern with multiple endpoints tied to the same service. You can also solve load balancing issues by randomizing the service endpoint a consumer connects to for the initial call that establishes the connection. You could, for example, obtain an endpoint reference from a look-up service that hands out different addresses in a round-robin fashion.
The original XML specification requires base64 encoding of all binary data inside an XML document. Similar to encryption, encoding is a separate processing step that takes extra time. In addition, the base64 encoding algorithm increases message sizes by 33%. That means the transmission time over the wire will also increase by 33%, unless we use some form of compression.
The MTOM industry standard aims to avoid base64 encoding of binary data in XML documents. Instead, SOAP messages are transmitted as multi-part MIME messages. The first MIME part contains the XML message, but all message parts of type byte only contain pointers to subsequent parts of the MIME message.
These subsequent parts only hold the raw binary data to avoid the processing overhead of base64 encoding and decoding as well as the bloat of the message. The MIME protocol adds a little bit of extra overhead, but it's small compared to the 33% increase of base64 encoding, and only significant when the binary data is less than 1KB in size.
The MTOM encoder in WCF analyzes an array of sizes to determine the smaller encoding format. The encoder encodes binary data in the base64 format if the amount of binary information is less than 1KB. Otherwise the encoder chooses the MTOM format.
You can select the MTOM encoder simply by configuring the binding's messageEncoding or setting the MessageEncoding property programmatically. Example 19.15 shows basicHttpBinding configured for MTOM encoding:
<system.ServiceModel> <bindings> <basicHttpBinding> <binding name="..." messageEncoding="Mtom" /> ... </basicHttpBinding> </bindings> </system.ServiceModel>
MTOM encoding makes transfer of large binary data more viable than transmitting it as an XML document. However, you need to examine if transmitting large binary objects in one message itself is actually a realistic approach. Transferring large binary objects in one swoop is more likely to fail on unreliable networks and can then require full re-transmission in case of failure. A chunked transmission approach is more resilient to network failure and can resume transmission at the point of failure.
Performance Considerations for Service Contract Design
There are many settings you can tweak to increase performance after you have deployed a service. Ideally, you should identify services with high performance requirements and design service contracts accordingly rather than relying on your ability to tune performance later. Contract design probably has the biggest impact on performance of all the options we've discussed so far.
However, in practice, you have to make some hard trade-off decisions between performance, reusability, and maintainability of a service contract. Optimizing only for reuse often results in service capabilities that return large amounts of data to make the response relevant to a larger range of service consumers.
When performance matters, however, service capabilities can do as little processing as needed. Because requirements can vary between consumers, how much processing is necessary is best decided by the individual consumer. This is where Contract Denormalization can provide an effective means of accommodating multiple service consumers with the same service contract by providing intentionally redundant service capabilities optimized for different consumer types.
It's important to give consumers options to select how much processing the service is going to perform and how much data it is going to return. A Customer entity service, for example, could let the consumer decide if it requires results in a concise or detailed format. With Contract Denormalization, you can design contracts with this type of flexibility.
In general, you can follow a loosely coupled approach or you can opt for a more strongly-typed, deterministic approach when defining individual service capabilities within a contract. The loosely coupled approach will tend to involve weaker typed capabilities that may rely on the use of parameters. The deterministic approach, on the other hand, can be easier to apply with Visual Studio, where you derive .NET classes from the service's WSDL definition.
The official series text book for service contract design and optimization techniques is "Web Service Contract Design & Versioning for SOA."
It's technically not necessary to mark reference types, such as the byte array in Example 6, as IsRequired=false for WCF or ASMX services because reference types are by default optional.
The default XML Schema representation for the ProductImage element without an IsRequired property or with IsRequired=false is:
<xs:element minOccurs="0" name="ProductImage" nillable="true" type="xs:base64Binary" />
Specifying IsRequired=true on the other hand does force the presence of the element in the message:
<xs:element name="ProductImage" nillable="true" type="xs:base64Binary" />
The minOccurs="0" statement that marks the element as optional content is no longer present in the schema.
If transmitting large amounts of unnecessary data is hurting performance of a service you can also choose to layer another service over the first service to trim the data flowing to the service consumer. This is only effective if the data transmission is the cause of a performance problem. In some cases, generating the response is more of a performance concern than the actual message transmission. Introducing another service layer also introduces additional overhead that further can decrease the effectiveness of this approach. Multi-Channel Endpoint may prove to be a more appropriate means for reducing message sizes.
Impact on Service-Orientation Principles
We've discussed a number of different techniques for how to architect services for performance. Let's now study how these techniques can impact the application of service-orientation principles. Table 3 summarizes these impacts.
Table 3 – A summary of different techniques and how they impact the application of service-orientation principles.