ShowTable of Contents
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.
Avoid retrieving large data sets and large 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 ex ample.
- 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 that have the same value for all users, 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.
- In Portlet Factory 6.1 and later versions, you can use the Discardable Variable builder to convert a variable to request scope, with support for reloading data if needed and for caching in WebSphere DynaCache. In version 7.0 and later, you can enable similar functionality in the Service Consumer builder, using the "Performance Options" section.
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.
Transform results in stateless service providers not in service consumers
Many use case scenarios call for creating simpler UI-oriented schema defined structures and transforming larger complex result sets from back end integration calls into these smaller structures. When calling these back end data integration operations via stateless service provider, it is significantly more efficient to transform the results into the new variable structure in the stateless service provider than it would be to do so in the consumer. By not exposing the larger result set outside of the stateless provider, you end up only storing the smaller transformed variable in the user's session in the consumer. If you instead return the entire result set to the consumer and transform it there, you would be storing both the original larger results that you no longer need and the transformed results in each user's session, thus using a lot more memory under a heavy user load on the system.
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 m echanism 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 necessary 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 WebSphere 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.
Restart Performance Test and Production Servers after redeploying WARs
When you redeploy a WAR, the server stops the application, replaces the deployed WAR with the new one, and thus when it starts up you have a NEW copy of all the WAR's necessary classes loaded into memory. JVMs don't immediately garbage collect "classes" (as opposed to object instances), and some classes may have static references to the old (pre-redeployment) caches, which can then keep references to old cache data object instances in memory. To avoid unnecessary memory use by those old classes, it is a best practice to restart performance test servers and production servers after redeploying your portlet WARs, to immediately remove any old classes from memory.
Use the latest version and fixpack of WebSphere 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 WebSphere Portlet Factory built in logging and diagnostic 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 performance
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
These slides describe some of the performance analysis tools that are used with Portlet Factory: Portlet Factory Performance Analysis Tools
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 accommodated 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 Tuning Guide
Be aware of the impact of WebSphere 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 Personalize support in WebSphere Portal consider using 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.
Disable testing support in service provider models
Before deploying, you should disable service testing by unchecking the "Add Testing Support" in the Service Definition builder (or disabling the Service Test builder if you are using that). The generation of service test pages uses some additional memory when models are generated.
Avoid excessive logging and related String construction
Logging code that generates a lot of output should be disabled in production and load testing, and only enabled selectively if needed. In all logging code, the code should first test to see if logging is enabled before constructing String objects for log output, since the String construction itself can use a lot of temporary memory.
Client (Browser) side performance concerns
For portlets, the portal page should be loading Dojo and not the portlet itself, so customization (eg, an optimized build) of Dojo should be done for the portal theme/page.
WebSphere Portal provides the following documentation for how you can do a custom (eg, optimized) Dojo build for use with Portal: