Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Performance patterns for distributed components and services, Part 2

Design guidelines for web services and other remote interfaces

André Fachat (andre.fachat@de.ibm.com), IT Architect, IBM Global Services
André Fachat is an IT Architect in the J2EE community within IBM Global Services AMS in Germany. Although he still knows the machine language of his first computer by heart, his areas of expertise now include Web and J2EE application architectures, distributed computing and modeling. He holds a PhD in theoretical physics from the Technical University of Chemnitz, Germany, where he investigated stochastic optimization algorithms on parallel computers. He joined IBM in 1999 and has since conducted various project engagements, including production references. He worked for IBM in such areas as solution architecture, application development, and consulting.

Summary: 

Part 2 of this article continues the discussion on distributed designs by the means of a shopping cart example. This example is quite simple, but still powerful enough to provide important insights into good and not so good practices. It shows that keeping the communication coarse-grained by reducing the number of remote calls is a good practice. It also proposes an ID-lists pattern to combine multiple remote calls into one.

Part 1 introduced and theoretically analyzed the shopping cart example. Part 2 investigates the example from a more practical viewpoint. It discusses remote access patterns appearing in different implementations of the example use case versus separation of concerns and caching. The article concludes with general guidelines for interface designs for distributed components derived from the project experience made with the described patterns.

Date:  10 Aug 2004
Level:  Introductory

Activity:  3503 views
Comments:  

Number of calls versus separation of concerns

The theoretical base introduced in Part 1 applies to many implementation technologies. It does not matter whether the remote call invokes Enterprise JavaBeans (EJBs), web services, or JDBC providers. To keep the promise of being implementation technology-independent, I will concentrate on the structure of the remote calls, such as the input parameters, the number of calls needed to execute a use case, and so on. This is a major area where the application architect can improve the performance of a distributed application.

I will therefore investigate the structure of remote calls by looking at remote service interfaces and the (remote) components that provide them. In the sample use case of retrieving a shopping cart, you start with the EJB technology implementation and translate it into the new terminology: the Home interfaces translate to the remote Home component, providing the find services that return the objects found.

One important design guideline used in the design of components and interfaces in SOA (in fact, in any IT architecture) is separation of concerns [SoC1, SoC2]. This means that the components and services should have clearly defined, non-overlapping responsibilities.

In the example use case, this means that the ArticleHome component should not know about the CartHome component and its Cart objects and vice versa. Instead, the ArticleHome component should only know about article-specific data, and should use articleId as a key to retrieve articles.

To clarify this, look at Figure 1, which depicts the initial (Remote Entity Bean) implementation of the use case. It shows the four Home components used for the tables Cart, CartItem, Article, and ArticleDescriptions, with finder services that retrieve the objects using either the cartId or the articleId. Note that all calls starting from the client application are remote. For N items the client needs to perform 2+N*2 remote calls.


Figure 1: Initial implementation of reading the shopping cart
Figure 1: Initial implementation of reading the shopping cart

The diagram shows all calls to the different Home components needed to implement the example use case. You can see that the separation of concern rule is obeyed, as every component handles an isolated call to retrieve its related object. However, the number of remote calls is large, as each Article object and its description are retrieved separately.

After looking at the initial implementation, you can now investigate how to improve the performance by reducing the number of remote calls.

Joined-tables implementation

One common way to reduce the number of calls in such a setup is to design specific finder services in the ArticleHome and ArticleDescriptionHome components to retrieve the articles in the shopping cart and their language-specific article data. Figure 2 shows the result.


Figure 2: Shopping cart specific services in the ArticleHome and ArticleDescriptionHome components
Figure 2: Shopping cart specific services in the ArticleHome and ArticleDescriptionHome components

Note that the client only needs four remote calls for any number of items -- one to CartHome, one to CartItemHome, one to ArticleHome, and one to ArticleDescriptionHome.

This design, however, violates the separation of concerns guideline because it requires that the ArticleHome and ArticleHomeDescription implementations know about the shopping cart. They need to find out which articles actually are in the shopping cart and then read the specific information for those articles. In a monolithic system, where shopping cart and articles are stored in the same database, this is easily implemented with an SQL (or EJBQL) join between the Article and Cart tables. However, the following specific problems might arise from this approach:

  • Assume you add auctions to the system using an Auction table. In the auction, an article whose data is stored in the Article and ArticleDescription tables, is auctioned. Using the same approach, to read the auction similar to the sample use case of reading the shopping cart, you have to add services to the ArticleHome and ArticleDescriptionHome interfaces to find articles for one or more auctions. So, the Auction and Article components become dependent on each other. With each new subsystem added that needs finders in the Article subsystem, the Article subsystem becomes more complex.
  • Assume you want to use a different implementation of the Article component. This could be required when the system grows and articles stored in different systems (like the Enterprise Resource Planning (ERP) system mentioned in the sample use case) need to be read and displayed in the use case. This new system does not know about the existing shopping cart, and thus, it is difficult to implement the finder services with the cartId (or the auctionId).

