Modified: websites/production/tapestry/content/performance-and-clustering.html
==============================================================================
--- websites/production/tapestry/content/performance-and-clustering.html 
(original)
+++ websites/production/tapestry/content/performance-and-clustering.html Sat 
Feb  3 18:21:36 2018
@@ -36,13 +36,26 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div></div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  
href="index.html">Home</a></li><li><a  href="getting-started.html">Getting 
Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  
href="download.html">Download</a></li><li><a  
href="about.html">About</a></li><li><a  class="external-link" 
href="http://www.apache.org/licenses/LICENSE-2.0";>License</a></li><li><a  
href="community.html">Community</a></li><li><a  class="external-link" 
href="http://www.apache.org/security/";>Security</a></li><li><a  
class="external-link" href="http://www.apache.org/";>Apache</a></li><li><a  
class="external-link" 
href="http://www.apache.org/foundation/sponsorship.html";>Sponsorship</a></li><li><a
  class="external-link" 
href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li></ul></div>
+
+</div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form 
enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";> 
- <input type="text" name="q"> 
- <input type="submit" value="Search"> 
-</form></div><div class="emblem" style="float:left"><p><a  
href="index.html"><span class="confluence-embedded-file-wrapper"><img 
class="confluence-embedded-image confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div><div
 class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Performance and Clustering</h1></div></div>
+            <div id="smallbanner"><div class="searchbox" 
style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; 
font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";>
+  <input type="text" name="q">
+  <input type="submit" value="Search">
+</form>
+
+</div>
+
+
+<div class="emblem" style="float:left"><p><a  href="index.html"><span 
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image 
confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></span></a></p></div>
+
+
+<div class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Performance and Clustering</h1></div>
+
+</div>
       <div class="clearer"></div>
       </div>
 
@@ -54,51 +67,49 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>Tapestry has a great 
<strong>performance</strong> story to tell. It's designed to take advantage of 
the speed of the modern JVM: no reflection, built to support a high level of 
concurrency without contention, and clean, lightweight code paths. In addition, 
there is built-in integrated GZIP content compression, far-future expires 
headers on static resources, JavaScript aggregation and minification, and an 
intentionally lightweight use of the HTTPSession. The result is a blistering 
fast framework. See <a  class="external-link" 
href="http://tapestry.apache.org/2011/06/13/tapestrys-performance-tested.html";>Tapestry's
 Performance Tested</a> for some objective numbers.</p><div class="aui-label" 
style="float:right" title="Related Articles"><h3>Related Articles</h3><ul 
class="content-by-label"><li> 
-  <div> 
-   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
-  </div> 
-  <div class="details"> 
-   <a  href="performance-and-clustering.html">Performance and Clustering</a> 
-  </div> </li><li> 
-  <div> 
-   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
-  </div> 
-  <div class="details"> 
-   <a  href="session-storage.html">Session Storage</a> 
-  </div> </li><li> 
-  <div> 
-   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" 
title="Page">Page:</span> 
-  </div> 
-  <div class="details"> 
-   <a  href="persistent-page-data.html">Persistent Page Data</a> 
-  </div> </li></ul></div><h2 
id="PerformanceandClustering-PerformanceTips">Performance Tips</h2><p>But even 
with all of Tapestry's built-in speediness, to really get top performance 
you'll need to be sure you're not hamstringing Tapestry. As a start, use the 
following checklist:</p><ul><li>Ensure (be absolutely sure) that <a  
href="configuration.html">Production Mode</a> is turned on in 
production.</li><li>Minimize the use of the HTTPSession (see below), especially 
if you're using clustering.</li><li>Set <a  
href="configuration.html">tapestry.clustered-sessions</a> to "false" if you 
aren't using clustering.</li><li>Organize your JavaScript files into <a  
href="legacy-javascript.html">JavaScriptStacks</a>.</li><li>Ensure that your 
static resources (images, CSS, JavaScript) are being cached by the 
browser.<ul><li>Use "asset:" or "context:" <a  
href="component-parameters.html">binding prefixes</a> for all links to static 
resources (images, CSS, JavaScript).</li><li>Make sure that your 
 firewall, proxy server, load balancer, front-end web servers, and app servers 
all allow caching of static resources.</li><li>Ensure "cache-control" and 
"vary" HTTP headers are set correctly for your static resources.</li><li>Use a 
client-based tool (like Firebug) to examine the requests that your browser 
makes as you navigate through the site. You should <em>not</em> see repeated 
requests for static resources.</li></ul></li><li>Consider using a <a  
class="external-link" 
href="http://en.wikipedia.org/wiki/Content_delivery_network"; 
rel="nofollow">Content Delivery Network</a> for static parts of your 
site.</li></ul><p>After all of the above issues are addressed, if you still 
have performance problems, they probably aren't related to Tapestry.</p><h2 
id="PerformanceandClustering-ClusteringversusStickySessions">Clustering versus 
Sticky Sessions</h2><p>For web applications, <strong>clustering</strong> is a 
load-balancing technique in which multiple application servers are set up to 
behave
  as one big server. Generally this requires replicating HttpSession data 
across the servers, to ensure that a user's web interactions will continue 
without interruption regardless of which server handles the next request. 
Session replication achieves very high reliability, but it incurs an extra 
performance cost (due to the serializing and deserializing of session data and 
the extra network traffic required).</p><p>In contrast, <strong>Sticky 
Sessions</strong> (also called <em>session persistence</em> or <em>sticky 
persistence</em>) is a load balancing technique in which each session is 
assigned to a particular server for the duration of the session. This approach 
doesn't require copying HTTPSession data between servers, so it's very 
scalable. But if a server goes down, all of its sessions are lost.</p><p>In 
general, the sticky sessions approach is the way to go when possible (that is, 
when performance is more important than session survival). It represents a much 
more efficient use
  of resources ... you are scaling <em>out</em> not <em>up</em>, which is 
always cheaper. It also means that you don't have to be as careful about what 
goes into the HTTPSession.</p><p><em>For details on setting up clustering and 
sticky sessions, see the documentation of whatever load balancer you are 
using.</em></p><h2 
id="PerformanceandClustering-Clustering">Clustering</h2><p>Tapestry is designed 
to be "a good citizen" of an application server that supports clustering. It is 
careful about what it writes into the HttpSession. The framework understands 
that the server that receives a request may not be the same one that rendered 
the page initially; this knowledge affects many code paths, and it guides the 
approach Tapestry takes to caching page and component properties.</p><p>Your 
part is to properly manage the objects put into the HttpSession (via 
@SessionAttribute, @SessionState or @Persist; see <a  
href="session-storage.html">Session Storage</a>):</p><ul><li>Don't store 
anything i
 n the session that you don't have to. Principally this means minimizing the 
use of @Persist (see <a  href="page-navigation.html">Page Activation</a> and <a 
 href="using-select-with-a-list.html">Using Select With a List</a>), storing 
only IDs in the session rather than whole entities.</li><li>Where possible, 
persist only objects that are immutable (i.e., String, or a primitive or 
wrapper type).</li><li>Only put <em>serializable</em> objects into the 
session.</li><li>Make use of the @ImmutableSessionPersistedObject annotation 
and OptimizedSessionPersistedObject interface (both described 
below).</li></ul><p>Again, Tapestry is a good citizen, but from the application 
server's point of view, it's just another servlet application. The heavy 
lifting here is application server specific.</p><p></p><h2 
id="PerformanceandClustering-ClusteringIssues">Clustering Issues</h2>
+                <div id="ConfluenceContent"><p>Tapestry has a great 
<strong>performance</strong> story to tell. It's designed to take advantage of 
the speed of the modern JVM: no reflection, built to support a high level of 
concurrency without contention, and clean, lightweight code paths. In addition, 
there is built-in integrated GZIP content compression, far-future expires 
headers on static resources, JavaScript aggregation and minification, and an 
intentionally lightweight use of the HTTPSession. The result is a blistering 
fast framework. See <a  class="external-link" 
href="http://tapestry.apache.org/2011/06/13/tapestrys-performance-tested.html";>Tapestry's
 Performance Tested</a> for some objective numbers.</p><div class="aui-label" 
style="float:right" title="Related Articles">
+
 
-<p>The Servlet API was designed with the intention that there would be only a 
modest amount of server-side state, and that the stored values would be 
individual numbers and strings, and thus, immutable.</p>
 
-<p>However, many web applications do not use the HttpSession this way, instead 
storing large, mutable objects in the session. This is not a problem for single 
servers, but in a cluster, anything stored in the session must be serialized to 
a bytestream and distributed to other servers within the cluster, and restored 
there.</p>
 
-<p>Most application servers perform that serialization and distribution 
whenever HttpSession.setAttribute() is called. This creates a data consistency 
problem for mutable objects, because if you read a mutable session object, 
change its state, but <em>don't</em> invoke setAttribute(), the changes will be 
isolated to just a single server in the cluster.</p>
 
-<p>Tapestry attempts to solve this: any session-persisted object that is read 
during a request will be re-stored back into the HttpSession at the end of the 
request. This ensures that changed internal state of those mutable objects is 
properly replicated around the cluster.</p>
 
-<p>But while this solution solves the data consistency problem, it does so at 
the expense of performance, since all of those calls to setAttribute() result 
in extra session data being replicated needlessly if the internal state of the 
mutable object hasn't changed.</p>
 
-<p>Tapestry has solutions to this, too:</p>
 
-<h3 
id="PerformanceandClustering-@ImmutableSessionPersistedObjectAnnotation">@ImmutableSessionPersistedObject
 Annotation</h3>
+<h3>Related Articles</h3>
 
-<p>Tapestry knows that Java's String, Number and Boolean classes are 
immutable. Immutable objects do not require a re-store into the session.</p>
+<ul class="content-by-label"><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
 
-<p>You can mark your own session objects as immutable (and thus not requiring 
session replication) using the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/ImmutableSessionPersistedObject.html";>ImmutableSessionPersistedObject</a>
 annotation.</p>
+        <div class="details">
+                        <a  href="performance-and-clustering.html">Performance 
and Clustering</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
 
-<h3 
id="PerformanceandClustering-OptimizedSessionPersistedObjectInterface">OptimizedSessionPersistedObject
 Interface</h3>
+        <div class="details">
+                        <a  href="session-storage.html">Session Storage</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
 
-<p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptimizedSessionPersistedObject";>OptimizedSessionPersistedObject</a>
 interface allows an object to control this behavior. An object with this 
interface can track when its mutable state changes. Typically, you should 
extend from the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/BaseOptimizedSessionPersistedObject.html";>BaseOptimizedSessionPersistedObject</a>
 base class.</p>
+        <div class="details">
+                        <a  href="persistent-page-data.html">Persistent Page 
Data</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
 
-<h3 
id="PerformanceandClustering-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
 Service</h3>
 
-<p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SessionPersistedObjectAnalyzer.html";>SessionPersistedObjectAnalyzer</a>
 service is ultimately responsible for determining whether a session persisted 
object is dirty or not (dirty meaning in need of a restore into the session). 
This is an extensible service where new strategies, for new classes, can be 
introduced.</p></div>
+<h2 id="PerformanceandClustering-PerformanceTips">Performance Tips</h2><p>But 
even with all of Tapestry's built-in speediness, to really get top performance 
you'll need to be sure you're not hamstringing Tapestry. As a start, use the 
following checklist:</p><ul><li>Ensure (be absolutely sure) that <a  
href="performance-and-clustering.html">Production Mode</a> is turned on in 
production.</li><li>Minimize the use of the HTTPSession (see below), especially 
if you're using clustering.</li><li>Set <a  
href="performance-and-clustering.html">tapestry.clustered-sessions</a> to 
"false" if you aren't using clustering.</li><li>Organize your JavaScript files 
into <a  
href="performance-and-clustering.html">JavaScriptStacks</a>.</li><li>Ensure 
that your static resources (images, CSS, JavaScript) are being cached by the 
browser.<ul><li>Use "asset:" or "context:" <a  
href="performance-and-clustering.html">binding prefixes</a> for all links to 
static resources (images, CSS, JavaScript).</li><li>Make
  sure that your firewall, proxy server, load balancer, front-end web servers, 
and app servers all allow caching of static resources.</li><li>Ensure 
"cache-control" and "vary" HTTP headers are set correctly for your static 
resources.</li><li>Use a client-based tool (like Firebug) to examine the 
requests that your browser makes as you navigate through the site. You should 
<em>not</em> see repeated requests for static 
resources.</li></ul></li><li>Consider using a <a  class="external-link" 
href="http://en.wikipedia.org/wiki/Content_delivery_network"; 
rel="nofollow">Content Delivery Network</a> for static parts of your 
site.</li></ul><p>After all of the above issues are addressed, if you still 
have performance problems, they probably aren't related to Tapestry.</p><h2 
id="PerformanceandClustering-ClusteringversusStickySessions">Clustering versus 
Sticky Sessions</h2><p>For web applications, <strong>clustering</strong> is a 
load-balancing technique in which multiple application servers are 
 set up to behave as one big server. Generally this requires replicating 
HttpSession data across the servers, to ensure that a user's web interactions 
will continue without interruption regardless of which server handles the next 
request. Session replication achieves very high reliability, but it incurs an 
extra performance cost (due to the serializing and deserializing of session 
data and the extra network traffic required).</p><p>In contrast, <strong>Sticky 
Sessions</strong> (also called <em>session persistence</em> or <em>sticky 
persistence</em>) is a load balancing technique in which each session is 
assigned to a particular server for the duration of the session. This approach 
doesn't require copying HTTPSession data between servers, so it's very 
scalable. But if a server goes down, all of its sessions are lost.</p><p>In 
general, the sticky sessions approach is the way to go when possible (that is, 
when performance is more important than session survival). It represents a much 
mo
 re efficient use of resources ... you are scaling <em>out</em> not 
<em>up</em>, which is always cheaper. It also means that you don't have to be 
as careful about what goes into the HTTPSession.</p><p><em>For details on 
setting up clustering and sticky sessions, see the documentation of whatever 
load balancer you are using.</em></p><h2 
id="PerformanceandClustering-Clustering">Clustering</h2><p>Tapestry is designed 
to be "a good citizen" of an application server that supports clustering. It is 
careful about what it writes into the HttpSession. The framework understands 
that the server that receives a request may not be the same one that rendered 
the page initially; this knowledge affects many code paths, and it guides the 
approach Tapestry takes to caching page and component properties.</p><p>Your 
part is to properly manage the objects put into the HttpSession (via 
@SessionAttribute, @SessionState or @Persist; see <a  
href="performance-and-clustering.html">Performance and Clustering</
 a>):</p><ul><li>Don't store anything in the session that you don't have to. 
Principally this means minimizing the use of @Persist (see <a  
href="performance-and-clustering.html">Page Activation</a> and <a  
href="performance-and-clustering.html">Performance and Clustering</a>), storing 
only IDs in the session rather than whole entities.</li><li>Where possible, 
persist only objects that are immutable (i.e., String, or a primitive or 
wrapper type).</li><li>Only put <em>serializable</em> objects into the 
session.</li><li>Make use of the @ImmutableSessionPersistedObject annotation 
and OptimizedSessionPersistedObject interface (both described 
below).</li></ul><p>Again, Tapestry is a good citizen, but from the application 
server's point of view, it's just another servlet application. The heavy 
lifting here is application server specific.</p><p></p><h2 
id="PerformanceandClustering-ClusteringIssues">Clustering Issues</h2><p>The 
Servlet API was designed with the intention that there would be 
 only a modest amount of server-side state, and that the stored values would be 
individual numbers and strings, and thus, immutable.</p><p>However, many web 
applications do not use the HttpSession this way, instead storing large, 
mutable objects in the session. This is not a problem for single servers, but 
in a cluster, anything stored in the session must be serialized to a bytestream 
and distributed to other servers within the cluster, and restored 
there.</p><p>Most application servers perform that serialization and 
distribution whenever HttpSession.setAttribute() is called. This creates a data 
consistency problem for mutable objects, because if you read a mutable session 
object, change its state, but <em>don't</em> invoke setAttribute(), the changes 
will be isolated to just a single server in the cluster.</p><p>Tapestry 
attempts to solve this: any session-persisted object that is read during a 
request will be re-stored back into the HttpSession at the end of the request. 
This ensur
 es that changed internal state of those mutable objects is properly replicated 
around the cluster.</p><p>But while this solution solves the data consistency 
problem, it does so at the expense of performance, since all of those calls to 
setAttribute() result in extra session data being replicated needlessly if the 
internal state of the mutable object hasn't changed.</p><p>Tapestry has 
solutions to this, too:</p><h3 
id="PerformanceandClustering-@ImmutableSessionPersistedObjectAnnotation">@ImmutableSessionPersistedObject
 Annotation</h3><p>Tapestry knows that Java's String, Number and Boolean 
classes are immutable. Immutable objects do not require a re-store into the 
session.</p><p>You can mark your own session objects as immutable (and thus not 
requiring session replication) using the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/ImmutableSessionPersistedObject.html";>ImmutableSessionPersistedObject</a>
 annotation.</p><h3 id=
 
"PerformanceandClustering-OptimizedSessionPersistedObjectInterface">OptimizedSessionPersistedObject
 Interface</h3><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptimizedSessionPersistedObject";>OptimizedSessionPersistedObject</a>
 interface allows an object to control this behavior. An object with this 
interface can track when its mutable state changes. Typically, you should 
extend from the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/BaseOptimizedSessionPersistedObject.html";>BaseOptimizedSessionPersistedObject</a>
 base class.</p><h3 
id="PerformanceandClustering-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
 Service</h3><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SessionPersistedObjectAnalyzer.html";>SessionPersistedObjectAnalyzer</a>
 service is ultimately responsible for determining whethe
 r a session persisted object is dirty or not (dirty meaning in need of a 
restore into the session). This is an extensible service where new strategies, 
for new classes, can be introduced.</p></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to