SOA applications need just as much help as traditional web applications when it comes to reliability, performance and traffic management. This article provides four down-to-earth TrafficScript examples to show you how you can inspect the XML messages and manage SOA transactions.
Why is XML difficult?
SOA traffic generally uses the SOAP protocol, sending XML data over HTTP. It's not possible to reliably inspect or modify the XML data using simple tools like search-and-replace or regular expressions. In Computer Science terms, regular expressions match regular languages, whereas XML is a much more structured context-free language.
Instead of regular expressions, standards like XPath and XSLT are used to inspect and manipulate XML data. Using TrafficScript rules, Stingray can inspect the payload of an SOAP request or response and use XPath operations to extract data from it, making traffic management decisions on this basis. Stingray can check the validity of XML data, and use XSLT operations to transform the payload to a different dialect of XML.
The following four articles give examples of traffic inspection and management in an SOA application contect. Other examples of XML processing include embedding RSS data in an HTML document.
Routing SOAP traffic
Let’s say that the network is handling requests for a number of different SOAP methods. The traffic manager is the single access point – all SOAP traffic is directed to it. Behind the scenes, some of the methods have dedicated SOAP servers because they are particularly resource intensive; all other methods are handled by a common set of servers.
The following example uses Stingray's pools. A pool is a group of servers that provide the same service. Individual pools have been created for some SOA components, and a ‘SOAP-Common-Servers’ pool contains the nodes that host the common SOA components.
# Obtain the XML body of the SOAP request
$request = http.getBody();
$namespace = "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"";
$xpath = "/SOAP-ENV:Envelope/SOAP-ENV:Body/*[1]";
# Extract the SOAP method using an XPath expression
$method = xml.XPath.matchNodeSet( $request, $namespace, $xpath );
# For ‘special’ SOAP methods, we have a dedicated pool of servers for each
if( pool.getActiveNodes( "SOAP-".$method ) > 0 ) {
pool.select( "SOAP-".$method );
} else {
pool.select( "SOAP-Common-Servers" );
}
TrafficScript: Routing SOAP requests according to the method
Why is this useful?
This allows you to deploy SOA services in a very flexible manner. When a new instance of a service is added, you do not need to modify every caller that may invoke this service. Instead, you need only add the service endpoint to the relevant pool.
You can rapidly move a service from one server to another, for resourcing or security reasons (red zone, green zone), and an application can be easily built from services that are found in different locations.
Ensuring fair access to resources
With Stingray, you can also monitor the performance of each pool of servers to determine which SOAP methods are running the slowest. This can help troubleshoot performance problems and inform decisions to re-provision resources where they are needed the most.
You can shape traffic – bandwidth or transactions per second – to limit the resources used and smooth out flash floods of traffic. With the programmability, you can shape different types of traffic in different ways. For example, the following TrafficScript code sample extracts a ‘username’ node from the SOAP request. It then rate-shapes SOAP requests so that each remote source (identified by remote IP address and ‘username’ node value) can submit SOAP requests at a maximum of 60 times per minute:
# Obtain the source of the request
$ip = request.getRemoteIP();
# Obtain the XML body of the SOAP request
$request = http.getBody();
$namespace = "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"";
$xpath = "/SOAP-ENV:Envelope/SOAP-ENV:Body/*/username/text()";
# Extract the username using an XPath expression
$username = xml.XPath.matchNodeSet( $request, $namespace, $xpath );
# $key uniquely identifies this type of request from this source.
$key = $ip . ", " . $username;
# The 'transactions' rate shaping class limits each type to 60 per minute
rate.use( "transactions", $key );
TrafficScript: Rate-shaping different users of SOAP traffic
Why is this important?
An SOA component may be used by multiple different SOA applications. Different applications may have different business priorities, so you might wish to prioritize some requests to a component over others. Applying ‘service governance’ policies using Stingray's rate shaping functionality ensures that all SOA applications get fair and appropriate access to critical components, and that no one application can overwhelm a component to the detriment of other applications.
This can be compared to time-sharing systems – each SOA application is a different ‘user’, and users can be granted specific access to resources, with individual limits where required.
When some SOA applications are externally accessible (via a web-based application for example), this is particularly important because a flash flood or malicious denial-of-service attack could ripple through, affecting many internal SOA components and internal applications.
Securing Traffic
Suppose that someone created a web services component for a travel company that enumerated all of the possible flights from one location to another on a particular day. The caller of the component could specify how many hops they were prepared to endure on the journey.
Unfortunately, once the component was deployed, a serious bug was found. If a caller asked for a journey with the same start and finish, the component got stuck in an infinite loop. If a caller asked for a journey with a large number of hops (1000 hops perhaps), the computation cost grew exponentially, creating a simple, effective denial of service attack.
Fixing the component is obviously the preferred solution, but it’s not always possible to do so in a timely fashion. Often, procedural barriers make it difficult to make changes to a live application. However, by controlling and manipulating the SOA requests as they travel over the network, you can very quickly roll out a security rule on your SDC to drop or modify the SOAP request. Here’s a snippet:
$request = http.getBody();
$from = xml.XPath.matchNodeSet( $request, $namespace, "//from/text()" );
$dest = xml.XPath.matchNodeSet( $request, $namespace, "//dest/text()" );
# The error response; can read a precanned response from disk and return
# it as a SOAP response
if( $from == $dest ) {
$response = resource.get( "FlightPathFaultResponse.xml" );
connection.sendResponse( $response );
}
$hops = xml.XPath.matchNodeSet( $request, $namespace, "//maxhops/text()" );
if( $hops > 3 ) {
# Apply an XSLT that sets the hops node to 3
$transform = resource.get( "FlightPath3Hops.xslt" );
http.setBody( xml.XSLT.transform( $request, $transform ) );
}
TrafficScript: Checking validity of SOAP requests
Why is this important?
Using the Service Delivery Controller to manage and rewrite SOA traffic is a very rapid and lightweight alternative to rewriting SOA components.
Patching the application in this way may not be a permanent solution, although it’s often sufficient to resolve problems. The real benefit is that once a fault is detected, it can be resolved quickly, without requiring in-depth knowledge of the application. Development staff need not be pulled away from other projects immediately. A full application-level fix can wait until the staff and resources are available; for example, at the next planned update of the component code.
Validating SOAP responses
If a SOAP server encounters an error, it may still return a valid SOAP response with a ‘Fault’ element inside.
If you can look deep inside the SOAP response, you’ve got a great opportunity to work around such transient application errors. If a server returns a fault message where the faultcode indicates there was a problem with the server, wouldn’t it be great if you could retry the request against a different SOAP server in the cluster?
$response = http.getResponseBody();
$ns = "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"";
$xpath = "/SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault/faultcode/text()";
$faultcode = xml.XPath.matchNodeSet( $request, $namespace, $xpath );
if( string.endsWith( $faultcode, "Server" ) ) {
if( request.retries() < 2 ) {
request.avoidNode( connection.getNode() );
request.retry();
}
}
TrafficScript: If we receive a Server fault code in the SOAP response, retry the request at most 2 times against different servers
Why is this important?
This particular example shows how the error checking used by an SDC can be greatly extended to detect a wide range of errors, even in responses that appear “correct” to less intelligent traffic managers.
It is one example of a wide range of applications where responses can be verified, scrubbed and filtered. Undesirable responses may include fault codes, sensitive information (like credit card or social security numbers), or even incorrectly-localized or formatted responses that may be entirely legitimate, but cannot be interpreted by the calling application.
Pinpointing errors in a loosely-coupled SOA application is a difficult and invasive process, often involving the equivalent of adding ‘printf’ debug statements to the code of individual components. By inspecting responses at the network, it becomes much easier to investigate and diagnose application problems and then work round them, either by retrying requests or transforming and rewriting responses as outlined in the previous example.
... View more