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
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:
- * 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.
- * override the state manager to NOT store any per view state (huh? We’ll get to that)
- * override the view manager to pool and re-use UIViewRoot components.
- * 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!!!
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.
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).
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.
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.
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.
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:
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.
<input type=”hidden” name=”javax.faces.ViewState” id=”javax.faces.ViewState” value=”STATELESS_JSF” autocomplete=”off” />
<input type=”hidden” name=”javax.faces.ViewState” id=”javax.faces.ViewState” value=”-3761328746132864:7561873643853” autocomplete=”off” />
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.
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.
RudiThe views expressed on this blog are those of the author and do not necessarily reflect the views of Industrie IT.