Industrie IT

We mean business

Company news

A Practical Guide to Extending Continuous Integration to Continuous Delivery

Introduction


I am assuming that because you are reading this blog you are familiar with the concept of Continuous Delivery and are already a supporter of the concept. If not, close your eyes for a moment and imagine a software system that has a bug (I know this is a bit hard to imagine). Now imagine a developer fixing that bug, completing his unit testing and checking the code back into source control. Now count to 10 and the code has been deployed to production and the bug has been fixed. This is the Nirvana and goal of Continuous Delivery. I have found that from a technology stand-point this is now a relatively easy thing to achieve for applications with small to medium levels of complexity written in ‘friendly’ technologies. However, expanding this concept to complex applications in enterprise environment becomes more difficult but in my opinion still achievable.

So why do so few people seem to be doing it?

For the past few years I have been trying to answer this question and apply Continuous Delivery concepts to complex systems in enterprise organisations. Some of the challenges faced include:

  • Unfriendly technologies – this includes custom vendor programming languages and tools that do not immediately lend themselves to automated builds and deployments (Datastage and Webmethods are examples that spring to mind in this category).
  • Multiple External Interfaces – Systems that interact and rely on multiple external interfaces for data and processing.
  • Data – Systems that are heavily reliant on large volumes and synchronisation of data.
  • Old technologies – Systems where there are legacy components (this is almost always the case).
  • Team structures + Politics – One of the most challenging and slowest areas to combat and which can sink many good technology initiatives if not navigated correctly.
  • Budgets – The ever present reality of money. It is important to understand that the goal of Continuous Delivery is to provide efficiencies and save money. This must always be kept in mind and any efforts assessed against this goal i.e. is there value add.
  • Competing projects/priorities – The ever present reality of delivery. Continuous Delivery will assist with this and needs to be applied so that it is not seen as something delaying things.

I believe these and many more are just challenges and can be overcome. I am confident that one day this style of delivery will become the ‘norm’ in software development, potentially not fully automated all the way to production but at least to a test environment. What I aim to provide in this blog is a practical guide on how to make the next step from Continuous Integration to Continuous Delivery. It is a process I have used successfully and that I hope you will find useful. This guide assumes you have an established Continuous Integration process for your development practices. If not have a quick browse of http://jamesshore.com/Blog/Continuous-Integration-on-a-Dollar-a-Day.html.

Continuous Delivery

Most development teams now appear to have established some level of Continuous Integration but are either unwilling or are have trouble moving to Continuous Delivery. One of the key underlying reasons why this transition is difficult is because Continuous Delivery covers three main practices;  Continuous Integration, Automated Deployment and Automated Testing. These practices generally span multiple teams across the software development life-cycle. Organising people can be difficult, organising teams in an enterprise environment is even harder.

If you look at Continuous Delivery from an engineering perspective there are 4 main components (1 covering each of the practices and 1 for choreography and reporting):

  • Continuous Build/Integration –automated building of your application on check-in and execution of unit tests.
  • Automated Deployment –automated deployment of your build artifacts and environment config.
  • Automated Testing – automated acceptance/system testing of your application.
  • Pipeline Choreography + Reporting – something to tie the above three areas together and to provide status reporting.


Continuous Delivery – Components

To implement Continuous Delivery you will need to have some sort of technical solutions and tools in each of these areas.

More on each of these components later, for now lets go through the set of steps that can hopefully be used to help with the transition from Continuous Integration to Continuous Delivery.

Step 1 – Setup another development environment

If another development environment is not practical you can get away with nightly builds in a shared development environment but I strongly encourage you look at establishing a separate environment. Suitable names I have seen in the past for this environment include the assembly, dev staging or dev test environment.

This additional environment provides you with a location to:

  • test your continuous delivery process;
  • test your automated deployment process; and
  • run your automated integration and acceptance/system tests.

Ownership of this environment should initially be limited to a single team. It is important to contain the Continuous Delivery initiative to one team for the moment to avoid being dragged into any potential politics at this stage. It is important to note that this environment does not need to be, nor should be a full scale production like environment. In fact there are some key things about this environment that will need to be established. This may involve significant effort for some applications but the key is to start small providing as much value as possible early on and then to incrementally build.

More on this in step 4, for the moment I will simple list the key elements about this environment:

  • External interfaces should be stubbed – You do not want to be reliant on external systems for your tests. This causes unreliable results and the environment and tests will become a pain to maintain.
  • Cut-down static data – You need to control your data scenarios. Having random data will result in maintenance issues for your tests. Similarly you want a small data set to ensure efficient, quick turn-around times.

For now don’t worry about implementing a stub for every external interface and generating static data for every data scenario, just get an environment up and running which is fairly usable i.e. you can execute at least one use case on it. Remember, we want to add value quickly and incrementally.

Step 2 – Automate the deployment to this environment

The ease with which you be able to manage this step really depends on your maturity in the automated deployment space. However, if you don’t have an automated deployment framework don’t fear. For starters this can be a set of Bash, Ksh, Ant, DOS scripts <insert favourite> and some SSH keys to communicate between servers. Moving forward you can look at tools specifically designed for this purpose such as such as Control Tier, Chef, Run Deck, <insert favourite>… I feel it is important to separate your build and deployment processes. Some items you will need to consider during this step are:

  • Environment Variable – How does your application handle application properties vs environment properties.
  • Build Artifacts – where do you store your build artifacts

Jump to the step by step example of achieving this with Nexus, Tomcat, SSH and some simple shell scripts.

Step 3 – Integrate your Continuous Integration with your automated deployment

This step starts to tie together the underlying disciplines to form a Continuous Delivery framework. The aim here is extract the artifact built from your Continuous Integration and automatically deploy this into your new development environment after each code check in (with no manual steps required!). At the very basic level this can be achieved with a simple script with ties together the two components. I do however recommend that you look at a tool at this point to assist with the coordination and reporting. Using a tool will normally provide you with a nice interface and a history of build activity as well as a variety of notification mechanisms (email etc.) and security overlay. Make sure your tool is capable of filling your requirements in steps 4+5. I am most familiar and partial to the Atlassian suite so have provided the step-by-step demo using Bamboo but have a look around at what else there is available.

Jump to the step by step of how to achieve this step with Bamboo.

Step 4 – Automate your acceptance tests

First let me begin with a brief definition of the categories of testing:

  • Unit: jUnit, testNG, easyB, that is what TDD and BDD is all about.
  • Component: that’s where you want to use a spy/mocking framework: mockito, easyMock, rMock, jMock to test components in isolation, validating business rules.
  • Integration: testing that components interact together correctly, using your favourite IoC (Spring, CDI, seam, etc.) and mocking framework, SoapUI can also be used, we are more interested in data and logic flows rather than business rules.
  • System/Acceptance: the ultimate integration test, making sure all components are working together, using the GUI so you need something like selenium for browser based testing or QTP for native apps.

A useful diagram worth considering is the “test automation pyramid” taken from “The Clean Coder: A Code of Conduct for Professional Programmers” (R. Martin 2011) which gives an indication of what level of code coverage we should be targeting for each test category.

During this step we are not talking about the automation of unit tests. We are looking at some level of testing between component and system/acceptance testing depending on your application. My recommendation is to start with one simple system/acceptance test. Start with the obvious ones – i.e. 80% of usage. At this point you will need to start building out any mechanisms for controlling the data (if required) and stubbing out external interfaces. I won’t go into the details here of the variety methods that can be used to achieve this but I will mention this. Most developers when I talk to them about static data and stubbed interfaces immediately baulk at the effort that would be required to implement such a feat of programming wizardry. If you are thinking like this now I need to highlight at this point it is not as hard as you think it may be. I ask that you set aside a couple of hours, have a quick browse online about the various approaches and then sit down and figure out how you could achieve it for your application and your one test case that you are trying to write. Don’t try to boil the ocean here. Add value incrementally and ingrain the practices in your team and you will be amazed at the momentum that it creates once the framework is established.

The tools you use to test will depend on what type of testing you are planning on executing for your application, but for the purposes of this blog I will assume it is a web service under test and will use SoapUI as the tool of choice. One of the reason for choosing SoapUI as the tool is that it produces a nice JUnit style test output which integrates nicely with Bamboo in Step 5. Again I need to highlight that there are many tools out there that may be better suited to your needs so have a look around. I will also point out that everything is testable in an automated fashion, it really is just a question of difficulty (aka cost) versus value. Always look for the most cost effective manner to execute your tests. As a general rule this is normally at the unit test level. In some application it may not be possible to adequately perform units tests and so you may need to rely more heavily on integration/system tests (especially true when you are dealing with what I would refer to as difficult technologies). As an example, consider a system which delivers data via a webservice to a desktop application which then renders this data to PDF for users. To test at the PDF layer would be difficult and costly. Take a moment to consider where the majority of risk is, surely it is the data? In this example it then makes sense to push more of your testing down to the Web Service layer as it easy to implement and resolves the risk i.e. it adds value quickly and efficiently.

Always keep this in mind throughout the process. Some questions to ask yourself:

  • Is this the best point to write my test?
  • Can I test to the same outcome in a more efficient manner?
  • Are there any alternative testing points that can be introduced to the system?

Jump to step by step of how to achieve this with SoapUI

Step 5 – Integrate your automated test into your build pipeline

This is the last step before you have a working POC for Continuous Delivery, the subsequent steps are about maturing and socialising your work. The integration of your test suite into your build pipeline is critical as it helps cement the practices into your development process. All the same reason and arguments that apply for Continuous Integration and unit tests apply here i.e. fast feedback, always having a working build etc. With your Continuous Integration process you should already have your unit test integrated into your build process. This is about extending the same concepts of Continuous Integration to your system/acceptance test suite and new development environment.

How you integrate will be dependent on the tools you are using but some key features you will want are:

  • Notifications of failed tests (Email, IM, Build Lights <insert favourite>)
  • History of test results and when / why they have broken

Jump to step by step of how to achieve this with Bamboo, Maven and SoapUI

Step 6 – Expand your test suite

Ok by this step you should be able to check some code in and the following should automatically happen:

  • Your application is built;
  • Your application is deployed to your new dev environment; and
  • Your integration/acceptance test is run against your application.

You should be able to sit back smugly with your coffee and watch this all happen through your Continuous Delivery reporting tool.

Congratulations!

This step is now easy, expand out your system/acceptance test suite. Remember add value quickly and efficiently and ensure you are applying the most effective tests at the correct point in your application.

Step 7 – Go demo and talk to other teams

This can actually be one of the more difficult steps as it involves dealing with people, teams and office politics. This is why I have tried to defer this step until we have a working, solid version of Continuous Delivery which is adding real value to the business. Continuous Delivery and some of its concepts are rapidly gaining exposure but are still relatively new concepts. Many people outside of the development space will not see this concept as anything different that the 3 underlying practices; Continuous Integration, Automated Deployment and Automated Testing. Others will not see the value and see it as a ‘developers thing’. It is important to understand that Continuous Delivery spans more than just the development space and when executed correctly transitions all elements of software delivery. Now is the moment when you will need to start your road show and tackle any of these issues that arise. At this point your best tool would probably be a book on psychology, but some advice from experience is:

  • Keep an Open Mind – people are resistance for a reason, try to understand the reasons behind their views. They may have been burnt by an automated testing project previously. They may be afraid they will no longer be required.
  • Preach Value Add not Continuous Delivery – Always focus on providing value and return on investment in a timely manner. Avoid situations that result in a long turn-around prior to real value being added to the business. Don’t get lost or overly obsessed with terminology. It is great to talk in a common language but the important thing is to implement the process, what it is called is secondary.
  • Find your Supporters – identify your supporters and leverage them. Don’t try to go it alone, identify people who are supportive of the benefits and understand the final end-state you are trying to achieve. In many cases you are changing the delivery culture. Changing a culture is difficult, acknowledge it and deal with it appropriately .
  • Don’t get attached to Tools – During the journey to implement Continuous Delivery into your development practice you may need to tweak technologies and tools you have used. Do not become overly attached to the tools you have used in the above steps. Whenever you get involved in a discussion about tools just ensure you have your requirements ready i.e. integrates with Continuous Delivery reporting tool etc. and then evaluate each tool against these requirements. The process is paramount, the tools are secondary and there to assist the process.
  • Work within existing structures – The question of the ownership about certain sections of the process will come up and will need to be resolved. Who writes the automated tests? Who manages the static data? No magic answers here and it depends on your organisation structure and skill sets in each of the teams. Just work through the advantages and disadvantages at each point and ensure the decisions make sense. Personally I am in favour of pushing as much as possible into the developers realm of responsibility as it makes sense that developers are responsible for the quality of work they produce. However, in larger more complex systems it may make sense to leverage other teams more.
  • Work from a Basis of Proof– As an example to illustrate what I mean here consider the following. Imagine all deployments to the test environment are manually approved and only to occur over defined windows. Don’t insist that all deployments to the test environment must be automated. Use the additional development environment to perform your automated deployments and tests and stick with the manual process to test. Once confidence has been built up that the deployments to the test environment are seen to be of high quality then the manual deployment process to test can be discussed.

It is best to prove the system works and then start discussing some traditional entrenched processes. Hope you have found this blog useful, if so please drop me a note and let me know.

Cheers Brendan

Step-by-Step Guides

Step-by-Step – Automate Deployments using Nexus, Tomcat and some simple Shell scripts


Note: This is a simple and brutal method to deploy a war artifact to a tomcat container. It is designed to show that automated deployment can be achieved easily. The process can be improved in many ways.

1. Extract the artifact from Nexus

OUTPUT_PATH=/myoutputpath/
NEXUS_REPO=http://mynexus
NEXUS_ID=snapshot
ARTIFACT_GROUP=industrieit.com
ARTIFACT_ID=continuous-delivery-app
ARTIFACT_VERSION=1.0-SNAPSHOT
ARTIFACT_PACKAGING=war

cd $OUTPUT_PATH;
wget $NEXUS_REPO/service/local/artifact/maven/redirect?g=$ARTIFACT_GROUP\&a=$ARTIFACT_ID\&v=$ARTIFACT_VERSION\&r=$NEXUS_ID\&p=$ARTIFACT_PACKAGING

2. Stop Tomcat

TOMCAT_HOME=/mytomcathome/

$TOMCAT_HOME/bin/shutdown.sh
while [ `ps -ef --sort=pid | grep "catalina.home=$TOMCAT_HOME" | grep -v "grep" | awk '{ print $2}'` ]; do
sleep 1;
done

3. Deploy Artifact

mv $OUTPUT_PATH/$ARTIFACT_ID*.war $TOMCAT_HOME/webapps/$ARTIFACT_ID.war

4. Start Tomcat

$TOMCAT_HOME/bin/startup.sh

This can be expanded to extract and set particular config variable if required. Again I suggest that you have a look at the available tools such as Control Tier, Chef, Run Deck, <insert favourite>… to support automated deployments before expanding too far.

Step-by-Step – Bamboo Integration of your Automated Build and your Automated Deployment


Note: Again this is designed to show a low effort way to integrate. The process can be improved in many ways.

1. Setup SSH key between bamboo agent and deploy server – If you are not sure how to do this see http://linuxproblem.org/art_9.html

2. Write a simple ssh wrapper script and check it into your source repository. This will be used to call your automated deployment script.

remoteServer=$1
cmd=$2

ssh ${remoteServer} ${cmd}

3. Make the wrapper script executable in source control – see here if you are using SVN http://www.mernin.com/blog/2008/02/making-scripts-executable-inside-subversion/

4. Configure a bamboo job to call the wrapper script after your build has been produced

  • Set source repository to point to where your wrapper script is located
  • Configure a Bash builder (see screenshot below) to call your ssh wrapper with appropriate server details and command to execute.


Step-by-Step – Automate your acceptance tests with Soap UI

1. Create a SoapUI project – http://www.soapui.org/Getting-Started/your-first-soapui-project.html

2. Create any necessary static data and stubs required for your test. Remember only focus on the single test for the moment.

3. Write an automated test – http://www.soapui.org/Functional-Testing/functional-testing.html

Step-by-Step – Bamboo integration of your SoapUI test suite with Maven



1. Check in your Soap UI project to a source repository

2. Create a Maven POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>com.industrieit</groupId>
<artifactId>continuous-delivery-demo-service-test</artifactId>
<packaging>jar</packaging>
<version>0.0.0-SNAPSHOT</version>
<name>Continuous Delivery Demo - Service Test</name>
<description />

<build>
  <plugins>
    <plugin>
      <groupId>eviware</groupId>
      <artifactId>maven-soapui-plugin</artifactId>
      <version>3.5.1</version>
      <configuration>
        <projectFile>src/test/resources/soapui-project.xml</projectFile>
        <endpoint>${endpoint}</endpoint>
        <junitReport>true</junitReport>
        <outputFolder>${basedir}/target/surefire-reports</outputFolder>
      </configuration>
    </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-install-plugin</artifactId>
    <version>2.3.1</version>
   </plugin>
  </plugins>
</build>
<properties>
  <endpoint>http://yourserver/yourwsdl.wsdl</endpoint>
</properties>
</project>

3. Configure a bamboo job to perform Maven build to execute the tests

  • Set source repository to point to where your SoapUI project is located
  • Configure a Maven builder (see screenshot below) to call maven goal “clean eviware:maven-soapui-plugin:test”
  • Ensure that the build is listed as producing test results
  • List the location of test results as “**/target/surefire-reports/*.xml”

The views expressed on this blog are those of the author and do not necessarily reflect the views of Industrie IT. 
Posted in Methodology, Technical | Tagged , , , , , , , , | Comments Off

Stateless JSF – high performance, zero per request memory overhead

UPDATE (10DEC11) – BETA 4 RELEASED… click here

UPDATE (07DEC11) – BETA 3 RELEASED : sub-millisecond non-render GET overhead, JSTL support, adaptive pools… click here

UPDATE – BETA 2 RELEASED… click here

The tables below provide summary results for the stateless JSF implementation discussed below.

Requests per second
 

STATEFUL JSF STATELESS JSF SPEEDUP
Hello World 2050 req / sec 2158 req / sec +5%
Small view 1000 req / sec 1850 req / sec +85%
Large view 20 req / sec 750 req / sec +3750%


Overhead – framework time outside Component.render();

STATEFUL JSF STATELESS JSF SPEEDUP
Small view <1 millisecond
Large view <1 millisecond >3,000%

 

NOTE: Since writing the article we have noticed our load test times were being adversely affected by the realtime graph listener in JMeter. Actual performance is significantly better than stated in the article. The small view sample page for example renders stateless not at 26,500 rpm but 110,000 requests per minute (large view 45,000 rpm). Stateful JSF also does better on the small views, though no better on the large

Browser side latency improvement – large view

Introduction

Now that no one company dominates the browser space, some pretty impressive browser implementations (both in render speed and javascript performance) are available, and standardisation is becoming quite complete. These facts will result in a movement of normal website development further to the client side. It’s already happening at a rapid rate.

Yes, component oriented development will be the major pattern for web development. But the ‘components’ are going to be objects sitting on the client browser, written in JavaScript. The sweet spot for full blown JSF has therefore, IMHO, passed. The idea of requiring server interaction for most DOM changes is already starting to seem like it came from another age. Will there actually be any server-centric web framework in common use for new business web apps in the not too distant future?

However, corporate environments always have a legacy base of software preventing rapid change. Many of you have an existing investment in JSF or desire to remain with the JEE standard. We need to provide a mechanism where JSF can be used as a lightweight compositing mechanism, with very low CPU and memory overhead if desired, in order to transition to a more client side approach to web development.

It is reasonable to expect the performance of page rendering to be mostly dependent on the amount of mark-up rendered (aside from time spent outside the framework like in database calls). Currently this is not the case with JSF. Page performance is largely related to the size of the view tree, regardless of whether the vast bulk of it is excluded from render due to being in non rendered branches.

This fact is the reason why many JSF apps seem so sluggish – even when they are rendering what appear to be simple pages.

JSF users, at this point, will start paring back page complexity by putting sections in multiple pages where not really warranted, seeking to minimise the view size. You could also do things like use JSTL c:if tags to trim whole branches from the view. However, you can get side effects. For example, using c:if to initially exclude a composite component from a page prevents any associated resource references from being included in the html head. This then causes issues on subsequent partial ajax rendering if and when the component is displayed. That’s why JSTL is generally discouraged from facelet based templates. If you do not use it, however, the view grows quickly.

The whole point of component based development though is to be able to handle more complex pages. In this sense, JSF as-is has fallen short of its goals. You don’t have to push the limits much to get less than stellar performance.

So what can we do to make JSF zippier?

The fundamental question is:

DO WE REALLY NEED A FULLY MUTABLE VIEW?

If not we can gain considerable performance advantages. In my experience it’s not commonly used, or is better done in the client, and for these reasons the costs of fully supporting it as things stand are too great.

Introducing Stateless JSF

Those familiar with the way the Tapestry framework operates will have an idea of where we are going with this.

Processing the mutable view structure in JSF (whether originally INTENDED or not) is IN PRACTICE a heavyweight operation for non trivial views. There seems to be an ongoing debate regarding this. Having used JSF for many projects, this has, for me, been settled.

With this in mind – rather than constantly recreating the views, we are going to pool and re-use them for other requests.

For this you will pay the price of:

  •  * You can’t (or shouldn’t) create the view dependant on any data that changes with respect to each request (normally easy if you don’t use JSTL).
  •  * You can’t (or shouldn’t) mutate the view after it’s created.
  • * All persistent component state should be flushed to backing beans (you are most probably doing this anyway).

I say “you shouldn’t”  because in the current implementation the altered  view is put back in the pool as-is. If you do not respect the restriction, the pooled views will diverge in structure and you will start to get differing behaviour for each request. We could enforce this with a hash check and flag an error if a mutated view is returned to the cache, but this will suffice initially.

On the upside – views though static can be as complex as you want with very little performance penalty. Rather than changing the view in time, ramp up complexity by putting in many branches that are conditionally rendered.

An Overview of the Implementation

One plus in our solution is that we ARE NOT changing any core implementation classes. We are simply making use of the ‘plugability’ and extensibility of JSF (something they did get right), by slightly (or majorly!) overriding the state manager, the view handler, and the view language factory. These can all be cleanly overridden by adding entries to the faces-config.xml file to provide alternate implementations.

We will not, therefore, need to provide custom implementation jars at all. We will be using the default JSF 2.1.3 Mojarra release jars. Note that although we provide alternate implementations of these components, we are overriding the existing implementation classes, so it’s not guaranteed you can move the classes to a different version of Mojarra, and certainly not MyFaces. Porting should not be difficult however.

I have also taken care to allow an incremental changeover. Individual pages can be marked as running in stateless mode. The remainder will operate exactly as they do now.

Here are the changes that are required to be made to run stateless:

  1. * in the view definition language factory, we will return a subclass of the FaceletViewHandlingStrategy  that only runs buildView() ONCE. We do this by placing a marker on the ViewRoot to indicate we’ve already built the view.
  2. * override the state manager to NOT store any per view state (huh? We’ll get to that)
  3. * override the view manager to pool and re-use UIViewRoot components.
  4. * provide a phase listener to return the view to the pool after render. Note that the pool manager will enforce a minimal time in the pool before supplying to a new request. This is because the post render event is not the end of JSF processing and we must ensure there is no overlap between requests.

When we do this, we are forced to accept some restrictions compared to stateful JSF.

  •  * make sure the view is created without regard to any data that varies between requests. This is normally easy to do if you steer clear of using jstl tags.
  • * be careful with JSTL tags (particularly c:if). Views are only built once, so if a c:if test initially returns false, it will never appear in any view. This is unlike normal behaviour where buildView continuously tests the conditional and inserts/trims the view as needed. c:if tags can be used to prune the UIViewRoot tree at build time  to reduce the latency of buildView and minimise the viewstate. However, now that we are caching the view, page performance is not affected by buildView. Make the pages as complex as required for the function and exclude as needed with simple conditionally rendered fragments. Do not prematurely optimise – you will be surprised how much you can pack into the view compared to stateful mode.
  • * The addToView event can’t be relied upon – its only called once on initial creation and not every time we are re-using the view
  • * It is normally possible (though not common) to work with JSF directly against the UIComponent objects in the view heirarchy, and have the state retained across requests without binding to a backing bean. Since we are not retaining any per view state this is no longer possible.
  • * Some other features I don’t use and haven’t tested for may not work (let us know).

Before being returned back into the available pool, the component tree is traversed, resetting all UIInput components. This is obviously to ensure that a field submitted from user 1 is not displayed to a different user 2 when the view is later retrieved from the view cache and re-used. A non-initialised UIInput sets itself from the backing bean – which is exactly the behaviour we need. However, state that is not flushed through to backing beans or returned to the server for later submission due to validation failure is lost. You can think of this as ultra-thin split client/server side state saving (client side on validation failure, server side on success)

A word of caution. DO NOT just plug these classes into your app without having a good understanding of the JSF lifecycle, the persistent state of your custom components, and your particular circumstances. To overcome deficiencies in previous versions of JSF, or to achieve some particular behaviour, components have been developed that either mutate the component tree and/or store some sort of hidden state in the tree. Now I don’t use any of them, but if you do, the data will be retained in the view pool, possibly to be later used in the request cycle of a different user, and in the worst case this will be used to render markup and COMPROMISE CONFIDENTIAL USER data to others.

The only data expected to be flushed as temporary state through the view during a cycle (that needs to be cleaned up) is assumed to be components derived from UIInput. This includes the form fields. Any custom component you are using (and possibly some from the common JSF component libraries) that stores state into the view may be problematic in this regard. CHECK!!!

JSF State

The concept of what exactly is ‘STATE’ in JSF is also confusing. In a fully mutable view we must record the structure of the tree, as well as any persistent state related to each of the components in the tree.

If the tree structure does not change, the tree structure is by and large stateless. If you mandate all form data must be bound to backing beans, you don’t need to store the fields of this stateless tree either.

Indeed, the frustrating thing about all this JSF state saving is that if you don’t manipulate the tree structure (more common than not in my experience), all your views are exactly the same, and the UIComponent values may actually all be replicated in your backing beans.

Things like el expressions are just late bound string literals evaluated at a later time, but their representation in the tree is a simple string. The dynamic behaviour in this regard is conferred by having different backing beans presented to the view at different times (controlled via scope).

Now, data submitted from form values is, during the JSF lifecycle, stored in the view and processed. The UIViewRoot is not threadsafe, and that is why we must pool them and ensure they are not used in two different cycles at the same time.

However the state in the viewroot only exists during the actual request cycle. Any form data is bound into the tree at phase 2 of the JSF cycle. If it fails validation, it’s sent back to the client browser to be rendered as form fields again (our client side state). If it validates it is flushed through to a backing bean which, if appropriately scoped is retained across requests (our server side state, if you will).

So if any input values in the tree have already been replicated somewhere else and the tree doesn’t change. Is it REALLY necessary to persist ANY per view state? From what i can see, no (correct me if i am mistaken)

The advantage of this pooled view approach is that the actual views are cached, you only need as many to handle the maximum CONCURRENT requests, and they belong to the entire application. State flows through these pooled views temporarily during the JSF lifecycle, and end up either being sent back to the client or flushed through to your backing beans.

At this point the view can be reset and sent back to the free pool to be reused.

In the event that all of your backing beans for a view remain request or application scoped, you can run a JSF site for which there is no incremental persistent per request or per user retained state on the server, AND you forego continuous per-request CPU hit of the buildView part of the render phase, which can be significant (we’ll see how much shortly).

You will in this case, in the steady state, achieve scaling along the lines of what you’d expect from a simple front controller based framework like struts. This is definitely NOT the case with JSF out of the box, and severely limits its use.

With that said, let’s have a look at performance gains using our stateless changes.

I’m going to make a simple page and ramp up its complexity using the jstl c:forEach tag. As previously mentioned JSTL tags are applied at build time to affect behaviour during construction of the view tree. Foreach will actually create multiple UIComponent siblings and place them as children within the parent component. This is in contrast to the facelet ui:repeat which creates one component (uirepeat, funnily enough), and does request time iteration (and ‘smart’ fast forwarding on postback) to render the same component with different attributes.

One bug I have found is that calling buildView on a viewRoot is not idempotent. I find that the composite components don’t hold their place in the child list. They get moved to the end and therefore render in the wrong place on the page. If you hack around with the code and find this happening, you are calling buildView on a pooled viewroot. If you create a view and build it fine. If you build it any more than once, the composite components get re-arranged.

Performance Results

Testing was done on a Core2 laptop, Windows NT, Apache Tomcat 7.10, JDK 7u1, default settings. Incidentally – the escape analysis based optimisations  in Java 7 (lock elision and scalar replacement) can confer very impressive performance gains.

I’m going to break the testing into two separate tests to illustrate the two advantages gained by our stateless model – CPU (single user)  and memory (multi-user).

In the first case I will saturate the server from JMeter, retaining the session cookie, to gauge straight out speed without worrying about memory overload (only one user session will be created).

Single User

A simple page with a facelet included, a composite component, and a small number of inputs. In other words, a trivial site not comparable to any real site. A page such as you would find in a JSF tutorial.

STANDARD JSF 2.1.3, SIMPLE PAGE, 1 USER:

Ok so trivial page, single user, we get around 11,000 pages per minute after giving hotspot a chance to do its thing (18 milliseconds per request).

Now let’s try our stateless model under the same conditions:

STATELESS JSF 2.1.3, SIMPLE PAGE, 1 USER:

Ok stateless we top out at around 26,500 requests per minute (A 135 percent increase over standard.

Now if you left it at that you’d think it’s an improvement but not a major issue –even 11,000 requests per minute is more than enough to satisfy most throughput requirements.

You would, however, be grossly MISTAKEN.

Intuitively you would feel page time is mostly related to the complexity of the rendered output. This does not appear to be correct – in current implementations of Mojarra its more related to the complexity of the view, regardless of whether it’s all rendered or not. This is the thing that trips up those new to JSF.

To highlight my point, let’s increase the complexity and size of the view, while at the same time rendering exactly the SAME MARKUP. We do this via a jstl c:forEach iterator inside a non rendered fragment. C:forEach is a build time tag that will cause real individual UIComponent siblings to be created and placed into the view. In this example we are inserting 1000 panelGroups into a hidden fragment.

STANDARD JSF 2.1.3, COMPLEX PAGE, 1 USER:

WHOA!!! What’s happening here??? We are rendering EXACTLY the same markup, but the site has slowed to a crawl (an increase in render time of 1200%) to a quarter of a second.

What is happening is the buildView portion of the cycle is FAR eclipsing the actual rendering .

Buildview seems to be an integral part of the render cycle, regardless of request type (GET, postback etc).

Let’s try the same page with our stateless changes:

STATELESS JSF 2.1.3, COMPLEX PAGE, 1 USER:

You read that right – on the more complex view (though rendering the same output) we’re still levelling off at 16,500 requests per minute (median 10 milliseconds, 20 times more throughput than the default stateful mode).

NOW – tell me – which of the two scenarios do the pages from your complex website more closely resemble (simple or complex view)? It’s not difficult to assemble even more complex aggregate views, and watch as one page request monopolises a good fraction of a second of a fast CPU’s horsepower.

Multi-user

Finally – I’m going to try the absolute worst case scenario for standard JSF – a server saturated from unrelated requests, against a complex page. I’ll mimic this from JMeter by adding a cookie manager to the request element and marking the ‘clear cookies every iteration’ checkbox, so a new session gets created on each request.

STANDARD JSF 2.1.3, COMPLEX PAGE, MULI-USER:

With the default JVM heap settings for JDK 7, and a default tomcat 7.10 installation, after a mere 1200 independent web requests, the server has essentially locked up, after disappointing initial performance to begin with. The server’s memory has been exhausted purely due to persistence of the (IDENTICAL!!!) views, and it’s spending most of its time in garbage collection. Pages start taking seconds to render.

Now the above scenario is the most likely for a standard public website. If you have a session time of 30 minutes, with a complex view, server side state saving, and unique visitors, on default JVM heap settings, as little as one request per second will cause enough state to be stored to bring your machine down. The longer the session idle time the worse it gets.

You can see why people are having problems with JSF, and I don’t necessarily blame them. Its totally foreign behavior compared to what they are used to. Now I am using server side state with partial state saving turned off (pre JSF 2 you don’t have the option anyway). Partial state saving will give you SOME headroom (albeit from a low base). You could also use client side state saving, however on complex views (even with partial turned on) this gets VERY big and introduces additional CPU inefficiencies as well as unnecessary payload on each request. We have already shown CPU usage is excessive to begin with due to restore/buildView. Switching to client side state will make that worse. Security restrictions may also prevent this option.

This is the fundamental issue with JSF as it currently stands – on large views (the views you’d expect to be working with to take advantage of component oriented design) JSF is so demanding in both CPU horsepower AND memory as to be unsuitable for a whole range of situations (in my opinion).

I find for non trivial sites we have to compensate by having lots of (very fast!!! processors), smart session management (fast cleanup rather than long idle timeout) and multi-gigabyte heaps. And even then you could still possibly get into trouble on a public facing website rather than an intranet site, where there is less control over expected unique user base.

You will see from the facelet template representing my sample page that I am using JSTL to create 1000 panelGroups in a non rendered fragment. This may seem excessive, but  from my experience, it is by no means difficult to create a complex view with a component count of that order.

As a final test, let’s try our stateless model on the same page, hit with unrelated requests:

STATESTLESS JSF 2.1.3, COMPLEX VIEW, MULI-USER

Not bad! We’re still up at almost 16,200 requests per minute, continuous (essentially the same as single-user since we are not saving any per view state).

I have run this test for millions of cycles over several hours at 100% cpu to ensure that no session data is created by default and there are no discernable memory leaks. Garbage collection performance is also good. In the above test only a handful of full collections were performed over hours at full throttle, showing that whatever objects created by the framework to service a cycle are short lived and cleaned during an incremental only. If you switch to standard JSF with server side state saving, the persisted views rapidly end up in the old generation and influence pause times on the full sweeps.

Clearly, our stateless model degrades at a far more comfortable rate than standard JSF, as would be expected.

Incidentally, if we put everything inside the h:form in a non rendered fragment (essentially rendering an empty page aside from html boilerplate), it tops out at 35,000 rpm. That’s around 5 milliseconds latency.

You can view this 5 milliseconds latency as the ‘steady state framework overhead’ of Stateless JSF (on my core2 laptop at any rate). Since we are pooling views, this should not change that much. 5 milliseconds I can live with.

Postbacks will incur additional overhead due to the extra phases and will depend on how much of the view you push through to JSF (using <f:ajaxexecute=”….”/>  for example. Stick to good use of @this where appropriate. Provided you are rendering from simple beans in memory, GETS shouldn’t change much.

If the backing beans associated with a page view do not store any persistent session or application state (as is the case in our example) – you get that throughput FOREVER regardless of how many unique users, individual get requests, or postbacks are submitted. The framework no longer retains any per view, per request or per session state as part of default operation. Of course you could introduce session state by appropriately scoping your backing beans (like any other framework), but this is controlled by you, outside the scope of JSF, and is far more familiar and predictable.

And as a final plus – say goodbye to stale views. Postbacks always work since the views never change and you can always post into an available pooled view. Of course, you can still time out your session, but that’s not a JSF issue and doesn’t apply if your backing beans aren’t session scoped.

So there you have it. With these simple optimisations to the default internal JSF implementation modules you are free to use JSF in a lightweight, stateless fashion if desired, with vastly increased cpu and memory performance, while keeping the vast bulk of the normal jsf behaviour intact. Yes views are immutable, but you may have never made use of runtime view mutation anyway. Yes, you have to bind to backing beans, but you do that anyway.

Besides, components will increasingly be client side, and you can use a good javascript framework like JQuery to change the client DOM however you like, bypassing many JSF cycles through the use of JSON (I find this is how i use it now). The goal of Stateless JSF is to allow the framework to become a less instrusive compositing layer, with much of the  magic done client side if desired.

This should open up JSF to many more uses, and allow a transition across to client side programming with minimal overhead.

It’s important to note – it’s not all or nothing. Stateless JSF has been designed so stateless and stateful pages can co-exist as required. You don’t have to switch everything over. If there is only one page, or a public section of your site that is causing issues, you can run that stateless and run the rest stateful as is. The stateless implementation classes override the default implementation classes and simply fall back to default operation for pages not explicitly marked as stateless.

The Code

PLEASE REGARD THIS AS BETA QUALITY SOFTWARE. THE RE-USE OF VIEWS REQUIRES THOROUGH REVIEW TO ENSURE WE ARE NOT ACCIDENTALLY LEAKING DATA ACCROSS REQUESTS.

Download files and mercurial repo are available from bitbucket:

https://bitbucket.org/industrieit/stateless-jsf

Note that it is tested with MOJARRA 2.1.3. Since we are extending some implementation classes it may NOT work for other versions. In this case it’s best to just include the small number of source files in your own project and tweak as required.

If you  are not interested in how the code works and are happy with Mojarra 2.1.3, you only need the binary jar. The zip file conatins a full packaged maven project (with seam and spring) with prebuilt war in the target directory that can be deployed (Tomcat 7.10  tested) directly. You could also use the existing maven project as a base for your own development.

If you would like to tweak the code, you may copy the source files from package com.industrieit.jsf.stateless.impl.* and include them in your own JSF 2 project.

To enable Stateless JSF, include the abovementioned package in either source or jar form, and add the following settings to your faces-config.xml (custom settings such as those for seam, can be retained). We need to specify the state manager, the view manager, the view declaration language factory, and add a phase listener.

<?xml version="1.0" encoding="utf-8"?>
<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">

  <name>StatelessJSF</name>
  <application>
    <state-manager>
    com.industrieit.jsf.stateless.impl.SJSFStateManager</state-manager>
    <view-handler>
    com.industrieit.jsf.stateless.impl.SJSFViewHandler</view-handler>
  </application>
  <factory>
    <view-declaration-language-factory>
    com.industrieit.jsf.stateless.impl.SJSFVDLFactory</view-declaration-language-factory>
  </factory>
  <lifecycle>
    <phase-listener>
    com.industrieit.jsf.stateless.impl.SJSFPhaseListener</phase-listener>
  </lifecycle>
</faces-config>

 

Stateless JSF is made to work seamlessly with standard JSF. By default, nothing will change. In order to flag a page as stateless, you must place an appropriate child component of the view root as such (note the panelGroup above h:head):

<!DOCTYPE
composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:a="http://richfaces.org/a4j"
xmlns:b="http://java.sun.com/jsf/composite/comp">
  <h:panelGroup id="SJSF" rendered="false" stateless="true" />
  <h:head></h:head>
</html>

 

Normally components at the same level as the h:head tag are the direct children of UIViewRoot. The marker component must have an id of SJSF and it must have an attribute called stateless valued true. Unless this component is defined and placed in the correct location, Stateless JSF will operate exactly the same as regular stateful JSF. To test whether the page is operating stateless, view the rendered markup. If stateless, the value of the javax.faces.ViewState hidden field will be “STATELESS_JSF”, otherwise it’s normally a concatenation of two random numbers and indicates normal stateful JSF is in operation for that particular view.

STATELESS:

<input type=”hidden” name=”javax.faces.ViewState” id=”javax.faces.ViewState” value=”STATELESS_JSF” autocomplete=”off” />

STATEFUL:

<input type=”hidden” name=”javax.faces.ViewState” id=”javax.faces.ViewState” value=”-3761328746132864:7561873643853” autocomplete=”off” />

Questions

Does it work with Seam?

 Yes, tested with Seam 2.2.2, (jars are in the zip though config commented out in faces-config.xml), however conversations are not currently working. It would be nice if someone could identify the issue. I would guess conversations are set up by the seam phase listener in some way. Also – DO NOT USE page scope on stateless views.

What about JSF 2 view scoped beans or Seam page scoped components?

Don’t use the Seam page scope! I am not clearing it at the moment. The JSF 2 @ViewScoped beans are stored in the map accessed from UIViewroot.getViewMap(). I am currently just clearing them as I prefer to keep state outside of JSF. Beans stored in the view are problematic. Storing state in the tree prevents you from controlling identity. You can’t reuse the ‘same’ component in a different page, and you lose the state if you refresh the page. There are other options. Some sort of ‘conversation’ managed outside of JSF is more flexible.

I could have persisted the viewMap in the session keyed to a unique viewstate id the same way stateful JSF does, but have chosen not to. This automatically allocates session data per view, exactly what I’m trying to avoid. I’d rather avoid ‘getting a little bit pregnant’. Either run fully stateless or don’t bother. Hence the fixed viewstate id string of “STATELESS_JSF”

How does this work with component libraries?

Not sure – let us know.  Theoretically should be ok, but any components that try to persist to the view and not a backing bean will not work properly. Not only that – if the component does not subclass UIInput the state will not be cleared when put back in the free pool. This could be dangerous as it will inevitably be used to service a request from a different user.

Most of the sites I work on have exacting styling requirements and most of the component libraries are not flexible enough to be styled freeform. Most of the components I do therefore are custom composites mainly utilising the base JSF tags, with advanced behaviour implemented on the client through integration with JQuery and JSON. This makes a lot of the JSF tags and components redundant, and limits JSF interaction to mainly coarse grained submissions only. The new JSF 2 features allow you to create a component comprising backing beans, html markup and javascript to be developed, tested, packaged and versioned independently, and incorporated into the aggregate web application as a jar file. This has merit on its own if we can avoid the overhead of standard JSF.

My Facelets don’t hot deploy when running STATELESS!

Yes, the views are being cached – currently its buildView() that determines whether the facelet files are changing and we no longer call that on each request. Either restart the container, or provide an action that calls SJSFStatePool.clearPool() to clear the viewcache. You could have a simple page that encodes the call in inline el. There may be a better way but that’s whats in the current release.

There is a flaw in the design / I have an idea that can make it better.

Great! Thats why it’s open source.

Cheers…

Rudi

The views expressed on this blog are those of the author and do not necessarily reflect the views of Industrie IT. 
Posted in Technical | Tagged , , , , | 29 Comments