Simplify, Batch, and Cache: How We Optimized Server-side Storefront Rendering

Celso Dantas
13 min readadvanced
--
View Original

Overview

This article discusses the optimization of Shopify's server-side storefront rendering engine, focusing on techniques such as simplifying data access, implementing caching layers, and reducing memory allocations. The new rendering engine achieves significantly faster response times, enhancing the overall performance for merchants.

What You'll Learn

1

How to use MySQL’s multi-statement feature to reduce database round trips

2

How to implement a thin data mapping layer for optimized SQL queries

3

How to implement multiple caching layers to improve response times

4

Why reducing memory allocations can enhance application performance

Prerequisites & Requirements

  • Understanding of SQL and caching concepts
  • Familiarity with Redis and MySQL(optional)
  • Experience with Ruby programming

Key Questions Answered

How does the new storefront rendering engine improve response times?
The new storefront rendering engine generates responses in less than ~45ms for 75% of requests and is nearly 5x faster than the previous implementation. This improvement is achieved through optimized data access, caching layers, and reduced memory allocations.
What caching strategies are implemented in the new rendering engine?
The rendering engine uses multiple caching strategies, including in-memory caching, node-local shared caching, full-page caching, and database query results caching. These strategies help reduce load times and improve response efficiency.
What is the purpose of the Liquid object memoizer?
The Liquid object memoizer prevents multiple accesses to the same object during a storefront request by caching it in memory. This optimization reduces database calls significantly, with some requests seeing up to 4,000 fewer calls.
Why is writing memory-aware code important?
Writing memory-aware code minimizes unnecessary object allocations, which can lead to more efficient garbage collection and improved performance. Techniques such as using in-place modifications instead of creating new objects are crucial for optimizing memory usage.

Key Statistics & Figures

Response time for 75% of storefront requests
less than ~45ms
This statistic highlights the efficiency of the new rendering engine compared to the previous implementation.
Average storefront response speed improvement
nearly 5x faster
This improvement is a direct result of the optimizations made in the new rendering engine.
Reduction in database calls due to Liquid object memoizer
up to 4,000 calls per request
This statistic illustrates the effectiveness of the memoizer in optimizing data access during rendering.

Technologies & Tools

Some links below are affiliate links. We may earn a commission if you make a purchase.

Key Actionable Insights

1
Implement MySQL’s multi-statement feature to batch load data efficiently.
By reducing the number of round trips to the database, you can significantly enhance the performance of your application, especially for high-traffic storefronts.
2
Utilize a thin data mapping layer to streamline SQL query execution.
This approach allows for more control over data retrieval and can lead to performance gains by reducing overhead associated with complex ORM layers.
3
Adopt a layered caching strategy to optimize data retrieval.
Implementing in-memory, node-local, and full-page caching can drastically reduce response times and improve the user experience during peak traffic.
4
Focus on reducing memory allocations in your code.
By writing memory-aware code, you can lower the frequency of garbage collection, resulting in faster application performance and better resource utilization.

Common Pitfalls

1
Over-reliance on caching without optimizing the underlying application.
This can lead to hard-to-detect bugs and performance issues if the application is not inherently fast before caching is introduced.
2
Using complex ORM layers that add unnecessary overhead.
While ORMs can simplify data handling, they may introduce performance bottlenecks that can be avoided with a thin data mapping approach.

Related Concepts

Caching Strategies
SQL Performance Optimization
Memory Management In Ruby
Data Retrieval Techniques