Web content cache configuration
Contents
- WCM caching recommendations
- Set the default Web content cache type
- WCM Cache
- Servlet cache
- Forced invalidation of caches
- Cache key generation: Servlet caching
- Cache key generation: WCM Caching
- Automatic invalidation
- Automatic invalidation: dependency IDs
- WebSphere Edge Server components
- Performance Tuning
- Recommended Tools
- Typical rendering times
- Caching scenario
- Lean Testing
- Graphs: Number of Users in Time
- Summary
- Recommended Resources
- Servlet Caching
- Servlet Caching - view.jsp
- Servlet Caching - cachespec.xml
- Group Based Personalization - view.jsp
- Multiple Caching Policies
- Multiple Caching Policies - view.jsp
- Multiple Caching Policies - cachespec.xml
- Metadata Generator: Random Caching Time
- Handle WCM_GLOBAL_CONTEXT - view.jsp
- Get current page ID - view.jsp
- Dependencies and multiple caching policies
- Network Dispatcher Configuration
- Content Based Router Configuration
- Caching proxy configuration
- HTTP Server configuration
- Skin Timer
- Theme Timer
- Addenda
WCM caching recommendations
Edge Server caching proxy Recommended for caching resources...
- images
- CSS
- JavaScript
Use instead of WCM basic caching
Servlet caching Recommended for caching of WCM and portlets Unless it's a very static item, IBM does not recommend using caching proxies to cache HTML. Do not cache items being dynamically cached by the WebSphere Portal Server.
WCM caching When personalization and access control is required. Static Site Use prerendering and HTTP server. Caching not needed With servlet caching the goal is majority of requests handled by caching proxy. Should be almost nothing left to do at WCM level. IBM testing has shown a 91% reduction in requests per second on portal server.
Set the default Web content cache type
To set default Web content caching type, edit...
PROFILE_HOME/PortalServer/wcm/shared/app/config/wcmservices/WCMConfigService.properties
...and set...
- connect.businesslogic.defaultcache
- connect.moduleconfig.ajpe.contentcache.defaultcontentcache
defaultcache defaultcontentcache No caching False None Basic cache True N.A. Site caching False Site Session caching False Session User caching False User Secured caching False Secured Personalized caching False Personalized Web content cache parameters
Basic cache connect.businesslogic.defaultcacheexpires
Default expiry for the basic cache. Either a relative period or absolute date and time.
connect.businesslogic.defaultcache
If true, basic caching is enabled. If false or missing, advanced caching is enabled.
Advanced cache connect.moduleconfig.ajpe.contentcache.defaultcontentcache
If the advanced cache is enabled, the default advanced cache type is set here.
SITE | SECURED | PERSONALIZED | USER | SESSION
connect.moduleconfig.ajpe.contentcache.contentcacheexpires
Default expiry for all advanced caches. It can be either a relative period or an absolute date and time.
Advanced cache: Session connect.sessioncacheconfig.memcachesize Other parameters...
resourceserver.browserCacheMaxAge Maximum time an item will be stored in a Web browser cache. resourceserver.maxCacheObjectSize Maximum size of objects that can be cached in kilobytes. By default this is set to 300. Cache expire time formats
For cache expire settings, specify either a relative or absolute time:
{units} =
d|D days m|M months s|S seconds h|H hours {date-format-string} =
- Mon, 06 Nov 2000 09:00:00 GMT
- Monday, 06-Nov-00 09:00:00 GMT
- Mon Nov 6 09:00:00 2000
- 6 Nov 2000 9:00 AM
The last two formats assume GMT.
- contentcacheexpires="REL 300S"
- contentcacheexpires="ABS Mon, 06 Nov 2000 09:00:00 GMT"
WCM Cache
WCM Cache settings apply to all content
Basic Low memory usage. Same content for every user. Better to use caching proxy in typical scenario. Advanced Increased memory usage. Supports access control and personalization. Less configurable than servlet caching for Portal scenario WCM cache can be manually overriden by GET options for URLs.
WCM basic cache: Configuration
Configuration Options
- connect.businesslogic.defaultcache=true
- connect.businesslogic.defaultcacheexpires=expirydate
expirydate applies to all content items
Note that the following disables the WCM Advanced Content cache
connect.moduleconfig.ajpe.contentcache.defaultcontentcache=none
Object Cache name:
services/cache/iwk/module
WCM Basic Cache: URL Override
- CACHE
- NONE renders current URL bypasing cache
- SITE enables basic caching for current URL
- EXPIRES
WCM advanced cache: Configuration
Configuration Options
- connect.moduleconfig.ajpe.contentcache.defaultcontentcache=[ SITE | SECURED | PERSONALIZED | USER | SESSION ]
...where
SITE Essentially the same as "Basic" Caching except that "Connect Tags" are processed each time. IBM recommended not to use Connect tags, What alternate method should we use? (A: JSP components)
SESSION Stores a copy of an item in the cache for each session. (Memory only) USER Stores a copy of an item in the cache for each user SECURED Stores a copy of an item in the cache based on which groups the current user belongs to. Other users that belong to the same groups will access the same cached items PERSONALIZED Stores a copy of an item in the cache based on the current users "personalization" profile. Other users who have selected the same personalization categories and keywords, and who belong to the same Group, will access the same cached items - connect.moduleconfig.ajpe.contentcache.contentcacheexpires=<EXPIRY_DATE>
<EXPIRY_DATE> applies to all content items
- connect.businesslogic.defaultcache = false
This disables the WCM Basic Content Cache
Object Cache names
- services/cache/iwk/session for SESSION cache
- services/cache/iwk/processing for all other cache types
WCM advanced cache: Which to use when
For content that is Use Description Not personalised SITE Every user can access the same cached items Unique for different groups of users SECURED Users that belong to the same groups will access the same cached items Unique for different personalization profiles PERSONALIZED Users that share the same personalization profile will access the same cached items Unique for every user USER Every user gets its own cached items Unique for every session SESSION Every session gets its own cached items WCM advanced cache: URL Override
CONTENTCACHE
Will override cache type for referenced URL
- SITE, SECURED, PERSONALIZED, USER, SESSION
Retrieves content of request for specific cache type. If not found content will be loaded to cache
- NONE
Will deliver uncached content
CONTENTCACHEEXPIRES
Specifies a new expiry setting
- REL <NUM> <UNIT>
- ABS <TIME>
Servlet caching
Servlet caching caches requests at the appserver Web container layer.
Slower than prerendering. Faster than WCM content caching
Servlet caching can cache
- WCM rendering portlets
- WCM servlet
Monitoring and management via the Cache Monitor web application.
Syndication
If you invalidate cache content before you syndicate, you will invalidate the old content.
If you invalidate during syndication, the old version will be cached again.
Ensure that you invalidate after finishing syndication.
If syndication is set to every 15 minutes, that is effectively the life time of the cache if syndication wipes out all items.
Servlet caching: Configuration
Dynamic Cache Service enabled by default. Servlet caching disabled by default.
Cache Monitor used for management. Install from...
WASROOT/installableApps/cachemonitor.ear
Specific cache behaviour defined by...
WEBAPP/WEB-INF/cachespec.xml
For example...
config/cells/cell/applications/wcm.ear/deployments/wcm/ilwwcm.war/WEB-INF/cachespec.xml
By default, some of theme and skin resources will be cached.
Some of the example portlets have predefined cachespec.xml files. For example, for ilwwcm.war...
<?xml version="1.0" ?> <!DOCTYPE cache SYSTEM "c:\ibm\appserver\properties\cachespec.dtd"> <cache> <cache-entry> <class>servlet</class> <name>com.presence.connect.ConnectServlet.class</name> <property name="store-cookies">false</property> <property name="save-attributes">true</property> <property name="consume-subfragments">true</property> <cache-id> <component id="CACHEID" type="parameter" > <required>true</required> </component> <component id="" type="servletpath" > <required>false</required> <value>/connect</value> </component> <timeout>3000</timeout> </cache-id> </cache-entry> </cache>
The results of included JSPs can be cached with servlet cache, depending on consume-subfragments option.
Components of the cachespec.xml file
<cache> The root element of the cachespec.xml file, appearing only once. It holds multiple <cache-entry> stanzas. <cache-entry> There is one of these for each item to be cached. Cache entries can describe items to be cached, items which will invalidate other cache entries, and dependencies between cache entries. <class> Identifies the type of entry. Possible values are command, servlet, and webservice. <name> The name of the item to be cached. For commands, it should be the fully qualified package and class name, including the .class suffix. For servlets or JSPs, it should be the URI path relative to the application's context root. For example, if the full URL to the JSP is... http://www.myco.com/myapp/products/catalogList.JSP
...the value here would be...
/products/catalogList.JSP
If you were using the cachespec.xml file from the application server properties directory (global), the entire URL would be necessary. If you have multiple servlet aliases, multiple <name> stanzas could be included here to list each alias that you intend to cache.
<property> Used to set optional properties on a cache entry, such as whether it can be cached outside of WebSphere Application Server, and whether this entry can be persisted to disk. (There is a list of definable properties in the WebSphere Application Server V5 Information Center.) There can be multiple properties per cache entry. <sharing-policy> Determines whether a cache entry should be shared between distributed caches, and if so, how that should occur. Distributed caches will be discussed later. <cache-id> Where the cache identifiers for each cache entry are configured. This is a key, similar to a database key structure that identifies a particular cache entry as unique. Caching is generally not as simple as specifying a particular servlet, JSP, or command to cache. These must be qualified with attributes that distinguish one cache entry from another. For example, caching a servlet that returns a weather forecast by the URI... /weather/forecast
...would not be desirable; think of what would happen if one user asked for the forecast for Miami and that result was cached, and the following user invoked this URI to get the forecast for Anchorage. In this case, there is probably a request parameter that is sent along with the servlet invocation that has the city name or zip code for the forecast. This is the piece of data that would ensure the cached results are unique and match the request, so, for example, Miami forecasts are always returned to other users asking for Miami weather. This parameter should be designated as required, as the cache entry is meaningless without it. Sample 5, below, shows a similar cache specification. There may also be other parameters as part of the cache ID, such as whether the user is asking for a short-range or long-range forecast. Each component of the cache ID is specified in a <component> tag, as shown in the examples below.
Servlet caching: cachespec.xml
<?xml version="1.0" ?> <!DOCTYPE cache SYSTEM "cachespec.dtd"> <cache> <cache-instance name="jndi/cache-instance-name"> <cache-entry> <class>servlet</class> <name>/jsp/html/view-original.jsp</name> <sharing-policy>not-shared</sharing-policy> <property name="save-attributes">false</property> <property name="ignore-get-post">true</property> <property name="consume-subfragments">true</property> <cache-id> <component id="UNIQUE_ID" type="attribute"> <required>true</required> </component> <component id="WCM_GLOBAL_CONTEXT" type="parameter"> <required>false</required> </component> <component id="PAGE" type="attribute"> <required>false</required> </component> <timeout>150</timeout> <metadatagenerator> com.ibm.pl.fz.randomcacher.RandomCacher </metadatagenerator> </cache-id> </cache-entry> </cache-instance> </cache>Attributes...
- <cache-instance>
Recommended to create new servlet cache instance, using WAS admin
- <name>
Either path to JSP or class name with .class at the end
- <sharing-policy>
Cache replication in cluster. Recommended values are
not-shared only cache invalidations will be replicated shared-push if full replication is needed - <property>
save-attributes=false will not store request attributes ignore-get-post=true will keep one copy for GET and POST results consume-subfragments will include content of all referenced JSPs - <cache-id>
Defines rules to store different results for the same URL. Can be defined multiple times with different options
- <timeout>
Cache timeout in seconds. Can be overriden by metadatagenerator.
- <metadatagenerator>
References class name that can populate attributes used by components
- <idgenerator>
References class name that will create custom cache ids
- <component>
Defines specific part of cache ID
parameter Use value of named GET/POST parameter attribute Use value of named request attribute session Use value of named session attribute - <required>
If component is required, but value is null request will not be cached
- <value>
Defines specific value, that is cacheable
- <not-value>
Defines specific value, that is not cacheable
Servlet caching: generic workflow
- Create basic version that will cache page
- Check that contents of page will change when performing actions
- Add components to make actions change content of page
- cachespec.xml automatically reloads after changes (typically 5 sec)
- Modified JSPs should reload automatically
- Repeat
It is tricky!
Advanced caching logic requires populating request attributes before calling WCM servlet
Can be achieved using
- servlet filter
- custom metadata generator
Both require Java class creation. Servlet filter requires changing of web.xml. Custom metadata generator need to be put into WEBINF/classes folder
Slower development cycle, requires application restart
Servlet caching: Use with WCM Servlet
Name of WCM servlet is...
com.presence.connect.ConnectServlet.class
Some requests can never be cached, include following in <cache-id> section
<component id="MOD" type="parameter"> <required>false</required> <not-value>Subs</not-value> <not-value>Synd</not-value> <not-value>ItemDispatcher</not-value> <not-value>Syndication</not-value> <not-value>MemberFixer</not-value> <not-value>VersioningEnablement</not-value> <not-value>WorkflowEnablement</not-value> <not-value>PlutoUploadFile</not-value> <not-value>PlutoDownloadFile</not-value> <not-value>AJPECatSelect</not-value> <not-value>RefreshAllItems</not-value> <not-value>Template</not-value> </component>Additional components to include in the cache-id section. All should be marked as not required
id Choose between Draft and Published versions pagedesign Choose between alternate page designs version Choose between different versions source Choose components directly cmpntname Choose components directly cmpntid Choose components directly Servlet caching: Portal Specific
One of the attributes has to be based on portlet ID. You need to differentiate between anonymous and logged in versions. Typically a new view.jsp is created that sets all required attributes and then calls original view.jsp renamed to view-original.jsp
It is not possible to access portlet request from servlet request, which makes custom metadata generators not possible.
WCM rendering portlets have complex rules when to get context path from different URL parameters, session, portlet settings or portlet data. Check original view.jsp. This article includes number of examples at the end. All of those have been proven on multiple customer projects
Servlet caching and Personalization
Caching is not possible without rules how to use ACLs. Use only group names for defining access controls. Create few groups for different kinds of users
Add additional attributes in view.jsp depending on user group. If combinations of groups are allowed create hash from group names (shown later). Add this hash as request attribute
WCM Personalized Caching...
- Global setting . will impact all portlets
- Not all portlets require personalization
- Not all portlets require the same personalization
- URL overrides not possible with portal
Servlet caching...
- Can be tailored for each portlet
- If portlet is displayed on multiple pages can cache just one instance
Caching scenario: Portal has two portles on front page. User can select local news for one of 20 cities, and industry news for any set of 10 industries.
With WCM personalized caching we would cache up to 20480 copies of combined list. If we split it to two portlets, and use Servlet caching only 1044 copies will be needed.
Forced invalidation of caches
As underlying mechanism for both WCM and Servlet cache is Object Cache, methods are very similar. What is different is creation of caching keys.
Getting cache instance...
DistributedMap cache = (DistributedMap) new
InitialContext().lookup("cachename");Example: Flush a cache
cache.clear();
Example: Remove an individual item from the cache
cache.invalidate((String)cacheKey);
Cache key generation: Servlet caching
All component names are used, semicolon is separator. When component value is null or empty string no value is included
Example:
CMPNTNAME1=;CMPNTNAME2=CMPNTVAL2
If "ignore-get-post" is not true:
METHOD=GET|POST
Additionally CHARSET=UTF8 or other
Cache key generation: WCM Caching
- Basic cache
All request parameters (includes querystring information)
REQUESTURI The url to the current page (without querystring information) CONTAINERURL Only used for connect tags, is the url to parent page As of today connect tags are supported. Their functionality will not be extended though, and their use is not recommended for new implementations.
- Site and Session advanced cache
- Processed: <ABSOLUTE_URL_&_QUERYSTRING>
- User advanced cache
- <WMM_MEMBER_ID_OF_CURRENT_USER>
- Processed: <ABSOLUTE_URL_&_QUERYSTRING>
- Secured advanced cache
- <DN_FOR_ALL_GROUPS_USER_BELONGS_TO> (Includes nested groups)
- Processed: <ABSOLUTE_URL_&_QUERYSTRING>
- Personalised advanced cache
- <DN_FOR_ALL_GROUPS_USER_BELONGS_TO> (Includes nested groups)
- <CATEGORIES_FOR_CURRENT_USER>
- <KEYWORDS_FOR_CURRENT_USER>
- Processed: <ABSOLUTE_URL_&_QUERYSTRING>
Automatic invalidation
Easy when no syndication is involved. Implement custom workflow stage. Implement servlet that will monitor for content in this stage. When anything found, push to next workflow stage and invalidate url
With syndication, you can add fixed delay, can check & compare. Much harder.
Automatic invalidation: dependency IDs
With portal frequently you need to update set of portlets. You might also need to manually remove content of all portlets in given category. It's hard to find specific content in Cache Monitor for large systems
Solution: Use Dependency IDs which is configured similarly to cache components.
Examples of dependency IDs
- Portal Page Title
- Portal Path
- WCM Site Area
WebSphere Edge Server components
- Network Dispatcher
- Load balancer operating on IP level
- Supports hot-standby configuration and automatic failover
- Uses response times and number of connections to balance
- Caching Proxy
- Reverse proxy
- No direct support for clustering
- It is possible to override caching headers, but better to do it on HTTP server
- Content Based Router
- TCP level equivalent of Network Dispatcher
- Plugin to Caching Proxy
- Gives CP ability to switchover between backend servers
Performance Tuning
- Basic tuning of JVM
- Servlet caching for WCM and portlets
- Caching proxy for static resources
Speedup - at least 10 times. Lot of things cached - less work for portal & WCM. Much lower usage of database connections. Less opportunities for memory leaks
Recommended Tools
- OpenSTA
This is small (8MB), efficient and free load testing tool. Lean testing makes testing after each change possible. Test takes 15 minutes.
- IBM PageDetailer
A graphical tool that enables Web content providers to rapidly and accurately measure client side performance of Web pages. Good for comparing "artificial" performance numbers of lean testing to end user experience.
- IBM Rational Performance Tester
Very powerful, big and complicated product. Much easier to use for user simulation than OpenSTA.
It's best used for full user simulation tests, as it's much easier to record and tune longer scripts than with OpenSTA. Also creates two separate performance graphs: for main requests and resource requests.
- Ethereal
Network protocol analyzer. After correctly enabling caching of LDAP objects and WCM portlets there should be almost no traffic to backend system during load test. It's good to check it this way.
- Theme & Skin Timers
These are described later. Essentially they show rendering time of each portlet on page and time used to completely render whole page.
You might be surprised which portlets take most of the rendering time. Generally it's not much worth to spend time on portlets taking less than 30ms to render with no load. Start with slowest one.
Typical rendering times
Simple WCM content 30ms Simple WCM menu 200ms Complicated presentation template 300ms & more WCM cached portlet 15ms Servlet cached portlet 3ms Lean Testing
No need to decide on arbitrary parameters
- Think times
- User tasks sequence
- Creation of test users
You get three important numbers
- Maximum responses per second
- Response time at that time
- CPU usage at that time
This test runs very fast. Reuse LTPA and sessions. Tune TCP/IP configuration at tester machine. Monitor loading machine CPU usage!
Graphs: Number of Users in Time
Every user runs the same script. New user added every 60 seconds. Two important graphs collected
- Number of requests per second
- Response time
Remember to monitor loading machine CPU and network. If 80% is reached you need to organize second or faster machine. Fast Ethernet is not THAT fast. Very easy to saturate
Summary
- Use tools
- PageDetailer to see what.s happening
- OpenSTA to see performance impact
- Timers to see where to concentrate your work
- Rational Performance Tester for final results
- Edge Components are always needed
- Portal by itself is very fast
- WCM without caching is very slow
- Caching proxy is blazingly fast
Recommended Resources
- IBM WebSphere Portal Version 6.0 Tuning Guide
- IBM WebSphere Portal Version 6.0 Web Content Management Tuning Guide
- Best Practices for using IBM Workplace Web Content Management V6.0
- Mastering DynaCache in WebSphere Commerce
Servlet caching
WCM content is served up by a View servlet. For example...
http://hostname:8080/wps/myportal/View?WCM_GLOBAL_CONTEXT=/Content/mycontent
To enable the servlet caching at the WebSphere layer, and reduce load at the WCM layer....
- Enable servlet caching in the WAS admin console...
Application servers | WebSphere_Portal | Web container | Enable servlet caching
- Create a servlet cache instance. Go to...
Resources | Cache Instances | Servlet Cache Instances | WebSphere_Portal as the scope | New
- Enter portlet-dynacache as the instance name and jndi/portlet-dynacache as the jndi name
- To cache content used by the local rendering portlet, deploy the cachespec.xml configuration file to the deployed local rendering portlet's WEB-INF folder...
wp_profile/installedApps/F32BC/PA_WCMLocalRendering.ear/ilwwcm-localrende.war/WEB-INF
- Rename the view.jsp file in...
wp_profile/installedApps/F32BC/PA_WCMLocalRendering.ear/ilwwcm-localrende.war/jsp/html
...to view-original.jsp
- Copy the attached view.jsp file in it's place
- Restart portal servers.
- To verify caching, use the cache monitor application and select the jndi/portlet-dynacache cache instance from the drop down to view the cache's statistics.
Servlet Caching - view.jsp
<%@ page session="true" contentType="text/html" %> <%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %> <portletAPI:init/> <% portletRequest.setAttribute("UNIQUE_ID", portletResponse.encodeNamespace(portletRequest.getUser()==null?"":.anonymous")); java.lang.StringBuffer sb = new java.lang.StringBuffer(); // Build paging list from all WCM_Page.<MenuID>=<PageNum> parameters java.util.Map params = portletRequest.getParameterMap(); for(java.util.Iterator i = params.keySet().iterator();i.hasNext();) { String key = (String) i.next(); int k = key.indexOf("WCM_Page."); if(k>=0) { // Store just menu IDs and page numbers sb.append(key.substring(k+9)); sb.append("="); sb.append(params.get(key)); sb.append(";"); } } // If we have any pagers, add them to cache id if(sb.length() > 0) portletRequest.setAttribute("PAGE",sb.toString()); %> <jsp:include page="view-original.jsp"/>Servlet Caching - cachespec.xml
<?xml version="1.0" ?> <!DOCTYPE cache SYSTEM "cachespec.dtd"> <cache> <cache-instance name="jndi/portlet-dynacache"> <cache-entry> <class>servlet</class> <name>/jsp/html/view-original.jsp</name> <sharing-policy>shared-push</sharing-policy> <property name="save-attributes">false</property> <property name="ignore-get-post">true</property> <property name="consume-subfragments">true</property> <cache-id> <component id="UNIQUE_ID" type="attribute"> <required>true</required> </component> <component id="WCM_GLOBAL_CONTEXT" type="parameter"> <required>false</required> </component> <component id="PAGE" type="attribute"> <required>false</required> </component> <timeout>150</timeout> <metadatagenerator> com.ibm.pl.fz.randomcacher.RandomCacher </metadatagenerator> </cache-id> </cache-entry> </cache-instance> </cache>Group Based Personalization - view.jsp
// Create MD5 hash for group based personalization/ACLs String grd = (String)portletRequest.getSession().getAttribute("GRD"); if(grd == null) { User user = (User)portletRequest.getUser(); MessageDigest md = MessageDigest.getInstance("MD5"); List sorted = new LinkedList(); for(Iterator i = user.getGroups ().iterator(); i.hasNext();) { Group group = (Group)i.next(); sorted.add(group.getName()); } for(Iterator i = sorted.iterator(); i.hasNext();) { String name = (String) i.next(); md.update(name.getBytes()); } byte[] digest = md.digest(); StringBuffer hex = new StringBuffer(); for (int i = 0; i < digest.length; i++) { hex.append(Integer.toHexString(0xFF & digest[i])); } portletRequest.getSession().setAttribute("GRD", hex.toString()); }Multiple Caching Policies
It is worth having multiple WCM portlets on pages:
- Different caching policies
- Some elements are static, rarely change
- Some change frequently
Need to balance number of views with expiration times. Can be accomplished in two ways:
- Use individual UNIQUE_ID values for portlets in cachespec.xml
- Use something else: categories
Multiple Caching Policies - view.jsp
// Get listensTo attribute from WCM config String listensTo = (String) portletRequest.getData().getAttribute("WCM_LISTENS_TO"); if(listensTo==null) { listensTo = (String) portletRequest.getPortletSettings().getAttribute("WCM_LISTENS_TO"); } portletRequest.setAttribute("LISTENS_TO",listensTo); // Get caching policy from WCM categories String cachePolicy = (String) portletRequest.getData().getAttribute("CATEGORY_OVERRIDE"); if(cachePolicy==null || cachePolicy.equals("")) { cachePolicy = "DEFAULT"; portletRequest.setAttribute("CACHE_POLICY",cachePolicy); }Multiple Caching Policies - cachespec.xml
<?xml version="1.0" ?> <!DOCTYPE cache SYSTEM "cachespec.dtd"> <cache> <cache-instance name="jndi/portlet-dynacache"> <cache-entry> <class>servlet</class> <name>/jsp/html/view-original.jsp</name> <sharing-policy>shared-push</sharing-policy> <property name="save-attributes">false</property> <property name="ignore-get-post">true</property> <property name="consume-subfragments">true</property> <cache-id> <component id="UNIQUE_ID" type="attribute"> <required>true</required> </component> <component id="CACHE_POLICY" type="attribute"> <required>true</required> <value>DEFAULT</value> </component> <timeout>150</timeout> </cache-id> <cache-id> <component id="UNIQUE_ID" type="attribute"> <required>true</required> </component> <component id="CACHE_POLICY" type="attribute"> <required>true</required> <value>5876533A56C765EA6</value> </component> <timeout>3000</timeout> </cache-id> </cache-entry> </cache-instance> </cache>Metadata Generator: Random Caching Time
package com.ibm.pl.fz.randomcacher; import javax.servlet.http.HttpServletResponse; import com.ibm.websphere.servlet.cache.CacheConfig; import com.ibm.websphere.servlet.cache.FragmentInfo; import com.ibm.websphere.servlet.cache.MetaDataGenerator; import com.ibm.websphere.servlet.cache.ServletCacheRequest; public class RandomCacher implements MetaDataGenerator { public void initialize(CacheConfig cc) {} public void setMetaData(ServletCacheRequest scr, HttpServletResponse hsr) { FragmentInfo fi = scr.getFragmentInfo(); int timeout = fi.getTimeLimit(); int rtimeout = timeout+(int)Math.round(timeout*Math.random()); fi.setTimeLimit(rtimeout); } }Handle WCM_GLOBAL_CONTEXT - view.jsp
// Get listensTo attribute from WCM config String listensTo = (String) portletRequest.getData().getAttribute("WCM_LISTENS_TO"); if(listensTo==null) listensTo = (String) portletRequest.getPortletSettings().getAttribute("WCM_LISTENS_TO"); String contextPath = null; String portlet = portletRequest.getParameter("WCM_PORTLET"); if(listensTo.equals("WCM_LINKING_SELF") && portlet != null && portlet.equals(portletResponse.encodeNamespace("WCM"))) { contextPath = (String) portletRequest.getParameter(portletResponse.encodeNamespace("WCM_CONTEXT")); } if(contextPath==null && !listensTo.equals("WCM_LINKING_NONE")) { contextPath = (String) portletRequest.getParameter("WCM_GLOBAL_CONTEXT"); if(contextPath!=null) portletRequest.getSession().setAttribute("WCM_CONTENT_CONTEXT", contextPath); } if(contextPath==null) contextPath = (String) portletRequest.getSession().getAttribute("WCM_CONTENT_CONTEXT"); if(contextPath==null) contextPath = (String) portletRequest.getData().getAttribute("WCM_CONTENT_CONTEXT"); if(contextPath==null) contextPath = (String) portletRequest.getPortletSettings().getAttribute("WCM_CONTENT_CONTEXT"); portletRequest.setAttribute("WCM_GLOBAL_CONTEXT",contextPath);Get current page ID - view.jsp
String customID = (String) portletRequest.getPortletSettings().getAttribute("CID"); if(customID==null || customID.equals("")) customID = (String) portletRequest.getData().getAttribute("CID"); if(customID==null || customID.equals("")) { portletRequest.setAttribute("UID", portletResponse.encodeNamespace("")); ModelUtil util = com.ibm.wps.model.ModelUtil.from(request); NavigationNode node = (NavigationNode)util.getNavigationSelectionModel().getSelectedNode(); MetaData iMetaData = ((MetaDataProvider)node).getMetaData(); Object internalPageName = iMetaData.getValue("InternalPage"); if (internalPageName != null) { portletRequest.setAttribute("PORTAL_PAGE", internalPageName); } else { portletRequest.setAttribute("CID", customID); } }Dependencies and multiple caching policies
<cache-id> <component id="UID" type="attribute"><required>true</required></component> <component id="ANON" type="attribute"><required>true</required></component> <component id="WCM_GLOBAL_CONTEXT" type="attribute"><required>true</required></component> <component id="PAGE" type="attribute"><required>false</required></component> <timeout>86400</timeout> <metadatagenerator>com.ibm.pl.fz.randomcacher.RandomCacher</metadatagenerator> </cache-id> <cache-id> <component id="CID" type="attribute"><required>true</required></component> <component id="ANON" type="attribute"><required>true</required></component> <timeout>864000</timeout> <metadatagenerator>com.ibm.pl.fz.randomcacher.RandomCacher</metadatagenerator> </cache-id> <dependency-id>CID <component id="CID" type="attribute"><required>true</required></component> </dependency-id> <dependency-id>CTX <component id="WCM_GLOBAL_CONTEXT" type="attribute"><required>true</required></component> </dependency-id> <dependency-id>PP <component id="PORTAL_PAGE" type="attribute"><required>true</required></component> </dependency-id>Network Dispatcher Configuration
dscontrol executor start dscontrol executor set clientgateway 192.168.1.1 dscontrol executor set staletimeout 30 dscontrol executor set fintimeout 30 dscontrol highavailability heartbeat add lb01 lb02 dscontrol highavailability backup add primary manual 3333 dscontrol cluster add www.cluster.com dscontrol port add www.cluster.com:80 method mac porttype tcp reset yes dscontrol server add www.cluster.com:80:cp01 dscontrol server add www.cluster.com:80:cp02 dscontrol server add www.cluster.com:80:http01 dscontrol server add www.cluster.com:80:http02 dscontrol rule add www.cluster.com:80:primary type true priority 1 dscontrol rule add www.cluster.com:80:backup type true priority 2 dscontrol rule useserver www.cluster.com:80:primary cp01 dscontrol rule useserver www.cluster.com:80:primary cp02 dscontrol rule useserver www.cluster.com:80:backup http01 dscontrol rule useserver www.cluster.com:80:backup http02 dscontrol executor configure www.cluster.com dscontrol manager start dscontrol manager smoothing 10 dscontrol advisor start http www.cluster.com:80 dscontrol advisor interval http www.cluster.com:80 3Content Based Router Configuration
cbrcontrol executor start cbrcontrol cluster add www.cluster.com cbrcontrol port add www.cluster.com:80 cbrcontrol server add www.cluster.com:80:http01 \ advisorrequest "GET /wps/portal HTTP/1.1\r\nHost: www.cluster.com" \ advisorresponse "HTTP/1.1 200 OK" cbrcontrol server add www.cluster.com:80:http02 \ advisorrequest "GET /wps/portal HTTP/1.1\r\nHost: www.cluster.com" \ advisorresponse "HTTP/1.1 200 OK" cbrcontrol rule add www.cluster.com:80:http1 type true priority 1 cbrcontrol rule add www.cluster.com:80:http2 type true priority 2 cbrcontrol rule useserver www.cluster.com:80:http1 http01 cbrcontrol rule useserver www.cluster.com:80:http2 http02 cbrcontrol manager start cbrcontrol manager smoothing 10 cbrcontrol advisor start http www.cluster.com:80 cbrcontrol advisor interval http www.cluster.com:80 3Caching proxy configuration
On the WebSphere Edge Server, edit ibmproxy.conf, and set...
Proxy /wps/* http://www.cluster.com/wps/* :80
Redirect / http://www.cluster.com/wps/portal :80
CacheMinHold http://* 30 minutes
AggressiveCaching http://*
CacheQueries Always http://* 30 minutes
NoCaching http://*/wps/myportal*
NoCaching http://*/wps/portal*
CacheExpiryCheck off
ServerConnPool on
ProxyPersistence on
CacheMemory 512 M
MaxContentLengthBuffer 500 K
KeepExpired onCaching Proxy configuration contains lots of comments. You need to locate proper places for above configuration directives.
Remember to remove comments from CBR plugin initialization lines!
HTTP Server Configuration
LoadModule headers_module modules/mod_headers.so
Header set Cache-Control publicThis will make all items cacheable.
Set NoCaching directives for dynamic pages.
Skin Timer
Following code added around portletRender tag in Control.jsp of each skin<div style="border: 1px solid red; padding 2px;"> <% long start = java.lang.System.currentTimeMillis(); %> <wps:portletRender.> . </wps:portletRender> <div style="color: red; padding: 4px; border: solid red; ">Theme Timer
Following code added in Default.jsp
<body> <% long pagestart = java.lang.System.currentTimeMillis();%> . <div style="color: red; padding: 4px; border: solid red;"> <%= java.lang.System.currentTimeMillis() - pagestart %>ms </div> </body>Addenda
Q: In a multi-server configuration with Dynacache and caching proxies installed, is there a requirement that when a bridge is published? Do we need to invalidate the caches? What should we be doing and what is the approach to doing it?
A: There is no remote API for the caching proxy to invalidate cache items. What you can do is whenever content like images are being changed, make sure you also change the file name.
Q: Does a hardware solution exist that increases [caching] performance?
A: Yes, load balancers and caching proxies on dedicated hardware can help.
Q: Have you seen any caching performance enhancing hardware solutions, or can you recommend any?
A: I have seen several in production, however per policy I can not recommend one specific brand.
Q: Does syndication have any impact on basic or advanced caching?
A: Yes
Q: In our current WCM 5.1 environment with over 15,000 items, a consulting portal architect designed a custom portlet with a custom cache map that boosted performance. Is this a sound approach?
A: It can be. For detailed discussion, listen to audio recording.
Q: Can we use the HTTP servers' caching capability instead of caching proxies?
A: Recommend proxies. HTTP caches mix poorly with WebSphere plug-ins.
Q: We use Personalization heavily in our environment. Is it still better to use the user Advanced Setting rather than none at all?
A: The only drawback of enabling the advanced cache Setting is you might run out of Application Server memory
Q: We use our own Java code in the back end. Would that still work with caching?
A:Yes.
Q: We have an authoring server on WCM version 5.1. Would I need to set up caching on that server as well, or just on servers to which we syndicate?
A: From a usability perspective, it is preferable to not have caching on the authoring server, as it may confuse the authors.
Q: Is servlet caching valid for WCM specific pages, such as if I have two pages in the same site area and I put a JSP in one of those pages drawing dynamic content, for example, cookie information? Is servlet caching valid for caching those types of pages?
A: Yes, you can set the Personalization Cache ID to depend on the cookie value
Q: Do you recommend servlet caching over basic or advanced WCM caching?
A: With cookies, you can do either
Q: As a follow-up to the previous question about syndication wiping out caches, does that happen unilaterally or only to items syndicated?
A: Not sure everything is cleared. Please ask this question via the User Forum, so we can follow up with detailed answers.
Q: Do you have recommended best practices for incorporating edge components?
A: Depends on size of deployment
Q: In one slide you showed a WCM server running Portal. Is that valid?
A: You have to run Portal all the time
Q: With reference to WCM Advanced Caching, how would we invalidate individual cached items in a production server running in a cluster? It was mentioned that there is no way to tell when the syndication process has run, therefore do we have to flush the entire cache? We cannot use the workflow invalidation to programmatically remove these cached items because we author on a separate node in a separate environment which syndicates to a publishing server. If we syndicate every ten minutes, do we have to flush the ENTIRE cache every ten minutes?
A: This advanced caching task is not easy to achieve in such a configuration. You might use the workflow-based solution, but there will be a delay in sending invalidations by the time it usually takes to perform syndication. However, I have seen such solutions working at customer sites. Also remember, that most of cache items will automatically be removed from cache after timeout, or LRU eviction from cache.
Q: In a stand-alone WCM environment (no WebSphere Portal), how do we cache a page for best performance but ensure that the JSP is not cached? We have a JSP (WCM JSP Library Component) embedded within a WCM page, Should we use a
tag to NOCACHE the JSP component or some other method? A: To disable caching for a specific included JSP, you need to create an additional entry in the cachespec.xml file for this JSP and disable caching by adding the property do-not-cache=true. Examples are given in "Mastering DynaCache in WebSphere Commerce" RedBook on page 199.
Q: Instead of using a caching proxy, can we cache on the HTTP server?
A: It is generally possible to configure the WebSphere Plugin to cache content inside the HTTP server using cachespec.xml files. I personally find a caching proxy much easier to configure and to manage than the plugin/esi invalidator combination. The use of proxy and cache modules together with a plugin does not seem to work correctly.
Q: If you have an authoring server, do you need to configure caching there or on the "receiving" server, or on both?
A: It is not recommended to configure caching on an authoring server. It is a best practice to only enable caching on a delivery and receiving server.
Q: Where can we download the page and theme timers?
A: Those timers are small JSP snippets, included in the presentation reference section.
Q: Does syndication wipe the cache only for the syndicated items or for all items?
A: Syndication heavily affects low level WCM caches. By default, after the syndication of each item the caches are cleared. You can delay this cache flushing by using the following options...
render.cache.delaysyndicationflush = true
render.cache.syndicationclearthreshold = 200 # Size of partial cache flush during syndication...in WCMConfigService.properties. This setting does not affect WCM advanced, basic and servlet caches.
Parent topic
Caching options