Performance best practices
This page collects some best practices for Portlet
Factory related to performance and memory. This is not a comprehensive
list, and most of the best practices for the underlying platforms – WebSphere
Portal, J2EE and WebSphere Application Server, and Java – are also applicable
for Portlet Factory applications.
Contents
- Avoid retrieving large data sets, particularly in session
variables.
- Use caching across users when feasible.
- Avoid deploying a large number of Portlet Factory WAR
files.
- Use the latest version and fixpack of Portlet Factory.
- Use Portlet Factory's built-in logging tools to look
at performance-related information.
- Use automated load testing tools to validate the performance
and capacity of your application.
- See the WebSphere Portal and WebSphere Application
Server tuning guides for recommendations to optimize server performance.
- Be aware of the impact of Portlet Factory profiling
features.
- When using profiling for Edit (Personalize) support
in Portal, use the "Execution Time" setting for profile entries.
- Utilize the capabilities of external systems when possible.
Avoid retrieving large data sets, particularly in session variables.
Large data sets are the most common cause of memory capacity
issues. Here are some suggestions for how to keep data sets smaller.
- When retrieving data, try to retrieve a small amount for
viewing at a time. Depending on your data source, you can often reduce
size with a more restricted query (to reduce the number of rows and/or
number of columns retrieved). With SQL builders, you can use a selective
query to do this. With Domino, you might consider using or creating more
selective views in Domino, to reduce the row and column count.
If you can't restrict the data set size from the data source (for example,
if you only need to display a few columns while your data source returns
a lot of columns), you can create a service provider that removes unneeded
data, so that the data used by your consumer model (and potentially stored
in session) is smaller.
- If you have a large set of categorized data, consider
providing an interface that initially shows just a list of the categories,
with links to retrieve data for a single category at a time. This technique
uses much less memory than retrieving the entire data set and displaying
it with Category Row builder, for example.
- Caching of results can be another technique for sharing
data across users and reducing session memory use. For example, if you
enable caching in the Service Operation builder, all users (for the same
profile) will share the same result object. This sharing will occur even
though the result variable may be session-scoped in the consumer model
- each user session will have a reference to the same Java object.
- Use paging to fetch data in subsets. There are a number
of builders in Portlet Factory that support a UI for paging through tabular
data sets. For example, there are paging options in the View & Form
builder and the Data Page builder, and the Paging Assistant builder provides
some of the underlying support. These paging features can use a "DataRetriever"
interface that can be used to automatically fetch data in chunks from an
external source. Some data access builders such as SQL Call and Domino
Data Access can provide support for a paging DataRetriever interface. Other
data access builders such as SAP Function Call do not have any built-in
support for paged data access. There are two samples that show some custom
support for paging data: IBM
- Paged web service provider and IBM
- Creating a custom data paging provider. When
you are using Data Page builder to display paged data, be sure to select
the top-level variable as the data to display, not an XML element within
the variable.
- For large variables, if they can be marked as "Shared
(read-only)", they will share a copy instead of having a copy in each
session. Some builders such as Localized Resource will create read-only
variables. Similarly, Variables that are marked as request scoped will
not be stored in the session.
Note that in Portal, each portlet gets its own session, and once a portlet
session is created, it is not released until the entire Portal session
is released. This means that if you have a large number of portlets spread
across many Portal pages, they can potentially all end up in session. Therefore
when you have a large number of portlets, it's especially critical to keep
Variables in session as small as possible.
Use caching across users when feasible.
The Cache Control builder lets you cache the results of
an operation across users. The results are shared for all users of the
same model and profile, so this mechanism is not suitable for user-specific
queries or results.
The Service Operation and Lookup Table builders also have
options for caching results, and both use the functionality of the Cache
Control builder under the covers.
Note that when you are using the Cache Control builder,
you have to select a method that returns the data to cache, and that method
should not have any important side effects.
If you cache a method or service operation that takes input
arguments, the Cache Control builder will automatically keep a separate
cache entry for each unique set of input values. Therefore you should use
it cautiously for methods that take arguments, since you could potentially
end up with a large number of cache entries.
The data cached with these builders is associated with
a specific generated WebApp. In other words, each profile will in general
have its own cache. This is important in some cases. However, if you have
a scenario where data can be cached across profiles, it may be best to
implement the caching in a non-profiled model (perhaps a service provider
model), so that the cached data can be shared across all users.
Avoid deploying a large number of Portlet Factory WAR
files.
Instead, combine portlets in a small number of WAR files
(ideally, one or two). You can have as many portlets as you want in a single
WAR file. Each WAR has overhead of 8MB or more, so if you deploy 20 WARs,
you could use perhaps 150MB - 200MB extra memory, when compared with using
a single WAR. Also, keep in mind that Portlet Factory caching cannot be
shared across WARs. For example, if you have a service provider with a
cached operation returning several MB of data, each WAR will have its own
copy of that data.
Use the latest version and fixpack of Portlet Factory.
Each Portlet Factory release typically includes additional
performance and memory optimization work. By using the latest release you
can get the benefit of all Portlet Factory product improvements related
to performance. Check to make sure you have the latest fixpack also.
Use Portlet Factory's built-in logging tools to look
at performance-related information.
There are some useful logging tools built into Portlet
Factory that can help look at performance. For example:
- Server stats. Server statistics are recorded in a log
file in deployed WAR files whenever the server is running. The server stats
logging records statistics about requests to the Portlet Factory application
every five minutes. This can provide valuable information about the "health"
and performance of the application, and is most useful for looking at servers
under load, either in testing or production. Since server stats logging
does not add any significant performance overhead, it is recommended that
they are left enabled (as they are by default). The server statistics are
written to WEB-INF/logs/serverStats.txt.
- Model action tracing. This feature lets you see all the
actions that take place during server requests to a model. It shows the
sequence of operations, such as calls to methods and page display, with
elapsed time for each. This is most useful for looking at application behavior
for a single user during testing.
- Session size diagnostics. This feature lets you see all
the variables that are in use by a running application. It can help you
find areas where you may be putting a lot of data into session, for example,
by retrieving a large data set. Like model action tracing, this is most
useful for targeted testing with a single user.
This
tech note has more information on these features:
Techniques
to enhance WebSphere Portlet Factory application peformance
For analyzing overall Java heap memory use, the verbose GC logging should
be enabled in the application server. This log file (native_stderr.log)
can be conveniently viewed with the PMAT tool available on developerWorks
(
http://www.alphaworks.ibm.com/tech/pmat).
Use automated load testing tools to validate the performance
and capacity of your application.
In order to find the capacity for a particular application,
for example to know how many concurrent users can be accomodated on a single
server, there is no substitute for automated load testing of the application.
Every application is different, and it is often not possible to extrapolate
between applications.
See the WebSphere Portal and WebSphere Application
Server tuning guides for recommendations to optimize server performance.
For WebSphere Portal, see the IBM
WebSphere Portal Version 6.0 Tuning Guide
Be aware of the impact of Portlet Factory profiling
features.
When you use profiling, each unique profile will generate
its own "WebApp" object in memory, with metadata describing the
pages, methods, variables, and so forth for the model. Each WebApp also
has separate cached results when you use the Cache Control builder or the
caching features of Service Operation and Lookup Table. Therefore you should
avoid having a very large number of different profiles for a model. For
example, if you allow individual users to edit profile values with the
"Edit" mode in Portal, you might potentially end up with a separate
WebApp for every user. See the next item for how to avoid this.
Also, when you are using caching, if you can cache data
in an unprofiled model such as a service provider model, this is better
than caching data in a profiled model, since you'll have a single shared
cache instead of multiple entries. On the other hand, if you need profile-specific
cache results, you can get them by caching in the profiled model
When using profiling for Edit (Personalize) support
in Portal, use the "Execution Time" setting for profile entries.
When you allow users to edit individual values in "Edit"
mode, you may have a potential situation where each user ends up with their
own generated WebApp (see information above on the impact of profiling).
The "Execution Time" setting for profile entries can, in some
scenarios, allow you to avoid this, by having the developer indicate which
profile values are simple runtime values that don't require a unique regen.
This technique can also be valuable in other situations (in addition to
Edit mode) where you may have a large number of unique profiles.
To edit this setting, open up the profile set by double-clicking
the ".pset" file, then go to the "Entries" tab, select
the desired profile entry and click the "Edit" button. The choice
for Execution Time is at the bottom of that dialog box. Note that you can
only use this choice when the associated profiled builder input can accept
a runtime value such as a variable reference. It cannot be used when profiling
a value which would result in different generated code, such as the filename
for the Imported Page builder.
Utilize the capabilities of external systems when possible.
Instead of using a Method / LJO to categorize, sort, compute,
or sum data from an external source, let the external data storage system
to do the work for you. Usually sources such as databases are much better
equipped to handle such tasks.