ID-lists implementation

One solution that works well without increasing complexity too much is to change the finder services to accept not a single ID, but a list of IDs as input parameter. The finder services would then, in a single call, return the objects for all IDs given.

To implement the use case, the finder service retrieves all items for the cart from the CartItemHome component. Instead of retrieving each article when the item is read, the articleIds for all items are collected. Then in a single call, the article data for this set of ID values is read from the ArticleHome component. This also gives the additional opportunity to remove duplicate ID values. Also the article descriptions can be retrieved the same way from the ArticeDescriptionHome component. Figure 3 shows this scenario.


Figure 3: Optimized approach using lists of IDs as parameters
Figure 3: Optimized approach using lists of IDs as parameters

The figure shows that the same number of remote calls, namely four, is used to retrieve the entire shopping cart as in the joined-tables implementation. But this latter approach obeys the separation of concerns guideline in that it has the advantage of keeping the ArticleHome classes separate from the shopping cart classes. The components do not depend on each other, and so you can more easily replace the article implementations with a new implementation, for example.

Both approaches to reduce the number of remote calls (the joined-tables and the ID-lists implementation) can improve performance considerably by avoiding the set-up times as shown in the theory section. However, as ID-lists implementation obeys the separation of concerns, it is the preferred solution.


Wrapper services

This section investigates the application of the facade pattern [DP] to the interface design and how you can use it to save even more remote calls.

Web services involve a specific kind of remote call. Designed to be interoperable, they use XML as the transfer language, and (generally, but not always) HTTP as the transport protocol. Web services are often used to enable remote access to existing service components. Compared to other techniques, XML serialization and deserialization (marshalling and unmarshalling) is rather slow [WSA]. This means a web services call is slower than a local call to the existing component.

The following section investigates the difference between fast and slow calls with the shopping cart example. You will see that a wrapper service that works as facade to the shopping cart, taking remote requests and submitting requests to other services, can improve performance when it reduces the number of slow calls.

Assume the above use case of reading a shopping cart is implemented as a web service (the home components are wrapped in web services, while the user is using a web services client). Figure 4 shows this scenario.


Figure 4: Reading the shopping cart with two web service calls using the web service wrappers (CartService, ArticleService)
Figure 4: Reading the shopping cart

For simplicity, also assume that you have already combined the calls to retrieve Cart and CartItem into a single call to CartHome and that Article and ArticleDescriptions are retrieved through a single call to ArticleHome. The interfaces are designed similar to the ID-lists implementation above.

To implement the use case, the client first performs a remote call to CartService and retrieves the Cart and CartItem objects. It collects the article IDs from the CartItems and then performs a second remote call to ArticleService to retrieve the Article and ArticleDescription objects. As the second call requires information gathered in the first call, the two calls must be serialized (they can not be run in parallel).

You can optimize this even more by introducing a wrapper service. In the use case example, you implement a CartWrapperService that functions as a wrapper and converts the service call coming from the client to calls to the original Home components. This compound service combines the CartService and ArticleService calls presented in Figure 4 into a single remote call. Figure 5 presents this setup.


Figure 5: Reading the shopping cart with a CartWrapperService that calls the original implementation
Figure 5: Reading the shopping cart

The figure shows that now there is only one remote call to the CartWrapperService while all other calls are local calls from the facade to the service implementation.

Important is the fact that although the number of local calls (from the CartWrapperService to CartHome and ArticleHome) is not reduced, this interface design saves network latency and transport times for the response of the first remote call and the request of the second remote call.

Although it seems not to address separation of concerns when combining CartService and ArticleService, in fact it does. The original services can still be used independently and have separate concerns. The CartWrapperService component has its own concern -- combining all services to a complete shopping cart (for example, it could also include calls to a pricing service).

In this section, you have seen that moving complexity (combining the calls) from the client to the server helps reduce the number of remote calls. Using this qualitative argumentation, you can see that this coarse-grained communication approach can improve performance compared to a more fine-grained approach.


Number of calls versus caching

When you need to reduce the number of calls further, you can employ caching techniques where applicable in the calling application. Without going into the details of caching service call results, I will give you a negative example from project experience, so you can avoid the described pitfall. In this example, caching was used to overly reduce the number of remote calls, but this approach also resulted in a performance degradation, not improvement. This shows that you must employ caching with care.

In the sample use case, this article has so far only vaguely described the finder for the article descriptions (getArticleDescriptions()) at the ArticleDescriptionHome component. Assume that the article descriptions are language dependent, so they have to be kept in a table separate from the Article table. In other words, for each article there may be more than one description in the ArticleDescription table, one for each language supported (see Figure 1 in Part 1).

The client that calls the service for the use case is now assumed to be a Web-based store application that displays the cart to a user. On the user interface the user can select which language to use. To reduce the number of calls to the ArticleHome component, when a page is read, all descriptions in all languages for the article are read and cached in the calling application. So when the user changes the language, it can automatically be retrieved from the cache, without doing a remote call to the back end.

This approach works for a while. However, when the store goes from three to more than ten supported languages, it becomes unbearable. The time for the initial remote call (retrieving all languages) grows, as does the memory requirements for the cache. Finally, the page is not displayed due to time-out problems in the remote call caused by the excessive amount of data to be transferred.

What happens? The design trades the number of calls for the amount of data transferred. The number of calls is reduced, but each call in itself retrieves a lot of data that is never used. Who will read a catalog in all those languages? So the overall performance is reduced by the additional computation, which could have been avoided by simply retrieving only the descriptions in the language that the user had currently selected.

This section showed that in relation to caching, you should not extend the interfaces to retrieve data that is not needed just to fill the cache. Instead, you should keep the interface small and lean to keep the amount of data to transfer as small as possible, thus reducing the transfer time [JDBCPerf].


Best Practices

This article investigated aspects of interface design for remote services in theory and analyzed some common examples. From this, you can derive generic guidelines for designing distributed components and service interfaces in an SOA context:

  • Keep in mind that almost any interface may at some time become distributed. You should especially design interfaces between layers or domains with this in mind, while layer- or domain-internal interfaces might not require this level of attention. Interfaces should, however, be marked as to whether they are designed for remote access or not.
  • Keep separation of concerns by separating the interfaces from each other. For example, an interface to retrieve article data does not need to know about shopping carts. This allows for easier reuse of the service in new contexts.
  • For retrieving item information, always think about lists of IDs or key values as input, not single IDs or key values. Once the interface goes remote, this allows for improved performance by letting you group requests together (as in the ID-lists implementation example).
  • Keep the communication coarse-grained. Any communication path saved is normally an improvement (but keep the data size in mind). In some cases, a wrapper on the remote side might improve performance by encapsulating multiple calls on the remote end into a single remote call.
  • Think about the data size transferred, and do not retrieve data that is not needed at a specific time, such as when:
    • the chance that you'll need it is small and you cannot foresee needing it in the future (for example, change of user language for language-specific data), and
    • it can easily be retrieved by another remote call in case it is then needed.
  • Keep your eyes open. Your mileage may vary, so always verify that following the guidelines leads to acceptable results in your specific situation.

Conclusion

Developers often seek performance improvements in the "infrastructure" of an application, like keeping the set-up time low through database connection caching, parallelizing calls, preparing XML parsers or serializers before the actual call, and much more. This article, however, shows that these might not be enough to ensure a well-performing application.

This article investigated interface designs for remote components and services. The theory section in Part 1 showed the different steps of a remote call with the conclusion that reducing the number of remote calls is a main way to improve performance. Part 2 introduced the ID-lists pattern to reduce the number of remote calls and still obey the separation of concerns pattern. Wrapper services on the remote side of the call are another way to reduce the number of remote calls. The caching example showed that reducing the number of calls must be carefully employed. Finally, a set of guidelines for the design of remote interfaces was given.

The discussion illustrated that the interface design has a large influence on the performance. A well-designed interface can greatly reduce the number of remote calls and thus execution time. The remote interfaces should be carefully designed according to the guidelines presented. Nevertheless, the design changes to improve performance have to be carefully monitored to ensure that the right design decisions have been taken.

Of course, good interface design does not guarantee that the application performs well, but it is needed in addition to the usual infrastructural measures.


Acknowledgements

Thanks to Stefan Peuser, Olaf Zimmermann, Witold Szczeponik and Frank Müller for providing invaluable input and reviewing this article.


Resources

About the author

André Fachat is an IT Architect in the J2EE community within IBM Global Services AMS in Germany. Although he still knows the machine language of his first computer by heart, his areas of expertise now include Web and J2EE application architectures, distributed computing and modeling. He holds a PhD in theoretical physics from the Technical University of Chemnitz, Germany, where he investigated stochastic optimization algorithms on parallel computers. He joined IBM in 1999 and has since conducted various project engagements, including production references. He worked for IBM in such areas as solution architecture, application development, and consulting.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=15050
ArticleTitle=Performance patterns for distributed components and services, Part 2
publish-date=08102004
author1-email=andre.fachat@de.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers