The Benefits of Application Routing
Written by Gregory W. Bond   
In a recent blog post entitled "Sip Servlets Application Routing Guidelines and Best Practices," Vladimir Ralev, co-developer of the open source Red Hat Mobicents SIP servlet container, provides an insightful perspective on resource usage related to application routing in SIP servlet containers. Unfortunately, based on this analysis he concludes that architects and developers should "forget that application routing exists." However, this conclusion is not justified in the article. Furthermore, based on over a decade's experience building complex, large-scale systems that utilize application routing, our own group here at AT&T advocates the use of application routing in many circumstances. (By way of full disclosure, a member of our research group, Pamela Zave was the co-inventor of application routing, and two more members of our group, Eric Cheung and Hal Purdy, introduced application routing into the SIP Servlet 1.1 JSR 289 standard.)

Although Ralev admits that application routing is "every architect's dream" he only addresses issues related to application routing resource consumption. Issues like time to market, system reliability and maintainability are ignored in the analysis. This argument is analogous to those against the first high-level language: FORTRAN. Detractors claimed that FORTRAN utilized excessive memory and CPU but ignored its advantages: development speed, reliability and maintainability. Similarly, the modularity afforded by object-oriented languages was initially derided as being resource intensive but, again, the benefits of modularity outweighed the costs.

Application routing provides architects and developers with an abstraction. Like all abstractions, there are trade-offs involved with application routing that architects and developers should be aware of. Indeed, by choosing to utilize a SIP servlet container a developer has already chosen to add a layer of abstraction between their application and the SIP stack, thereby giving up direct control over interactions with the stack and incurring additional resource overhead in the process. The choice to utilize an application router is analogous; it is yet another abstraction between the application and the SIP stack that incurs additional resources but brings with it many benefits as well.

The Benefits

The group I work with here at AT&T routinely uses application routing in the development of both prototype systems and very large-scale production systems. Application routing permits us to develop complex, converged telecom systems very quickly by composing re-usable and customized modular telecom components. Because application routing occurs at runtime it offers design and deployment flexibility, feature interaction management, and opportunities for reuse.

Application routing is useful in the early stages of the software lifecycle to handle changing requirements, or for rapid prototyping. The benefits of reusing telecom logic should not be underestimated. Since each re-usable module is relatively small and thoroughly tested, a system composed of re-usable components is inherently more reliable than a custom-built monolithic application. Of course, composing re-usable telecom logic can be accomplished in other ways, for example, by composing re-usable ECharts state machine fragments using our ECharts for SIP Servlets (E4SS) framework. However, there is a limit to the complexity that is achievable using this latter approach, beyond which the resulting code becomes unmaintainable. (For examples of composing re-usable features to create different systems see the paper by Tom Smith referenced at the end of this article.)

Application composition and routing were designed for managing feature interactions simply by changing the order of applications in the chain. This is particularly helpful when you don't fully understand the feature interactions ahead of time, or when you may want different interactions for different customers or scenarios. Not only does modularity allow you to defer many decisions, but it also allows you to implement most decisions simply by changing routing precedence. Application composition offers flexible management of feature interaction, allowing overall service behavior to be modified by the designer or deployer and customized for different users. Using application routing, this can be achieved by including/excluding applications or by adjusting the relative ordering of applications.

When application routing is used to create a system by composing a series of relatively simple applications together, the system is inherently more maintainable than a system consisting of a single, complex, monolithic application because it is easier for maintainers to locate and fix bugs in the individual, simple applications.

The flexibility afforded by application routing translates directly into the ability to rapidly design and prototype complex systems in a way that is consistent with agile design practices. Application routing also leads to to more reliable systems and simplified maintenance.

Guidelines for Modularization

Here are some specific guidelines we use when deciding whether to implement system logic as a monolithic application or as a set of applications to be composed using application routing.
  • It is not advisable to combine applications that act for different parties into a single application. For example, a single application should not serve both the caller and callee. Similarly it is not advisable to combine applications that act for different roles for the same party. For example, a person, Jane, may have applications that serve in her role as a customer service representative, and also have applications that serve in their role as an individual i.e., as Jane herself.
  • When adding a new capability, if the new capability is general-purpose and may be re-used in other contexts, then it is a good candidate for implementation as a separate application. Re-usable applications can often be parameterized to make them even more general.
  • Each application in the call path should perform call control functions and/or observe signaling events. It can be used on its own, or can be composed into a larger service using application routing.
  • When a system calls for juggling of multiple parties or media sources then it is a good candidate for decomposition into separate modules so that each module handles a manageable number of calls in an independent fashion.
  • We have also found modularity to be quite helpful for optional features, adaptors that solve short-term integration problems, and for integrating off-the-shelf features.

(For more information about the thinking behind these guidelines take a look at the paper by Eric Cheung and Tom Smith, and the paper by Pamela Zave referenced at the end of this article.)

Addressing the Issues

In addition to ignoring the benefits of application routing, Ralev's article paints an overly bleak picture of resource utilization issues. I agree that architects and developers should be aware of these issues, but I also feel that these issues are largely addressed with existing technology. Furthermore, just as high-level languages spawned research programs in compiler optimization that greatly narrowed the gap between the performance of assembly language and high level language code, it seems that there are opportunities for container vendors and academic institutions to do the same thing for SIP servlet containers. Since all container vendors must adhere to the same standards, providing a high performance container is a way for a container vendor to differentiate their product from their competitors' products. The issues that Ralev raises should be seen as opportunities for container vendors, not as reasons to avoid using abstractions provided by the container.

Here is a list of issues raised by Ralev that I feel are addressable today or in short-order. Other issues not listed here are opportunities for future optimizations.

  • Redundant or excessively fine grained DB queries caused by partitioning of the application space. DB caching (e.g. Ehcache or Terracotta) can address this issue. Granted these require configuration effort, but with a suitable development framework, these efforts can be minimized.
  • Application router DB queries incur additional overhead. These can be mitigated using standard DB caching approaches as mentioned above. Moreover, this problem only needs to be solved once for a general purpose application router. Also, it should be recognized that for many classes of systems there is no need to for an application router to access a DB; statically provisioned routing rules are all that is necessary. The version of our DFC application router included with E4SS works this way; its configuration is specified via an XML file. The version of the DFC application router included with our Converge framework accesses a DB for its configuration.
  • Advocates development of monolithic apps using if-then-else style programming. Of course, this is an option but, just like deciding to code a routine in assembly language, this option should only be pursued when you expect to encounter resource issues. Modular programming is standard practice today and the same reasons we modularize our programming logic apply for modularizing our telecom logic.
  • Converged systems suffer from multiple HTTP entry points. One way to deal with this is to simply provide a separate web application that provides a single point of entry for the underlying multiple points of entry. Although this is simple, it can be further simplified with support from a development framework.
  • Schema sharing limits independence. Any form of composition involves dependencies between composed modules. Just consider accessing any Java system library: the developer's code is dependent on the library's interface. The goal in software engineering is to limit the dependencies. There are approaches that exist today for limiting dependencies when it is necessary to share schemas. For instance our Converge framework builds on the Grails web application development framework. In order to provide modular schema sharing we rely on Grails plugin architecture to share schemas and we use Grails services to provide an interface to those schemas if desired. (An overview of Converge and the plugin approach are provided in two presentations of mine referenced at the end of this article.)
  • A chain of dependencies breaks isolation. As mentioned above, there is always going to be some form of dependence when composing modules. Application routing allows applications in a chain to be freely re-ordered, removed or added. Although the resulting behavior for some permutations may not make sense, the fact that it is possible illustrates that application routing is a very effective mechanism for minimizing dependencies between applications.
  • Application composition is not a design pattern. Actually, it is a well established design pattern, commonly known as "pipes and filters", whose roots go back to Unix pipes in the 1970s. Application routing is an instance of pipes and filters that is able to dynamically (at run-time) construct pipes and filters graphs by linking together applications. Application routing can be used to compose individual applications or, as Ralev points out, it can be used at a coarser grained level to compose deployment units. The approach our group uses when developing a new system is to design and prototype it in terms of composed applications. We use the prototype to evaluate resource utilization. If we encounter problems with over-utilization, then we consider merging some of the applications modules together otherwise we stick with the original design since it is more reliable and maintainable.

Conclusions

In conclusion, our group here at AT&T has been using application routing for over a decade because it's allowed us to develop complex systems faster than any other way we know of. Furthermore, because we rely on re-usable applications we are more confident about their reliability then we'd be if the system had been coded from scratch. Finally, since the applications comprising a system are typically simple, the system is more maintainable then if it were a complex monolithic application. When designing a system, we use guidelines to decide how to de-compose the system into applications. While it is true that resource utilization issues can arise when using application routing, some of these issues are addressable today and the remaining issues should be viewed as an opportunity for container vendors to differentiate their products from their competitors'. Based on our experience, it is safe to say that the architect or developer who takes Ralev's advice and forgets that application routing exists puts themselves in jeopardy of developing an application that will be slow to market, potentially buggy and difficult to maintain.

(Many thanks to Eric Cheung, Tom Smith and Pamela Zave for their feedback on earlier drafts of this article.)

References

Discuss this article on the forums. (0 posts)

Last Updated ( Friday, 09 September 2011 )