Showing posts with label Performance Tuning. Show all posts
Showing posts with label Performance Tuning. Show all posts

Saturday, 12 November 2016

MDEX Performance boost | Increase Number of threads

MDEX engine can be configured to run in multi threaded mode. By default MDEX runs in multi threaded mode only with number of threads configured to 1. Multi threaded mode cannot be disabled.

Engine 
How to configure [increase] number of threads : Number of threads are controlled with --threads flag. Specify the --threads flag when starting the MDEX Engine. Or you can mention same in MDEX configuration xml file. For example

 <arg>--threads</arg>
      <arg>2</arg>

 
Key benefits of multi threaded MDEX engine.

Large index files on disk : Single index files are shared between all the threads.
Long-running queries   : Some of thread responds to long running queries while others can respond to different queries.
Simplified system management and network architecture : Need to configure only single MDEX engine.
Applications with high throughput requirements with limited hardware resources : Fewer hard ware resources required than multiple single threaded MDEX engines.
Applications that heavily use the MDEX Engine dynamic cache : Threads in multi threaded MDEX shares the same dynamic cache.

Note : Recommended number of threads for the MDEX Engine is typically equal to the number
of cores on the MDEX Engine server.

Friday, 19 August 2016

Hidden Power of ATG | Service Cache

As we all know the importance of cache in web application performance. In the case of ATG most of the developers  are aware of repository and cache droplet.


While working on one of the Oracle commerce application. I came across new cache from ATG (called service cache). 

Below are the limitations of the above mentioned caches [repository/droplet].

1. Cache Droplet : Accessible through JSP pages. This caches the generated html fragments which includes whites space, this results in increased cache size [comparatively big cache].
2. Repository Cache : Applicable when accessing Database through repository layer.

This cache [Service Cache] is useful in number of scenarios like when you want to access database directly but still want to cache the results. You can also cache data like from other systems like third party response of some call or result of Endeca presentation API.

Here I am going to explain to configure this cache for caching the results in droplet call.

1. Create Cache Key Class : This class will represent the cache key object. Optionally you can directly create the string cache key in droplet itself. But this approach is useful when cache key is complex [includes language/local/segments]. This is also helpful to easily extend the cache key in future [add more fields]. Here you need to override the equals and hashCode methods [Internally used to compare cache keys].

=========================================================================
public class DropletCacheKey {

private String mLanguage;
private String mSegment;
private String mKey; 

public String getLanguage() {
        return mLanguage;
    }

public void setLanguage(String pLanguage) {
        this.mLanguage = pLanguage;
    }

public String getSegment() {
        return mSegment;
    }

public void setSegment(String pSegment) {
        this.mSegment = pSegment;
    }    

 public String getKey() {
        return mKey;
    }

public void setKey(String pKey) {
        this.mKey = pKey;
    }

 private boolean isSameRecordKey(DropletCacheKey pObject) {
        return (this.mKey == null && pObject.getKey() == null) ||
        (this.mKey!= null && pObject.getKey()!= null && pObject.getKey().equals(this.mKey)); 
    }

private boolean isSameRecordLanguage(DropletCacheKey pObject) {
        return (this.mLanguage == null && pObject.getLanguage() == null) ||
                  (this.mLanguage!= null && pObject.getLanguage()!= null
                  && pObject.getLanguage().equals(this.mLanguage)); 
    }

private boolean isSameRecordSegment(DropletCacheKey pObject) {
        return (this.mSegment == null && pObject.getSegment() == null) ||
                  (this.mSegment!= null && pObject.getSegment()!= null 
                 &&   pObject.getSegment().equals(this.mSegment)); 
    }

@Override
    public boolean equals(Object pObject){
        if(pObject instanceof
DropletCacheKey){
           
DropletCacheKey cacheKey = (DropletCacheKey) pObject;
            return (isSameRecordKey(
cacheKey)
                      && isSameRecordLanguage(cacheKey) && isSameRecordSegment(cacheKey));
        }
        return false;
    }

@Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("KEY : [ ");
        builder.append(mKey).append("|");
        builder.append(mLanguage).append("|");
        builder.append(mSegment);
        builder.append(" ]");
        return builder.toString();
    }

@Override
public int hashCode() {
        int PRIME = 31;
        int result = 1;
        result = PRIME * result + ((StringUtils.isBlank(mKey)) ? 0 : mKey.hashCode());
        result = PRIME * result + ((StringUtils.isBlank(mLanguage)) ? 0 : mLanguage.hashCode());
        result = PRIME * result + ((StringUtils.isBlank(mSegment)) ? 0 : mSegment.hashCode());
        return result;
    }
}
=========================================================================

2. Create Cache Adapter Class : This class contains the business logic to fetch actual result.

=========================================================================
public class DropletCacheAdapter extends GenericService implements CacheAdapter {

@Override
public Object getCacheElement(Object pKey) throws Exception {
     if (pKey != null) {
        // Write business logic here to fetch actual result and return the same
     }
}

@Override
    public int getCacheElementSize(Object pArg0, Object pArg1) {
        return 0;
    }

@Override
    public Object[] getCacheElements(Object[] pKeys) throws Exception {
        vlogDebug("Entering Object[] getCacheElements(Object[] pKeys) : " );
        if (pKeys != null) {
            int keyLength = pKeys.length;
            vlogDebug("Key Length :: " + keyLength);
            Object elements[] = new Object[keyLength];
            for (int i = 0; i < keyLength; i++) {
                elements[i] = getCacheElement(pKeys[i]);
            }
            return elements;
        } else {
            return null;
        }
    }

@Override
    public int getCacheKeySize(Object pArg0) {
        return 0;
    }

@Override
    public void removeCacheElement(Object pArg0, Object pArg1) {
    }
}
========================================================================= 
3. Create Cache Adapter Component : Configure cache adapter component using above class.

=========================================================================
# /com/cache/DropletCacheAdapter
 $class=com.cache.DropletCacheAdapter 
 $scope=global
cache=/atg/service/cache/Cache
=========================================================================
 
4. Create Cache Component : Now its time to configure cache component

=========================================================================
 # /com/cache/DropletCache
$class=atg.service.cache.Cache
$scope=global

# injecting caching adapter
cacheAdapter=
/com/cache/DropletCacheAdapter
#Configure below values as per your application need
maximumCacheEntries=10000
maximumCacheSize=10485760
maximumEntryLifetime=43200000
=========================================================================
 
5. Inject Cache component as property in droplet component : This is required as we need to refer cache inside the droplet code.

=========================================================================
 $class=com.search.droplet.StoreDroplet
$scope=global
dropletCache=
/com/cache/DropletCache
#inject other required component
=========================================================================

6. Update Droplet code to use this cache : Here first of all you need to create cachekey object based on input parameter [in this case language, segment and key]. Then invoke the get method on cache component [injected in above step].

=========================================================================
 public class StoreDroplet extends DynamoServlet {    

    private Cache  mDropletCache;

    public Cache
getDropletCache() {
        return
mDropletCache;
    }

   public void
setDropletCache(Cache pDropletCache) {
        this.
mDropletCache= pDropletCache;
    }

public void service(DynamoHttpServletRequest pRequest, DynamoHttpServletResponse pResponse) throws ServletException, IOException { 

// Create cache key using custom method here you need to write method that will return populated object
// of type DropletCacheKey you can modify definition of this object [class] as per your need.

// next fetch the result from cache using this key. This will automatically take care of adding object to cache 
// if already not done. And fetch object from cache if it is available there.
// Here you can also type cast the result. This type cast must be same as retuned type object of //getCacheElement method of cache adapter.
getDropletCache.get(dropletCacheKey);

//further you can utilize the retuned object 

}

}
=========================================================================

Note : You can monitor this cache from dyn/admin.

Saturday, 7 March 2015

Resolving Performance Puzzle

It is challenging for beginners to start performance tuning of an application. I was in same situation when got my first performance tuning assignment. Before starting with performance tuning we need to understand the aspects of it. 


In simple words Performance tuning is the improvement of system performance. Most systems will respond to increased load with some degree of decreasing performance. The core of performance tuning is the performance testing.


Here is the list of steps to execute systematic tuning.
  1. Assess the issue, get the numbers (to baseline the performance) to measure the performance (Mostly available/defined in Non Functional Requirement [NFR] document).
  2.  Measure the performance of system.
  3. Identify the bottlenecks (Part of the system that is critical for performance).
  4. Modify the system update/remove the bottleneck.
  5. Measure the system performance after above modification.
  6. In the case modification improves the performance adopt it,otherwise revert the above modification.
  7. Repeat from steps 2 to 6 in cycles to improve the performance requirement.
These are high level steps. The most confusing/challenging question comes into mind is. 

Where (which part of application) to start performance testing ?.

Most of the web applications are modularized/divided into 3 major parts.
  1. Database.
  2. Back-end code (Including third party calls). 
  3. Front-end.


Its always better to start from database and end at front-end.

Sunday, 1 March 2015

ATG Application Performance Tuning Toolkit




Here is list of tools I am using for application performance analysis and tuning.

 1.   JMeter : The Apache JMeter™ desktop application is open source software, a 100% pure Java application designed to load test functional behavior and measure performance. Apache JMeter may be used to test performance both on static and dynamic resources (Files, Web dynamic languages - PHP, Java, ASP.NET, etc. -, Java Objects, Data Bases and Queries, FTP Servers and more). It can be used to simulate a heavy load on a server, group of servers, network or object to test its strength or to analyze overall performance under different load types. You can use it to make a graphical analysis of performance or to test your server/script/object behavior under heavy concurrent load. 

2.   JvisualVM (Java VisualVM) :  Java VisualVM can be used by Java application developers to troubleshoot applications and to monitor and improve the applications' performance. Java VisualVM can allow developers to generate and analyse heap dumps, track down memory leaks, browse the platform's MBeans and perform operations on those MBeans, perform and monitor garbage collection, and perform lightweight memory and CPU profiling.

3.   TDA - Thread Dump Analyzer : The TDA Thread Dump Analyzer for Java is a small Swing GUI for analyzing Thread Dumps and Heap Information generated by the Sun Java VM.  
 
4.   MAT - Eclipse Memory Analyzer : The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption. Use the Memory Analyzer to analyze productive heap dumps with hundreds of millions of objects, quickly calculate the retained sizes of objects, see who is preventing the Garbage Collector from collecting objects, run a report to automatically extract leak suspects.

5.  Automatic Workload Repository (AWR) in Oracle Database : The Automatic Workload Repository (AWR) collects, processes, and maintains performance statistics for problem detection and self-tuning purposes. This data is both in memory and stored in the database.

The statistics collected and processed by AWR include :
  • Object statistics that determine both access and usage statistics of database segments.
  • Time model statistics based on time usage for activities, displayed in the V$SYS_TIME_MODEL and V$SESS_TIME_MODEL views.
  • Some of the system and session statistics collected in the V$SYSSTAT and V$SESSTAT views SQL statements that are producing the highest load on the system, based on criteria such as elapsed time and CPU time.
  • ASH statistics, representing the history of recent sessions activity.
I will update more on performance tuning.....