Level: Introductory Darl Crick (crick@ca.ibm.com), Software Architect, IBM Michael Rabbior (mrabbior@ca.ibm.com), Software Engineer, IBM
06 Apr 2006 Updated Jan 2008 This article describes how to configure caching and optimize performance when using the WebSphere® Commerce marketing campaign engine in three simple steps.
Introduction
The features of the marketing campaign engine are functionally rich and can require a large amount of
resources to execute. It is important that a system running the marketing campaign engine uses as much caching
as possible to optimize the system's performance. It is also important to balance the feature and option you
are going to use versus the performance of the system and the resources required. By spending time to configure
caching for the marketing campaign engine, you can improve performance in the order of 20
times. The CPU utilization on a WebSphere Application Server will decline significantly, and the CPU on the
database server will show reduced utilization. Furthermore, after you have configured the new cacheable command
for the marketing campaign business logic and cached the JSP used to display the marketing content, you can use
the features of the marketing campaign engine while maintaining optimal performance on your system. The main
value is taking advantage of the functionally rich marketing campaign engine without having to sacrifice significant
capacity or performance.
This article shows how to configure your system to take advantage of the changes made to the product.
We have found this process enables the most effective caching along with enabling functionally rich features.
In our experience, using this methodology gives you the biggest return for your invested time. At each step of the
process, we address what does this step do, how do we do it, and why do we bother. The article assumes you are familiar with the basics of caching and the features of the marketing campaign engine.
This article is not a comprehensive resource on all things caching. There are DynaCache techniques and methods not covered in this document that are more appropriate for your specific scenario. For more information on these
techniques, see Tutorial: Improve WebSphere Commerce performance with dynamic caching
and Caching
WebSphere Commerce pages with the WebSphere Application Server dynamic cache service. The assumption
is that the current site is using request servlet (full page) caching for pages that contain the marketing initiatives.
Step 1. Caching the marketing campaign engine logic
Why
The marketing campaign engine executes queries against the database to determine
the marketing initiatives that the user qualifies to see. It does this on each request to the system that involves this feature. It then uses this result to display the appropriate content.
By command caching, you remove the execution of the Java™ code and
database lookups on each request involving this feature. Only the code that needs to track information about the campaign will execute.
What
Command caching is a feature that allows you to cache the result of a command execution so that the result is returned without actually having to execute the code within the command.
How
You can create a cache-entry for the marketing campaign engine command using the command name and parameters or attributes. You can only have one cache-entry per command name.
Here is an example of a cache-entry that uses to cache the marketing campaign engine command:
<?xml version="1.0"?>
<!DOCTYPE cache SYSTEM "cachespec.dtd">
<cache-entry>
<class>command</class>
<sharing-policy>not-shared</sharing-policy>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeEvaluateCmdImpl.class </name>
<cache-id>
<component type="method" id="getEMarketingSpotName">
<required>true</required>
</component>
<component type="method" id="getMaximumNumberOfAssociateCatalogEntries">
<required>true</required>
</component>
<component type="method" id="getMaximumNumberOfCatalogEntries">
<required>true</required>
</component>
<component type="method" id="getMaximumNumberOfCategories">
<required>true</required>
</component><component type="method" id="getMaximumNumberOfCollateral">
<required>true</required>
</component>
<priority>1</priority>
</cache-id>
<dependency-id>eSpot</dependency-id>
<dependency-id>DC_userId</dependency-id>
</cache-entry>
|
Step 2. Caching the display portion of the marketing campaign logic
Why
Caching the display portion of the promotion logic also improves performance because it reduces database lookups.
This removes the execution of the Java code needed to build the display fragment associated to a particular set of
marketing assets. Keep in mind that the more pieces there are to assemble into a page, the longer it takes to retrieve entries from the cache.
What
The personalized content, or content that changes depending on the circumstances, needs to be in a JSP
fragment that is dynamically included by a parent page. This fragment is cached as individual cache entries, each
representing a single permutation and combination of marketing collateral the fragment can display.
How
The first step in caching the personalized content of an eMarketingSpot defines a mapping between the URL request the client makes and the eMarketingSpots that the request will cause to be evaluated. This allows the marketing runtime to determine what the eMarketingSpot will display before the fragment will be run. This allows the marketing runtime to generate a cache key that represents the exact display result of the eMarketingSpot.
Here is an example from the xml/campaigns/cache/eMarketingSpotInvocationList.xml file where the mappings are stored:
<?xml version="1.0" encoding="UTF-8" ?>
<EMarketingSpotInvocationList>
<StoreUsage storeId="0">
<EMarketingSpotInvoker name="TopCategoriesDisplay"
eMarketingSpotName="StoreHomePage"
maxAssociateCatalogEntries="20"
maxCatalogEntries="20"
maxCategories="20"
maxCollateral="20"/>
</StoreUsage>
<StoreUsage storeId="10001">
<EMarketingSpotInvoker name="*" eMarketingSpotName="SideBar"/>
</StoreUsage>
<StoreUsage storeId="10001">
<EMarketingSpotInvoker name="OrderItemAdd" eMarketingSpotName="SideBar"/>
</StoreUsage>
</EMarketingSpotInvocationList>
|
A StoreUsage element with a storeId of 0 indicates that the mappings defined within the element are applicable to all stores. A mapping with a name of "*" indicates the eMarketingSpot will be evaluated for every request to a store URL. Every time a request is made to a mapped eMarketingSpot, an attribute is added to the request name EMS_<emsName> that is used as a cache key for the fragment.
With this mapping file configured, an eMarketingSpot fragment can now be cached separately from its parent page. To do this, add an entry to cachespec.xml for the fragment. This entry must have the consume-subfragments property set to "false" so that it is not consumed with the parent JSP.
Here is an example from the sample cachespec.xml that caches the eMarketingspotDisplay.jsp separately from its parent page for an eMarketingSpot named <emsName>.
<cache-entry>
<class>servlet</class>
<name>/ConsumerDirect/include/eMarketingDisplay.jsp </name>
<property name="save-attributes">false</property>
<property name="store-cookies">false</property>
<property name="save-attributes">false</property>
<property name="do-not-consume">true</property>
<sharing-policy>not-shared</sharing-policy>
<cache-id>
<component id="storeId" type="parameter">
<required>true</required>
</component>
<component id="catalogId" type="parameter">
<required>true</required>
</component>
<component id="EMS_<emsName>" type="attribute">
<required>true</required>
</component>
</cache-id>
<dependency-id>eSpot</dependency-id>
</cache-entry>
|
You must have an entry made for each fragment you wish to cache separately.
The fragment being excluded must be self-executing, and cannot depend on attributes set by the parent JSP.
However, it can use the attribute from the marketing campaign engine because these attributes
will not be set for you on each request that involves a campaign. To determine if
the fragment is self-executing after the cachespec.xml is configured, hit the servlet's page. Next, use the
cachemontor to invalidate the child fragment. Then, execute the page request to confirm the execution of the fragment
is successful. If so, that fragment is self-executing. Note that not all fragments in WebSphere Commerce are
self-executing.
The cache-entry for the parent servlet contains values for those parameters passed into the fragment using the
jsp:include or c:import tags. This means that on a cache hit, the parameters passed from the parent to the fragment
are not regenerated. To pass new values to the fragment, you must invalidate and then re-execute the parent
JSP.
After creating the necessary cache policies the campaign caching component in WebSphere Commerce, enable
the instance configuration XML. To do this, locate the CampaignsCachingComponent in the instance configuration
XML, and set the enable attributes to "true". The component XML looks like the following example:
<component
compClassName="com.ibm.commerce.campaigns.cache.CampaignsCachingComponent"
enable="true" name="CampaignsCachingComponent">
<property display="true">
<start enabled="true"/>
</property>
</component>
|
When enabled, this component allows the campaigns runtime to support caching JSP fragments that contain the campaign content.
Step 3. Invalidating the marketing campaign engine command and JSPs
Why
We encourage defining invalidation rules to automate the invalidation of cache entries. If you do not have
invalidation rules configured, then you need to invalidate all of the cache when content changes. This means that
everything will be removed from the cache, and not just the changed pages. We do not recommend the invalidation of the complete cache. It may be common for the business user to change
the campaigns that they are running, and after that has been done, they will expect the system to change
immediately. The business user cannot invalidate the cache in order to have the site reflect their changes.
What
The simplest way to invalidate cache entries associated to the marketing campaign engine is to use the
command-based invalidation. This method is useful for changes made by the tooling provided to update the campaigns
in the system. The execution of the tools commands to update the system are used to invalidate the promotion cached command and JSP.
You can also invalidate entries in the cache through the cache monitor, but automating the invalidation reduces the risk of someone invalidating the wrong content.
A final way to configure automatic cache invalidation is using the CACHEIVL table in combination with database triggers or with an insert statement.
How
To trigger cache invalidation by a command, you must first declare dependency IDs for the cache entries
you want to invalidate. The dependency IDs represent the components that, should they change, invalidate the
content of this cache-entry. The following sample shows the cache-entry for an eMarketingSpot fragment, including the possible dependency ID:
<cache-entry>
<class>servlet</class>
<name>/ConsumerDirect/include/eMarketingDisplay.jsp </name>
<property name="save-attributes">false</property>
<property name="store-cookies">false</property>
<property name="save-attributes">false</property>
<property name="do-not-consume">true</property>
<sharing-policy>not-shared</sharing-policy>
<cache-id>
<timeout>3600</timeout>
<component id="storeId" type="parameter">
<required>true</required>
</component>
<component id="catalogId" type="parameter">
<required>true</required>
</component>
<component id="EMS_<emsName>" type="attribute">
<required>true</required>
</component>
</cache-id>
<dependency-id>eSpot</dependency-id>
</cache-entry>
|
Next, we need a command that is recognized by the dynamic cache. You must write this command to the
WebSphere Command Framework: its implementation class must extend from CacheableCommandImpl
(in the com.ibm.websphere.command package). To simplify command writing for command-based invalidation,
WebSphere Commerce has updated the abstract classes, ControllerCommandImpl, and TaskCommandImpl to extend
from CacheableCommandImpl. Any commands extend from these abstract classes also extends from
CacheableCommandImpl. Therefore, they are eligible for command-based invalidation.
Finally, make an entry for the command in your cachespec.xml that contains definitions for the invalidation IDs
you want to generate. The sample below listens for the WebSphere Commerce commands that indicate changes to an
order and generates invalidation IDs to invalidate the cache entries with matching dependency IDs:
<cache-entry>
<class>command</class>
<sharing-policy>not-shared</sharing-policy>
<name>com.ibm.commerce.tools.segmentation.SegmentAddUserControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentDuplicateControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentRemoveUserControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeDisableControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeScheduleDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeScheduleSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignCollateralDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignCollateralSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignCollateralUpdateCmdImpl</name>
<name>com.ibm.commerce.tools.epromotion.commands.RLPromotionDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.epromotion.commands.RLPromotionPublishControllerCmdImpl</name>
<name>com.ibm.commerce.tools.epromotion.commands.RLPromotionSaveControllerCmdImpl</name>
<invalidation>eSpot</invalidation>
</cache-entry>
|
Notes:
- To invalidate, the eMarketingSpot must have a dependency ID that matches the invalidation ID being generated. The sample eMarketingSpot entry is invalidated in this case.
- The list of commands above is only a sample of the commands that might be needed to invalidate the cache in some cases. Make sure to include all other commands required when eMarketingSpot cache entries depend on business objects that are not touched by the commands above.
A final way to invalidate cache content is by making entries to the CACHEIVL table. You can change the frequency
of the DynaCacheInvalidation command by referring to the documentation on the scheduler in the
WebSphere Commerce Administration Guide on how to edit, delete, and schedule a new job. The WebSphere
Commerce scheduler runs a DynaCacheInvalidation command at a set interval. This command processes the entries
in the CACHEIVL table as follows:
- The "clearall" string value in the TEMPLATE or DATA_ID columns of the CACHEIVL table is used by DynaCacheInvalidation to clear the cache by dynamic cache invalidation API (clear).
- If the TEMPLATE column is set, then the DynaCacheInvalidation command calls the dynamic cache
invalidation API (invalidateByTemplate) and uses the name as the template ID. If the "clearall" string
value (which is case insensitive) is found in TEMPLATE column, then the DATA_ID column is ignored and the
DynaCacheInvalidation command clears the cache. If the TEMPLATE column is not empty, the command
invalidates by the template ID, ignoring the DATA_ID column.
- If the DATA_ID column is set and the template name is not set, then the DynaCacheInvalidation command
calls the dynamic cache invalidation API (invalidateById) and uses the DATA_ID as the ID. If the TEMPLATE
column is empty and the "clearall" string value is found in the DATA_ID column, then the command
clears the cache.
- When the dynamic cache invalidation API is called, it invalidates the cache entries.
This is a sample insert to invalidate the marketing campaign engine command and JSP:
INSERT INTO cacheivl (template, dataid, inserttime) values (NULLIF('A', 'A'),
'eSpot', CURRENT TIMESTAMP);
|
You are not restricted to one of the invalidation techniques mentioned. Your cache invalidation setup can combine
any or all of them to ensure that you can achieve the necessary invalidation for your system.
Conclusion
The WebSphere Commerce Performance and Marketing development teams have developed a methodology that
configures caching when using the features of the marketing campaign engine. In our experience, these three steps
achieve optimal performance. At each step, we have explained what motivation lies behind it, and how you too can
accomplish what we have set out to do.
Resources Learn
Discuss
About the authors  | |  |
Darl Crick is the Chief Architect for WebSphere Commerce Performance and Business Runtime at the IBM Toronto Software Lab, Canada.
|
 | |  |
Michael Rabbior is the Technical Team Lead for WebSphere Commerce Marketing and Merchandising at the IBM Toronto Software Lab, Canada. |
Rate this page
|