April 27, 2020
Estimated Post Reading Time ~

Improve the performance of the AEM websites

This post explains my experience on improving the Adobe Experience Manager(AEM) website performance

"Cache as much as possible" - CDN layer:
The caching is the important thing to be considered for improving the performance, in AEM setup the dispatcher will be used for caching the static content.

The CDN can be added on top of dispatcher to distributed caching to support the caching in different region to provide better performance. As the CDN is distributed at least by region the user will be served from nearby region to improve the performance. in this setup publishers will be only receive the initial request and subsequent request will be served by CDN and dispatcher.

There are multiple CDN options like Akamai and AWS Cloud Front. The request flow diagram below



Cache-Control max-age header:

Specify the cache control header with required max-age value to control the amount of time the files are cached by browser.

Add higher max-age values for static resources so that the browser caching can be used optimaly for bettwr performance.

The max-age can be be added as part of the virtual host configuration. e.g

<filesMatch ".(css|js|)$">
Header set Cache-Control "max-age=2628000"
</filesMatch>

<filesMatch ".(jpg|jpeg|png|gif|html|ico)$">
Header set Cache-Control "max-age=900"
</filesMatch>


Versioning of CSS and JS files:
The performance gain is achieved through browser caching static files for specified time(max-age). The browser cache busting is important to update the modified static files in browser, say the browser has the CSS file cached for one month and you want to change the CSS. You need a strategy for breaking the cache and forcing the browser to download a new copy of the CSS.

Change the version number of the static files upon modification so that the browser cache will be updated with new file irrespective of the max-age configuration.

The versioning of static resources can be enabled in AEM through "ACS Commons Versioned Clientlibs" - https://adobe-consulting-services.github.io/acs-aem-commons/features/versioned-clientlibs/index.html

Move the JS loading to end of the page:
Place your javascript at the end of your HTML file if possible. This allows the majority of page content to be loaded and rendered first. The user sees content loading, so the page looks responsive. At this point, the heavy javascripts can begin loading near the end.Only the core files that are absolutely needed in the beginning of the page load should be added in <head>. The rest should be loaded at the end.

Remove the duplicate CSS/JS from pages:
Make sure there is duplicate JS or CSS files are loaded into the page, this will increase the page load time.

Remove unused CSS/JS reference from the page:
Remove the unreferenced JS or CSS files from the page to improve the page load time

Group the JS/CSS with client library dependencies:
Try to minimize the number of JS and CSS files included into the page to improve the page loading time, group all the Java Scripts and CSS into a single file - can be more based on the requirement.

This can be achieved in AEM thought clientlibs - multiple clientlibs can be mered through enabling dependency or embed properties.

embed - We can embed code from one client library into another client library. At runtime, the generated JS and CSS files of the embedding library includes the code of the embedded library.

dependencies - This property is used to list other client library categories on which this library folder depends.

Minify JS/CSS:
Minification removes unnecessary characters from a file to reduce its size, thereby improving load times. When a file is minified, comments and unneeded white space characters (space, newline, and tab) are removed. This improves response time since the size of the download files is reduced.
The minification can be enabled in AEM through "Adobe Granite HTML Library Manager", the external tools also can be used for minifying JS and CSS in AEM.

Please note this will only minify the JS and CSS files not html, the html should be minified externally to reduce the size.



Enable GZIP Compression:
Enabling GZIP compression can reduce the size of the transferred response by up to 90%, which can significantly reduce the amount of time to download the resource, reduce data usage for the client, and improve the time to first render of your pages
The GZIP compression can be enabled in AEM through "Adobe Granite HTML Library Manager"



This will enable the GZIP compression only for JS/CSS, the GZIP compression for other types can be enabled in dispatcher(Apache)

Enable the required modules in conf file

LoadModule filter_module modules/mod_filter.so

LoadModule deflate_module modules/mod_deflate.so

Enable the compression based on the file types in config file - this is applicable for all sites, the configurations can be added for required virtualhosts

SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript

Reduce DOM elements:
The number of DOM elements directly impact the performance of the web page, reduce the number of DOM elements on the page to improve performance.

The number of DOM elements is easy to identify, just type in browser debug console:
document.getElementsByTagName('*').length.

Enable Keep-Alive Configuration:
Keep alive is a method to allow the same TCP connection for HTTP conversation instead of opening a new one with each new request. This will help to reduce the browser loading time by avoiding the connection creation overheads.

In Apache this can be enabled in httpd.config file, this can be enabled for specific virtualhosts also

#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive ON


Defer Parsing of JavaScript:
If you defer parsing of JavaScript that means JavaScripts should load, only after the content of the website has loaded.

<script type="text/javascript" src="scripts/sample.js" defer="defer"></script>

Async loading of JavaScript:
JavaScript can be loaded Asynchronously by adding async attribute in the JavaScripts, async tells the browser to load this script without blocking the page

For example:
<script async scr ="test.js" >

Cache third part services:
The third party service responses should be cached to improve the performance, the external caching tools like Ehcache can be used to enable the caching.

Refer the following URL for custom solution to cache the external data - https://www.albinsblog.com/2018/01/developing-caching-service-to-cache-static-data-adobe-experience-manager-aem.html?m=0#.W5vpkmiPLIU

Implement SDI(Sling Dynamic Include) :
Sometimes we may want to update dynamic content in the specific section of the page frequently and not to cache that particular section of the page.We normally use javascript libraries to make client side calls to fetch the dynamic content and update the page. Therefore dispatcher cache the whole page and our custom javascript will make calls to fetch dynamic content on demand. Using Sling Dynamic Include, we can avoid our custom implementation and also cache whole page and dynamic components are generated and included every request in dispatcher.

Refer the following URL for more details - https://helpx.adobe.com/experience-manager/kt/platform-repository/using/sling-dynamic-include-technical-video-setup.html

Domain Sharding/Cookieless domains to serve static resources:
To improve the page load time better to serve the static resources via different cookieless domain. The CDN should be enabled for this cookieless domain to improve the performance further.

Refer the following URL for enabling cookieless domain for static resources in AEM - https://www.albinsblog.com/2018/01/serving-static-resources-through-different-cookie-less-domain-adobe-experience-manager-aem-sling-pipeline-rewriter.html#.W5vtbGiPLIU

Optimizing images:
Large images slow down your web pages which creates a less than optimal user experience. Optimizing images is the process of decreasing their file size which in turn speeds up the load time of the page. The image should be also uploaded only with required dimensions and size to avoid the extra loading time.

There are multiple options
  • Extend DAM Update Asset with CreateWebEnabledImageProcess Workflow Process Step. It allows you to generate new image rendition with parameters like size, quality, mime-type. Depending on workflow launcher configuration, this rendition can be generated during creation or modification of assets. You can also trigger the workflow to be run on chosen or all assets.
  • Generate a custom workflow to generate the proper image renditions.
  • Using ACS commons Image transformer - Install ACS commons Package , Use Image transformer Servlet config to generate optimised or transformed images acc to requirement. For more Info https://adobe-consulting-services.github.io/acs-aem-commons/features/named-image-transform/index.html
  • Use some external tools to generate the images with required dimensions and size and also compress the images.
Remove additional 301 redirects:
Make sure the additional redirects are removed 
e.g http://www.example.com/ --> https://www.example.com/ --> https://www.example.com/en.html

Here the user can be directly redirected to https://www.example.com/en.html

Enable DNS prefetching:
Domain name prefetching is a good solution to already resolve domain names before a user actually follows a link(in the background). Here an example how to implement it in the HEAD section of your HTML:

DNS resolution time can lead to a significant amount of user perceived latency, Domain name prefetching will resolve the DNS in advance to avoid the delay during the URL access -

<link rel="dns-prefetch" href="//www.example.com">

Enable Preconnect:
Preconnect allows the browser to set up early connections before an HTTP request is actually sent to the server. Connections such as DNS Lookup, TCP Handshake, and TLS negotiation can be initiated beforehand, eliminating roundtrip latency for those connections and saving time for users.

<link href='https://www.example.com' rel='preconnect' crossorigin>

Lucene index configuration:
Enable the following configuration to improve the performance - The index will be copied to local file system on accessing from repository or writing to repository to improve the performance
Open /system/console/configMgr/org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProviderService and
enable CopyOnRead
enable CopyOnWrite
enable Prefetch Index Files

Custom Oak indexes:
Oak does not index content by default, custom indexes need to be created when necessary.
  • Create custom oak indexes for all frequently used search queries.
  • Analyze slow queries
  • Create the custom indexes under the oak:index node for all search properties
  • For each custom Lucene-based index, set includedPaths
Enable Htttp/2 protocol in dispatcher:
HTTP2 is the latest version of HTTP (HyperText Transfer Protocol) which has been optimized in such a way as to make your website load much faster. One of the primary goals of HTTP2 is to decrease the latency to improve page load speed in web browsers.

Some of the benefits of HTTP/2
  • Binary instead of textual
  • Fully multiplexed
  • Use one connection for parallelism
  • Header compression
  • Allows servers to push resources proactively
  • Prioritization of requests
Some of the improvements discussed in this post - Combining JS/CSS files, Domain Sharding/Cokkieless domain is not required if the HTTP/2 protocol is enabled.

The HTTP/1 protocol only supports limited number of parallel connection for a domain and remaining connection will be waiting. There is no restriction on parallel connection in HTTP/2 protocol, this improves the performance of website loading.

Refer the following link on enabling HTTP/2 in Apache 2.4 - https://httpd.apache.org/docs/2.4/howto/http2.html

JVM parameters for query performance:
Add the below JVM parameters to improve the query performance

-Doak.queryLimitInMemory=500000
-Doak.queryLimitReads=100000
-Dupdate.limit=250000
-Doak.fastQuerySize=True


Interpret the request.log to monitor and identify the request/response details including the processing time, the rlog.jar file can be used to interpret the request.log file. Refer https://helpx.adobe.com/experience-manager/6-3/sites/deploying/using/monitoring-and-maintaining.html#Usingrlogjartofindrequestswithlongdurationtimes for more details

Refer the following URL for server side performance tuning - https://www.albinsblog.com/2015/06/performance-tuning-adobe-cq5adobe-aem.html#.W5vpA2iPLIU

Some of the tools used to monitor the browser performance
https://tools.pingdom.com/
https://developers.google.com/speed/pagespeed/insights/
YSlow Chrome plugin
http://www.webpagetest.org/
https://testmysite.withgoogle.com/intl/en-gb
https://tools.keycdn.com/speed
https://tools.keycdn.com/performance
https://varvy.com/pagespeed/

Use some Application Performance Management (APM) tools like Dynatrace or AppDynamics to track the end to end performance of the application with all integration points.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.