Tuesday, August 07, 2012

Performance Tuning Webcenter Portal

There are so many elements that can impact the portal performance, I tried to compile a list of points and sources you can look at, hopefully it'll be helpful to someone out there...

1) HTTP Resources


WebCenter Portal pages, as well as Webcenter Content and any other web page for that matter, load to the browser, not only the generated HTML of the page, but a set of resources that help display it correctly, this include CSS files, JS libraries, Images, etc. This resources can be big and slow down the page. one of the first things you should do when looking at improving performance, it's to try to minimize the network traffic and latency needed to load these resources, when you thing about it, they seldom change and they are generally common to all the pages, so the best way to approach the issue is to look at three rules:


  • Caching, your browser is capable of caching most of these resources, this will ensure the page is loaded faster and reduce network traffic. you can set headers in the web tier to tune you max-age and tell the browser how long to cache the items.
  • Reduce Size, CSS and JS files often contain spaces , comments and formatting gaps that allows us to understand the files when developing, for production environment however, you should trim all spaces and comments, and produce optimized version of these assets, this will reduce the size of the documents.  Another thing you should consider to reduce the size, is to enable compression at the Web tier level, Apache can do this by using mod_deflate, if you are using Oracle Web Cache you can also configure it to provide compression for your files
  • Avoid unnecessary  resources: ensure you don't load unnecessary CSS or JS files, also try creating a single image for all your icons and use css positioning to display them, another thing to look at is to ensure you don't have nay 404 errors when loading the page, this are mainly pointers to resources removed from the server or misspelled.

A couple of resources to look at, if you want to configure the HTTP server:

https://blogs.oracle.com/ATEAM_WEBCENTER/entry/improving_webcenter_performance

If you want to use webcache:
http://www.oracle.com/technetwork/middleware/webcenter/webcenter-webcache-integration-176984.pdf


Here is an example of how the webcenter entry looks after following the compression and caching methods



SetHandler weblogic-handler
WebLogicCluster MYCLUSTER:PORT
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom_xml
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|bmp|ico)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:pdf|doc?x|ppt?x|xls?x)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.avi$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.mov$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.mp3$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.mp4$ no-gzip dont-vary

for resources caching:


Header unset Last-Modified
Header unset Expires
Header set Cache-Control "max-age=2592000, public"
Header set Surrogate-Control "max-age=2592000"
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/css
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary


2) JVM Memory

Heap Size
First of all you want to ensure the JVM has enough resources to work, this will depend entirely on your implementation, but you will want to allow the heap size to be between 2-3 GB, if your application requires more memory (you will be able to tell by the number of garbage collections and/or if you get the old java.outofmemory in the logs) consider spreading the load to another JVM instead of just increasing the heap size. You can clone the manage server and configure a cluster via weblogic.

Oracle provides a good set of recommendations regarding this at:

http://docs.oracle.com/cd/E17904_01/core.1111/e10108/webcenter.htm#BABEJCDE

To increase the heap size in the JVM to 2gb, for example, add the following to the start arguments of the managed server:

-Xms2048M -Xmx2048M -Xns512M

Weblogic mode

Another thing to consider is to enable the production mode in the weblogic domain, this adds additional security ad disables add-hot deployments from jdev, but also sets internal optimizations to the JVM 
 
-Dweblogic.ProductionModeEnabled=true

3) ADF Resources


ADF creates specific resources in the system for each page, and user, this resources represent the view and control page of the pages, and are loaded into the memory, you need to ensure the size of these memory objects doesn't grow exponentially when you add load to the system, also, when you have a hybrid navigation, for example your site needs to navigate between the webcenter application and static content deliever by another app like UCM site studio, or if you have a WebCenter portal application delievering your pages and Webcenter Spaces delievering the micro sites (you may want to consider this setup as the pages will run faster in the custom portal than in spaces), then the view and state objects are lost and left in the memory and need to be cleaned up by the system.

Cleanup Inactive Objects

To tune the clean up of these objects, you can set a few parameters in the startup arguments of your JVM

-Djbo.ampool.maxinactiveage=180000

This parameter defines how long an object can be inactive in the memory before it is tagged to be removed by the garbage collection

-Djbo.ampool.monitorsleepinterval=90000
This one defines how often to sweep the memory looking for inactive objects

Be aware however that this parameters also govern the pooling of connections to the database and other objects ADF reuses, so you need to find the right balance for your implementation. a good reference of these parameters and overall ADF tuning can be fond here:

http://www.oracle.com/technetwork/developer-tools/jdev/adfbc-perf-and-tuning-095672.html

HTTP Session

Another parameter that governs the re-usage of objects in memory and their life spam is the HTTP session, for your portal application you can modify the time out in the web.xml, the default value is 45 mins, reducing the time will free up memory however the users may get annoyed by the timeout if too low, again you need to find the right valance for your implementation

View and Control States

The view and control states in the memory are also mantain for multiple pages as the user navigates, this allows the back button on the browser to work, the problem is that the more pages the users navigates throught and the more users will increase the memory usage, The number of pages to mainain in memory for the user session can be control by the CLIENT_STATE_MAX_TOKENS in the web.xml of the application, spaces usually defaults to 15, while custom portals to 3. the lower the value the less memory required for each user, this also depends on your implementation and if you need the users to use the back button to navigate, also if you have a hybrid navigation as described before, it's better to set a low value. also consider the points in the following blog note about this setting:

http://andrejusb.blogspot.com.au/2011/07/adf-view-state-tuning-for-large.html


You should also set the view state to be compressed to reduce the size, this is controlled by the COMPRESS_VIEW_STATE setting in the web.xml

Performance Testing

Also, if you are doing performance or stress test for your implementation (and you should), make sure that the test scripts maintain these view and control states, otherwise you will end up with bogus memory leak results, a good reference for stress testing can be found here:

http://www.oracle.com/technetwork/developer-tools/adf/learnmore/adfloadstresstesting-354067.pdf




4) Data Sources


LDAP Tuning

Ensure the communication with your LDAP server, either OID or AD is good and that the server can handle the queries generated by webcenter, there are a couple of settings Oracle recommeds for OID here :

http://docs.oracle.com/cd/E21764_01/webcenter.1111/e12405/wcadm_security_id_store.htm#BGBGIAHC


JDBC pooling for read-only taskflows


For the tasklflows that are display on your portal pages, it is important understand the DB requirements, in most cases, these taskflows haev a read-only behaviour providing a snapshot of information and allowing the users to open another page or application where they can perform more actions, if this is the case, your DB connections don't need to maintain the transactions, and they perform small queries and can be release back to the pool as soon as they finish, usually in a portal scenario you have mainly read-based transactions in a common page displaying simultaneously, so one user calling one page can potentially set hold to more than 5 connections, also there are several performance considerations, so one of the key points for this type of TF in the page is to set the  following JDBC pooling options in the Application Module:

  • jbo.doconnectionpooling = true
  • jbo.txn.disconnect_level = 1

There are a couple of good articles about the benefits and trade-off of this configuration one of the more comprehensive ones is at:

http://andrejusb.blogspot.com.au/2011/10/adf-bc-tuning-with-do-connection.html

Also avoid XA drivers...

Web Services

Web Services are usually expensive transactions that gather data from multiple sources, ensure you cache some of the heavy resources, use coherence it's embed in the SOA suite and can significally reduce the time of the request

5) Taskflows


Only load what you need to


Your page will be as fast as your slowest TaskFlow, with this in mind you need to ensure the page does not need to wait for any taskflows or data sources that will take a long time. a few things to keep in mind:


  • Avoid Loading unnecessary taskflows: It is common to have taskflows in the page that are not loaded to all users or are loaded only upon certain conditions, this will also apply to pages with tabs,  you generally will use the "rendered" option to hide the taskflow, unfortunately, while this hides the taskflow from the View object of the page, the bindings still exists and will need execute before the page is displayed to the user, ensure you also modify the "Activation" flag in the bindings of the page, and set it to "Conditional", and then set the "Active" flag to the same condition as the "rendered" parameter in the jsff. Here is a good document explaining this in more detail:
  • For PopUps, ensure you have the ContentDelievery flag set to  "lazyUncached" this ensures the contents of the popup are not loaded until it is call and the initial page load is not affected

Load View Objects first

As I mentioned before, the page will be as fast as the lowest taskflow, so for example, I recently got across and implementation where the homepage, based on webcenter portal was taking almost 25 seconds to respond, even without any load to the server, upon further investigation, I found that there where 2 taskflows in the page that made web services calls, unfortunately, the way they were build, there was an initial action on the taskflow to call the web service, and then after the results were gather, a success action to display the jsff.

The problem here is that the View Object of the page will not be build until the service returns data, if the taskflow did not have a view object, that meant that the whole page will have to wait for the service to return to display to the user.

There are a number of build-in features within ADF that allow the view components to build and then do PPR to gather data, it is restricted to stamp components, so you should when possible USE TABLES or iterators, under the table's settings, you can find the Content Delivery method, it can be set to immediate, whenavailable or Lazy, use Lazy to force the table to be presented to the user before the data is available, this works for long queries or web services this way the page and other components in the page are shown to the users and the data is rendered once available.

For the above case, we re-build the taskflows so they will only have the view jsff action and call the service via the ADF View model. we managed to reduce the page loading time from 25 to 4 seconds, there were 12 components on the page but only 1 build incorrectly was creating a big impact.

I have to say however that one of the taskflows did still wait to return the view object even after the table and lazy delivery change, we manage to fix this issue but doing a little "hack" with the same concept in mind, we build the taskflow with an empty data-set, and created a PPR using an adf loop (I'll explain this in another post) that called the webservice and refreshed the table, the concept was the same as the Lazy delivery, ADF sometimes requires some persuasion to work as the documentation says it should.....

Cache,Cache,Cache..


Another thing to consider for long running queries and webservices, is to cache the results so the next time the users calls the page, we don't have to use resources again to retrieve the data from database or soa server. This is specially important for frequently visited pages like the portal home page. I mentioned coherance before, it is very simple to create a coherance cache, it's already configured to work in the managed server by default, you just need to use it, I'll post a small example in another post soon.

Hopefully this gives you a general guide to start tuning your implementation, the recommendations here by not means should be taken without considering your own requirements and architecture, this is not a recipe, understand your implementation before changing any configuration.

No comments: