10 Web services Performance Tuning Tips

This tutorial focuses on design guidelines and techniques to improve the performance of your SOAP Web services. Enjoy it!

#1 Use coarse grained Web Services

One of the biggest mistakes that many developers make when approaching web services is defining operations and messages  that are too fine-grained. You should try to reduce the requests by using a few coarse grained (highly functional) APIs, rather than several simple APIs. At the same time, make sure your message reflect your business use case rather than your programmer’s framework.

The reason why top-down Web services are the pure web services is really this: you define at first the business and then the programming interface.
Don’t define a web service operation for every Java method you want to expose. Rather, you should define an operation for each action you need to expose.

public void checkInventory(long itemId) {
 InventoryDAO.checkInventory(itemId);
}
public void checkAccount(long itemId) {
 CustomerDAO.checkAccount(clientId);
}
public void saveOrder(long itemId, long clientId) {
 OrderDAO.persisteOrder(itemId,clientId);
}

and this is the coarse grained web service we expose:

@WebMethod
public void makeOrder(long itemId, long clientId) {
 InventoryDAO.checkInventory(itemId);
 CustomerDAO.checkAccount(clientId);
 OrderDAO.persisteOrder(itemId,clientId);
}

For the sake of simplicity we don’t have added any transaction commit/rollback. However, what we want to stress is that the first kind of web service is a bad design practice. Also, it will yield poor performance because of 3 round trips to the server carrying SOAP packets.

#2: Use primitive types, String or simple POJO as parameters and return type

You can design Web services from the grounds up to be interoperable components. That is you can return both primitive types and Objects. How does a C# client is able to retrieve a Java type from a Web Service or viceversa ? that’s possible because the Objects moving from/to the Web services are in XML format.

As you can imagine, the size of the Object which is the parameter or the return type has a huge impact on the performance. Be careful with Objects which contain large Collections as fields. They are usually responsible of web services bad performance. If you have collections or fields which are not useful in your response mark them as transient fields:

@XmlRootElement
public class Customer   {
 
    private String password;
    private List<String> phoneNumbers;
 
    @XmlTransient
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    @XmlElement(name = "phone-number")
    public List<String> getPhoneNumbers() {
        return phoneNumbers;
    }
 
    public void setPhoneNumbers(List<String> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }
 
     
}

#3: Evaluate carefully how much data your need to return

Consider returning only subsets of data if the Database queries are fast but the graph of Object is fairly complex. Example:

@PersistenceContext(unitName = "persistenceUnit")
private EntityManager em;
 
@WebMethod
public List  readTaskListByPage(@WebParam(name = "start") 
 int start,
 @WebParam(name = "stop")  
 int stop) {

 Query dbQuery = em.createQuery(query);    

 List   listObjects = dbQuery.setFirstResult(start)
 .setMaxResults(stop-start).getResultList();

 return listObjects;        

}

Check this tutorial to learn how to paginate your Entity objectsHow to paginate your Entity data

On the other hand, if your bottleneck is the Database Connectivity reduce the trips to the Service and try to return as much data as possible.

#4: Inspect your SOAP packet

This tip is the logic continuation of the previous one. If you are dealing with complex Object types always check what is actually moving around the network. There are many ways to sniff a SOAP packet, from a tcp-proxy software which analyze the packets between two destinations.

The following tutorial covers all tips and hints to debug SOAP Web Services: How to debug Web Service request and response

#5: Cache on the Client when possible

If your client application requests the same information repeatedly from the server, you’ll eventually realize that your application’s response time, is not fast enough.
Depending on the frequency of the messaging and the type of data, it could be necessary to cache data on the client.

This approach, however, needs to address one important issue: how do we know that the data we are requesting is consistent ? the technical solution to this is inverting the order of elements: when the Data in your DB is stale, you need to notify your Clients so that they can refresh their caches.

When using a middleware such as WildFly / JBoss EAP, it will act as a client towards the Database. Check if using a second level cache is an option for your use case: Using Hibernate second level cache with JBoss AS and WildFly

#6: Evaluate using async messaging model

In some scenarios, responses to Web service requests are not instantaneous. Rather, they might require sometime after the initial request transactions complete. This might be due to the fact that the transport is slow and/or unreliable, or the processing is complex and/or long-running. In this situation you should consider an asynchronous messaging model.

JAX-WS supports two models for asynchronous request-response messaging: polling and callback. Polling enables client code to repeatedly check a response object until it is available. Alternatively, the callback approach defines a handler that processes the response asynchronously when it is available.

Consider using asynchronous Web methods is particularly useful if you perform I/O-bound operations such as:

  • Accessing streams
  • File I/O operations
  • Calling another Web service

Finally, check this tutorial to learn more about using Async Web Services: JAX-WS asynchronous Web Services made simple

#7: Override the default Binding Rules

Consider the following domain Object:

public class Person {
  private String name;
  private String surname;
  private String address;
  
  // Getter/Setter methods
}

If you don’t provide any information to the Java to XML Mapping, the payload for a Web Service using the above Class could be like that:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns1:echoResponse xmlns:ns1="http://jsr181pojo.samples.jaxws.ws.quickstarts.jboss.org/">
         <return>
            <address>1260 W Edgewood Cir</address>
            <name>John</name>
            <surname>Smith</surname>
         </return>
      </ns1:echoResponse>
   </soap:Body>
</soap:Envelope>

As you can see, several characters are wasted in XML elements which you could replace with attributes. Now let’s apply attributes to the Domain Class:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)

public class Person {
 
@XmlAttribute
private String name;
@XmlAttribute
private String surname;
@XmlAttribute
private String address;

}

With the above XML bindings, the SOAP Body that will travel across the wire is the following one:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns1:echoResponse xmlns:ns1="http://jsr181pojo.samples.jaxws.ws.quickstarts.jboss.org/">
         <return xmlns:ns2="http://jsr181pojo.samples.jaxws.ws.quickstarts.jboss.org/" name="John" surname="Smith" address="1260 W Edgewood Cir" />
      </ns1:echoResponse>
   </soap:Body>
</soap:Envelope>

Web services performance tuning

As you can see, the payload is more compact as the Class fields are now attributes of the return element. In this specific example, the saving is not that big however for large domain objects the difference might be quite big.

As a rule of thumb, always check the payload of the SOAP Body and see if you can reduce the size of the domain objects attached to it.

#8: Are you using the right type of Web Service?

Unlike SOAP Web Services, RESTful web services are stateless resources that you can identify through a set of URLs.
REST as a protocol does not define any form of message envelope, while SOAP does have this standard. So, at first, you don’t have the overhead of headers and additional layers of SOAP elements on the XML payload. That’s not a big thing, even if for limited-profile devices such as PDAs and mobile phones it can make a difference.

However the real performance difference does not rely on wire speed but with the ability to cache. REST suggests using the web’s semantics instead of trying to tunnel over it via XML. Therefore, REST services are generally designed to correctly use cache headers, so they work well with the web’s standard infrastructure like caching proxies and even local browser caches.

RESTFUL web services are not a silver bullet though:

  • REST web services are a good choices when your web services are completely stateless. Since there is no formal way to describe the web services interface, it’s required that the service producer and service consumer have a mutual understanding of the context and content being passed along.
  • SOAP Web Services, on the other hand, may be appropriate when you need a formal contract that describes what the service offers. The Web Services Description Language (WSDL) describes the details such as messages, operations, bindings, and location of the web service. Another scenario where it’s mandatory to use SOAP based web services is an architecture that needs to handle asynchronous processing and invocation.

#9: Cache The Service Port

You should consider caching the instance that contains the SOAP Web service port. A web service port is an abstract set of operations supported by one or more endpoints. Its name attribute provides a unique identifier among all port types defined within the enclosing WSDL document.

In a nuthell, the Port contains an abstract view of the web service. However, acquiring a copy of it is an expensive operation. Therefore you should avoid it for every operation. Here is a sample Web Service Client which retrieves the Port object:

URL wsdlURL = new URL(endPointAddress + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
JSEBean proxy = service.getPort(JSEBean.class);

Consider, however that they are not thread-safe so access to them needs to be synchronized. The simplest way to do this is to add synchronized blocks around proxy invocations:

synchronized(proxy) {
  proxy.invokeOperation();
}

#10: Use Literal Message Encoding for Parameter Formatting

The encoded formatting of the parameters in messages creates larger messages than literal message encoding. In general, you should use literal format unless as long as your platform support it. Here’s an example of an RPC/encoded SOAP message for helloWorld

<soap:envelope>
  <soap:body>
     <helloWorld>
       <a xsi:type="xsd:string">George</a>
       <b xsi:type="xsd:string">Michael</b>
     </helloWorld>
   </soap:body>
</soap:envelope> 

Here the operation name appears in the message, so the receiver has an easy time dispatching this message to the implementation of the operation.The type encoding info (such as xsi:type=”xsd:int”) is usually just overhead which degrades throughput performance. And this is the equivalent Document/literal wrapped SOAP message :

<soap:envelope>

  <soap:body>

    <helloWorld> <a>George</a> <b>Michael</b></helloWorld>

  </soap:body>

</soap:envelope>

Conclusion

In this article we have discussed some SOAP Web Services best practices in terms of performance. It comes without saying that the last advice is to test your SOAP Web Services endpoint and the end-to-end overall performance. (In endpoint performance, a client uses a thin HTTP driver to send and receive SOAP requests while in end-to-end performance, the client driver uses a thick web services stack to send and receive SOAP requests.)

Found the article helpful? if so please follow us on Socials