Blog Logo
TAGS

ASP.NET Core: How to Maximize Performance and Scalability of Your App

Whether you have an app with just a few users or millions of users per day, like Agoda, improving the user experience by optimizing application performance is always crucial. In the case of very high-traffic websites in the cloud, this optimization can translate into significant cost savings by reducing the number of required app instances. During Agoda’s transition from ASP.NET 4.7.2 to ASP.NET Core 3.1, our primary focus was on achieving this goal. We understand that different businesses require different levels of optimization in different categories. So, we’ve curated a comprehensive list of server-side optimizations. This list ranges from easy, quick wins to more intricate low-level micro-optimizations, allowing you to extract every ounce of performance and scalability from your application setup. Seven server-side optimizations that can help you maximize performance and scalability from your application setup Reduce the number of databases and external API calls your application has to make. Database calls and API calls tend to be inherently slow. In some cases, the slowness of these operations can severely impact the performance of the application being developed. To address this issue, we recommend implementing analytics or logging mechanisms to monitor the speed of your database and API calls. By doing so, you can assess the extent of the slowness and determine whether these calls are necessary or if they can be minimized. Assuming your API and database communications are already used sparingly, the next step is to explore further ways of reducing their frequency by leveraging caching. ASP.NET Core provides a convenient solution called IMemoryCache, which is user-friendly and straightforward to implement. However, it’s essential to be aware of the pros and cons associated with using IMemoryCache. Pros: Storing and retrieving data is incredibly fast and user-friendly. Cons: If you have multiple servers running the application, cache misses will be common, in these scenarios distributed caching is recommended. MemoryCache uses the server’s RAM, so be cautious how much data you put there. 2. Use Async versions of methods whenever possible Let’s debunk a crucial misconception: using async does not automatically make your application faster. In fact, in lower traffic web apps, there might be a slight dip in performance (usually less than 1%) due to the introduction of state machines. So, what is the true purpose of async/await? The answer is scalability. In a synchronous implementation, each request to your application is handled by a dedicated thread. When your application needs to make a database call, API call, or any other I/O operation, the thread has to wait for the external system to respond, resulting in inefficiency. Wouldn’t it be great if we could utilize that idle thread somehow? Let’s talk about threads in .NET for a moment. Threads are an OS abstraction used to schedule tasks on the CPU. However, creating threads is slow and expensive, which is why .NET Framework employs a ThreadPool to maintain a list of reusable threads for the application. To optimize performance, it’s essential to minimize reaching an empty ThreadPool as much as possible.