Common performance bottlenecks in a web application server

Alfred Yang
finnovate.io
Published in
3 min readJan 12, 2022
Photo by Andrew Seaman on Unsplash

Uh-oh, your web application is struggling to serve a growing volume of traffic and user demands. What is the first thing that comes to mind?

An uninformed (and often lazy) approach to addressing scalability issues is by increasing the server’s computational and memory capacity. However, in our experience, this only solves the problem temporarily when there are fundamental flaws with the software architecture.

You can do a lot with very little

We have developed applications that support 10’s of thousands of users leveraging a single t2.medium AWS EC2 instance. With most modern day applications, the majority of the code is executed on the client side. The user spends most of the time looking at a static screen, and only interacts with the server when new data is needed. Hence concurrent load on the server is often much lower than what people would anticipate.

When done right, you can squeeze a lot of use out of a $20 / month server. If you need high availability, you can throw another server of the same size into the mix and that should be sufficient for most software applications at launch. Let’s face it, most applications won’t see a whole lot of traffic on day one.

Scalability issues usually are a result of poorly optimized code

We have profiled dozens of applications to identify performance bottlenecks and I would say 9 out of 10 times, performance issues are caused by poorly optimized code.

Often performance issues can be isolated to a handful of operations that bog down the application server. When your application is not performing adequately under load, it’s important to understand the bottlenecks in the system and address them in order of priority. Bottlenecks are commonly found in three areas:

  • I/O’s (i.e. database queries)
  • memory usage
  • CPU usage

Bottleneck #1: database queries

Databases are designed to support a large volumes of I/O’s and they are rarely the performance bottlenecks in an application stack. With that said, we have seen examples where too many database calls are being made for trivial tasks. When there are many users, this can add up and cause performance bottlenecks.

We follow some ground rules when it comes to querying a database to reduce the number of I/O’s:

  • Never execute a database query inside a loop
  • Perform joins or aggregation lookups with indexed fields
  • Use bulk operations if possible when reading & writing large volumes of data
  • Consider caching data that is frequently accessed
  • Consider offloading and scheduling query intensive operations. If absolutely need to make a large number of database queries for a certain operation (i.e. generating a report), consider running them in a separate worker process from your main thread, so that they don’t get in the way of regular usage. Better yet, schedule the operation to run when the system isn’t under load.

Bottleneck #2: Memory usage

I think we have all come across cases where our server ran out of memory. Instead of throwing more RAM at the problem, we should take a moment to see if our software can be less memory hungry, and whether it will crew up excess memory to no end.

  • For operations that will consume a large amount of memory, or consume memory indefinitely, consider buffing data with a file or with a database
  • Be sure to release data that is no longer needed in memory to avoid memory leaks
  • Use paginations or batch operations to avoid consuming too much memory at once
  • Use memory efficient algorithms where possible

Bottleneck #3: CPU usage

Computational power is the last limiting resource that frequently causes bottlenecks. While CPU usage largely depends on the nature of your application, here are some ground rules:

  • Delegate data operations to the database where possible. The database can manipulate data (i.e. Join, group, sort etc) much more efficiently than code.
  • Cache frequently computed results
  • Consider offloading and scheduling computationally intensive operations
  • Use CPU efficient algorithms where possible — evaluate the algorithm’s big-O complexity. This can often be a tradeoff with memory usage.

Finnovate.io is a technology company focused on helping organizations build unique digital experiences on web, mobile and blockchain. Finnovate.io offers development services, training, consulting, as well as a platform that rapidly turns paper based content into digital interactive experiences.

--

--

Alfred Yang
finnovate.io

Alfred is the founder of https://finnovate.io, a company that focuses on helping organizations build unique digital experiences on web, mobile and blockchain.