Performance tuning of Spring based application

1. Introduction

What I had been through is some rigorous performance tuning activity, that finally brought up the performance of the application by around 50-80%. What used to take more than 1200ms to respond, then started responding in just 300-500ms, which is indeed an enormous difference. You might have been using Spring Security, Hibernate, Spring MVC the traditional way, but what if performance becomes a road-blocker! The strategies or tweaks I am listing down in this article will definitely have something for you to take.

2. Spring Framework

2.1 Connection Pooling

Connection Pooling is a technique to boost application’s performance where N connections to the database are opened and managed in a pool. The application just asks for a connection, uses it and then drops it back to the pool. When the application demands for a connection, the ready connections are kept available to used in the pool. The pool manages the connection lifecycle, such that the developer actually doesn’t need to wait for the connection to get established and filter out the stale ones.

A proper connection pooling setup plays a very important role in delivering higher performance.

We have already published a detailed article on Database Connection Pooling mechanisms with Spring Framework in the past. You can go through the article here. Connection pooling mechanism is an important deciding factor that makes a certain impact on the final performance of your application.

After Apache DBCP, the second most preferred connection pool implementation is c3p0, which easily integrates with Hibernate, and is said to deliver good performance.


3. Hibernate

3.1 Transaction

Hibernate does the dirty checking only when it needs to, to keep a check on the performance cost. The cost increases when a particular entity has a corresponding table with large number of columns. To even minimize the dirty checking cost, it’s better we help Spring by specifying a transaction to be read-only, which optimizes the performance even better, eliminating the need for any dirty checks.

Dirty checking in Hibernate is a concept where an entity is monitored for any changes when in persistent state and if any changes are found, Hibernate executes the corresponding SQL for it.

3.2 Periodically flush and clear the Hibernate session

When adding/modifying data in the database, Hibernate keeps in its session a version of the entities already persisted, just in case they are modified again before the session is closed (Dirty Checking). However, we can prevent Hibernate from holding the entities in its session longer than actually needed. So once the inserts are done, we might not need to keep the entities in persistent state anymore. In this case we can safely flush and clear the entityManager to sync up the state of entities with the database and remove the entities from the cache. This will keep the application away from memory constraints and sure to impact the performance on a better side.

3.3 Lazy Initialization

If you are sticking with Hibernate, make sure you use the lazy initialization feature effectively. Lazy load the entities only when it’s needed. Note that when a collection of a custom entity (something like Set<Person>) is lazy initialized, each entity in the collection will be loaded individually using separate queries. Hence, if there are too many entities expected in a lazy-initialized set, same number of queries will execute sequentially, which might lead to a big performance hit.

In order to avoid this, you can trick hibernate into loading all children simultaneously, e.g. by calling parent.getChildren().size().

– Suggested by Thomas Lötzer at Stackoverflow

3.4 Constructor Based HQLs

In normal scenarios, in an application using Hibernate, we don’t bother retrieving the whole entity with all its properties even though we don’t need all of them for a particular use case. A single entity might have 30 properties, while we might just need a few to be set in our web service response or display to the user. When in a scenario thousands of records are liable to retrieved based on our query, think of the unused fields we are heavily jamming our application with, which ultimately lead to a huge performance hit.

To deal with this, HQL/JPA provides us with a select new constructor call, which are often used for reporting queries, which allows the developer to select aggregated values as well. You can find more details on writing Constructor Based HQLs by clicking here.

3.5 Entity & Query caching

If the same query is invoked every time for a particular entity and the table data is not liable to change for a particular time slot, we can possibly cache the query and the entities with Hibernate.

If a query cache is applied, then no subsequent SQL statement is sent to the database for execution. The query results (which caches the identifier values and results of value type) are retrieved from the query cache, and then the cached entity identifiers are used to access the Hibernate’s second level cache where the corresponding actual entities are cached. This brings a high impact in the response time which we could notice. When we do this, we are also concerned about when the cache refreshes itself. We can do that easily with some simple configurations.

You can learn more about Entity and Query Caching by clicking here

3.6 Native Queries

Though the native queries have a setback, they are still the quickest as far as performance is concerned. When HQL tweaks don’t help improving the performance of your application, native queries can significantly improve the performance by around 40%.

3.7 Primary key generation

When specifying Hibernate annotations into entity classes or writing hbm files, let’s avoid using  key generation strategy as AUTO, which leads to huge amount of sequence calls.

With this simple change, an improvement in the range of 10-20% can be noticed in ‘insert-intensive’ applications, with basically no code changes.

Note that cannot apply SEQUENCE generation strategy with MySQL database, use IDENTITY generation strategy instead, as recommended in technology forum discussions.

4. Database

4.1 Proper Indexes

Indexes becaome an important factor if the tables involved have more number of rows and complex queries get fired by your application. The best way to get suggestions on required indexes is to check Query Execution Plan for each of the actual queries individually, in SQL server clients like SQL Management Studio.

Note that –

  • Indexes might slow down inserts and updates, so apply them carefully on columns that are frequently updated.
  • Indexes are meant to speed search operations which uses WHERE and ORDER BY clauses in the query.

4.2 Proper Joins

Make sure the tables joins are proper and no unnecessary joins are done.

If there is a table joined, whose none of the columns are being retrieved in SELECT, look for ways to eliminate the join with that table.

4.3 Views

Views are another strategy that we also give a thought on, when we are thickly surrounded by performance concerns. Until SQL Server 2000, views were meant just for convenience, and not speed. Later versions of SQL server came with a special feature called Indexed Views, that is said to immensely increase the performance, however Indexed Views must be created using a set of guidelines.

5. Server Optimization

5.1 Memory

Proper server maintenance is always very important when you are more performance-centric. Below are some of the basic points which can be considered –

  • Timely cleaning the temporary files. An scheduled automated script would be perfect here.
  • Multiple server instances with load balancing (BIG-IP)
  • Based on the application usage, we can try tweaking the server configurations, like you can refer here for Tomcat Configuration Recommendations.

6. Spring Security

6.1 Authentication cache

Spring Security performance is one of the concerns that sometimes comes into picture, when the request processing time is noticed to be on the higher unacceptable side. There might be situations where you notice that the actual request processing takes around 120ms, while Spring Security authentication/authentication adds up another 500-600ms.

6.2 LDAP Custom Authorities

This might not be the approach that you would want to consider, but it does provides you with an alternative to improve the performance of your Spring Security implementation.

In this approach, we set the user authorities with our own custom implementation rather than verifying the same from LDAP. There might actually be several reasons to do this, the application’s performance being one of the several reasons. You can go through other details on this approach here.

6.3 Native LDAP

No doubt, Spring Security provides us with the most standard and durable implementation to LDAP authentication, but with Core Spring LDAP, the approach becomes a bit ugly, yet gets better streamlined. The latter approach (with Core Spring LDAP) has been noticed to drastically improve the performance of your application when compared to that with Spring Security. Though it’s less advised to go with this approach, we still count it to be one of the alternative for improvement in the application’s performance.

The detailed example has already been published here.

7. Multithreading

7.1 Executor Service Framework

With all possible optimizations, the single hits to your application might look satisfying. However, the load tests with several concurrent hits to your application starts clogging your application’s performance. In such high concurrency scenarios, you might might want to tune up the thread defaults on Tomcat server. If there is high concurrency, the HTTP requests are put on hold until a thread becomes available to process it. In more extreme case, the wait queues elevate and the requests time out.

The default server thread implementation can be further complemented with the usage of Executor Framework within your business logic, to further make concurrent asynchronous calls from within a method in a single thread execution flow.

Executor Framework is a makeover of the core multi-threading implementation, provides an abstraction layer over all the internal thread management tasks, such that the developer needs to focus only on the implementation of the business logic.

To know more about the implementation of Executor Framework within your Spring application, click here.

Receive our updates to your inbox

Get more stuff like this
in your inbox

Subscribe to our mailing list and get interesting stuff and updates to your email inbox.