Improving Web Application Performance Using Azure Cache for Redis
Have your web applications ever experienced performance bottlenecks caused by expensive and repeated method calls? Adding Azure Cache for Redis to your web application can obliterate bottlenecks and provide a consistently fast and responsive user experience by caching the frequently accessed information to avoid the overhead of expensive API calls and database interactions. Figure 1 below demonstrates the Azure Cache for Redis “Cache-Aside” pattern for accelerating a web application’s performance.
Figure 1: the Azure Cache for Redis “Cache-aside” pattern accelerates web application performance
We recently released the Web App + Database and Cache in Azure portal | Create a resource for easily creating an Azure Cache for Redis with a Web App and a database. See Figure 2. It simplifies the steps for creating the resources securely and with connectivity configured. Developers can use it for coding proofs of concept, hosting production-ready web applications, and configuring Continuous Integration systems.
Figure 2: Web App + Database and Cache deployment template in Azure
Getting started using Azure Cache for Redis is easy, and the performance improvements can be dramatic. We will look at an example with an online shopping web application that has common features like browsing products, shopping cart, and session-state. Azure Cache for Redis is applied to cache repeated web queries, session state, and web page view. It’s built with ASP.NET core. The sample code is available at azure-cache-redis-demos/eShop.
In the sample application, the product catalog web page performance was measured by running Azure Load Test. Tests were run on two versions of the sample application for using cache and not using cache. Azure Cache for Redis was used to cache repeated data queries, session-state data, and HTML page views. Both environments use App Services Linux plan P3V3 with 1 node, which is a scaled-up version of what the Web App + Database and cache template would create. For context on planning the number of virtual users in a load test, we observe that usually when the web application passes 5000 total users is when developers need to plan for performance at scale. Since the number of concurrent users is about 1/3 of total active users, let’s just put 2000 virtual users in this test. The load test runs significantly faster when Azure Cache for Redis is used. Referring to the load test result in Figure 3, the performance for web application using Redis Cache is presented by the blue line, and the web application without Redis Cache is presented by the red line. Results show that the 90th percentile response times are 1.29s (with cache) vs. 9.56s (without cache), and the throughputs are 2.14k/s (with cache) vs. 837/s (without cache).
Figure 3. Performance comparison for the web application with and without cache
Instructions for deploying the web application and running load test are available in the sample app’s README file: azure-cache-redis-demos/README.md. To summarize the tasks:
- Deploy the sample web application to Azure. Deploy the web application to resources created from the Web App + Database with Redis Cache in Azure.
- Load test the web applications. Create a quick load test with Azure Load Testing. Use the homepage URL as the load test target URL. Scale up the App Services plan to P3V3. Put 2000 virtual users on the load test.
- Compare test results. Run the load test. View and compare load test runs to observe the difference between having cache vs. not having cache.
While performance tuning is unique to every application, patterns and best practices on using Redis Cache are repeatable and applicable in all scenarios. The rest of the blog will describe concepts and how-to for:
- Improving performance on repeated web queries with Azure Redis Cache-Aside pattern
- Ensuring resiliency and scalability by storing session-state data into Azure Cache for Redis
- Increasing Web App performance by storing generated page views in Azure Cache for Redis
In addition, the blog will describe the best practices for using Azure Cache for Redis to maximize performance gains. We will also have a peek into the next step scenario on adding intelligent recommendations into the online shop web application.
Improving performance on repeated web queries with Azure Redis Cache-Aside pattern
When customers browse the homepage, all products would load resulting in repeated queries to the web server and the database. Referring to Figure 4 that demonstrates the homepage that uses the loaded product catalog data and displays the data in the web view.
Figure 4: The homepage for the web application is accessed by all customers, causing repeated queries on getting all products
The Cache-Aside pattern ensures that repeated access to the same database queries are cached for fast performance. In our example, the ProductServiceCacheAside.cs implements the Cache-Aside pattern and is used in the CRUD operations in HomeController.cs and ProductsController.cs.
The Cache-Aside pattern is simple and intuitive to implement, per the algorithm below:
- The client program reads the item from the Azure Cache for Redis.
- If the data doesn’t exist in the cache, the client program reads from the database. Then the client program saves it in the Azure Cache for Redis for the next reads.
- The client program evicts the cached item from Azure Cache for Redis for every create, update, and delete operation.
Applying the Cache-Aside pattern in your web application accelerates performance with data operations. For even better performance, consider the write-behind/write-back caching patterns to write data directly into a Redis Cache that will sync with a database for persistence.
Ensuring resiliency and scalability by saving session-state data into Azure Cache for Redis
We want to retain customers by providing personalized shopping experience, which requires the web application to be stateful. For example, our online shop shows history for the last viewed item. The session-state data is volatile, unique to each user and session, and needs to load fast. It’s usually stored in Azure Cache for Redis for performance, scalability, and resilient failover. Referring to Figure 5, the last viewed item is saved and displayed on the top of the page after the user viewing the item.
Figure 5: Last viewed item is cached as session state for a customer to easily purchase later
Using Azure Redis Cache to store session-state is simple as the following steps in ASP.NET core:
- Add session middleware service in the Program.cs file.
- Add Redis Distributed Cache service provider to the Program.cs file. The session middleware will automatically pick up the configured instance of Distributed Cache as the backend store.
- Use HTTPContext.Session in your code. An example can be found in the sample at HomeController.cs
There are significant advantages to using Azure Cache for Redis for session-state data. Storing session state in-memory on the web server would require ‘sticky session’ to be configured which affects scalability. Also, in the case of a failover, previous session data would not persist. On the other hand, storing session state in a database is not as performant as using a cache – this is especially impactful when session state is used for initializing customer settings. Using Azure Cache for Redis spares the web application from such problems.
Increasing Web App performance by storing generated page views in Azure Cache for Redis
Rendering web views, such as iterating through the list of data models to create a view, can be CPU intensive. To solve the problem, the generated HTML code for page views can be cached for fast access and for resource efficiency.
While the performance improvement is dramatic, this is very easy to code. Referring to the Index.cshtml code, the distributed cache tag helper is all you need!
The codes below demonstrate how to add distributed cache tag helper in your Razor page:
<distributed-cache name="ProductListPageOutput" expires-after="@TimeSpan.FromHours(1)">
<!—your Razor codeà
</distributed-cache>
Best practices for using Azure Cache for Redis to increase performance
A few tips when tuning the web application to work with Azure Cache for Redis:
- Put Redis Cache in the same region as your Web App to reduce network latency
- Always keep the StackExchange.Redis library up to date!
- Use asynchronous methods for object serialization. Sample code available at azure-cache-redis-demos/ConvertData.cs.
- JSON serializers are good for getting started experience. For advanced performance optimization use protobuf-net.
- Configure the ThreadPoolMinThreads property in the eShop.csproj file to ensure the processes awaiting on Redis won’t throw HTTP 500 timeout errors due to failed resource allocation. Learn more at Threading config settings - .NET.
Next steps
In addition to the basic shopping capabilities, you may want to add intelligent features such as semantic search on product recommendations. An example is that your customers can simply ask “what should I wear for a weekend party” by typing or voicing and the online shopping web application will recommend clothing and accessories. Redis Cache Vector Similarity Search capability is well-integrated with Open AI for developers to easily build such scenarios. Check out Vector Similarity Search with Azure Cache for Redis Enterprise - Microsoft Community Hub.
Call to action
Try out the Web App + Database with Redis Cache in Azure today and see how much faster your app will run!
Published on:
Learn moreRelated posts
Disconnected operations for Azure Local
Introducing the new Linux-based Azure Cosmos DB Emulator (Preview)
We are excited to announce the preview release of the new Linux-based Azure Cosmos DB Emulator! This latest version is built to provide faster...
Azure Cosmos DB Shines at Microsoft Ignite 2024!
Microsoft Ignite 2024 took over the Windy City this week, bringing with it new technological innovation and exciting product announcements apl...