When we talk about improving the performance of an online store, it is common to hear recommendations like "enable PrestaShop cache", "enable Magento cache", "install Redis" or "use Cloudflare". The problem is that each of these technologies operates at a different layer and solves different problems.

A professional caching system implementation for an eCommerce platform does not consist of enabling every available cache, but rather identifying where the bottleneck occurs and applying the appropriate strategy at each cache layer.

Now, what do we mean by cache layer? Every web application is built with its own architecture made up of different levels with information that we can temporarily store so we don't have to rebuild them every time you visit or browse that web application.

My extensive experience has led me to distinguish, at least, these cache layers:

  • Application layer: Stores internal information the application needs to run faster. For example, PrestaShop/Symfony's own cache or Magento's own cache.
  • Template layer: Prevents continuously recompiling/processing templates (visual appearance). For example, Smarty cache in PrestaShop or PHTML in Magento. In plain terms: it prevents the browser from having to redraw the website every time you access it.
  • Code layer: OPCache; stores compiled PHP code, reusing it every time the user interacts with the web platform.
  • Data layer: Redis; stores data or results we want to retrieve quickly. It stores data in such a way that it returns it to the user without having to access the database.
  • HTTP layer: Varnish; stores complete HTTP responses. Returns data without having to reach PHP.
  • Distribution layer: CDN; stores and distributes resources like images, CSS, JavaScript, and fonts. Serves content from servers or nodes (proxies) distributed geographically, avoiding each request having to reach the origin server.

Each of these layers, in a professional top-level web system, must be treated independently of the others. Below I provide a Cache Architecture Plan that I have designed from my experience and knowledge.

1. Before caching: measure

Before modifying the architecture, I would analyze, at minimum:

TTFB (Time To First Byte)

TTFB measures the time from when the browser requests a page until it receives the first byte from the server. If TTFB is high, it may indicate that the server is taking too long to generate the response.

You can easily measure this value using PageSpeed Insights, although I personally do it from the PC console using the following command:

Bash
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" https://thewebsiteyouwanttomeasure.com/

Be careful! A low TTFB does not necessarily mean the page loads quickly, because afterwards we still have to download and process HTML, CSS, JavaScript, images, fonts, etc.

Ideal value: < 250 ms, acceptable real value: < 650 ms.

Total response time

It is essentially timing the user experience from when they click a link until the page finishes loading completely.

You can measure this value with PageSpeed Insights, it's not very complicated, although there are more advanced solutions like WebPageTest, but initially Insights is more than enough.

Ideal value: < 1 s, acceptable real value: < 2 – 3.5 s

Slow SQL queries

In MySQL/MariaDB, enable the slow query log with slow_query_log and define a threshold of 2 seconds (for example) with long_query_time. Then analyze the log with tools like mysqldumpslow to summarize slow queries or pt-query-digest for more detailed analysis. On platforms like Azure Database for MySQL, you can use Log Analytics and dashboards to visualize query performance.

Ideal value: 0, acceptable real value: < 1.5%

CPU and Memory usage

Today, all hosting plans, whether shared, VPS, or dedicated, have a CPU usage monitor. We only need to record CPU consumption values to proceed with the analysis for a Cache architecture. We don't need Glances, Kula, or Grafana for this.

Ideal value: < 60%, acceptable real value: < 80%

PHP-FPM processes and concurrent requests

To know the number of active, idle processes, and the request queue. In a top-level professional project, it would be ideal to use Prometheus and Grafana, but for an occasional moment when you can implement this Cache plan, doing it via curl is more than sufficient. You need to follow several steps, which I invite you to chat with your preferred AI — it will surely guide you better than I can on your system (tell the AI: "Use curl with the PHP-FPM status page").

  • Ideal value: < 70% capacity, acceptable real value: < 90% capacity
  • Ideal value: < 100 - 500, acceptable real value: < 500 – 1000+
  • Ideal value: < 600 ms, acceptable real value: < 1.5 ms (php execution time)

External API responses

You can measure them in several ways. The simplest, from the server, is with curl:

Bash
curl -o /dev/null -s -w "Total time: %{time_total}s\n" https://api.example.com/products

If you want to better analyze where the time goes:

Bash
curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnection: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" https://api.example.com/products

For a PrestaShop store, it is interesting to measure the call from the server where PrestaShop is hosted, because that way you know how long the external API actually takes to respond to your application.

For example, if a shipping API takes 1.8 seconds, each PrestaShop request that waits for it can increase that response time approximately by that amount. There you already have a clear candidate for caching, asynchrony, or integration review.

Ideal value: < 400 ms, acceptable real value: < 1.5 s

Number of requests to static resources

In Chrome or Firefox, open the store, press F12, go to Network, reload the page with Ctrl + F5 and from there you can filter by Img, CSS, JS, Font, etc.; the number of requests that appear corresponds to the number of resources requested.

Ideal value: < 50, acceptable real value: < 100

Store behavior under load

With tools like Grafana K6 or JMeter, you can simulate 100, 1000 concurrent users. You can measure response time, TTFB, errors, requests per second, and CPU/memory consumption of PHP-FPM and MySQL.

Ideal value: 0 errors, acceptable real value: < 1% errors.

2. Analyze and decide which cache layers to use

Once the above metrics are obtained, I would analyze where the bottleneck really is and, from there, decide which cache layers we need to implement.

Not all stores need all layers. A small store can work perfectly with OPCache and application cache, while an eCommerce platform with a large catalog, international traffic, and thousands of concurrent users may need a much more complete architecture.

If TTFB is high

I would analyze the source of the delay and mainly study application cache, Redis, or Varnish, depending on where the bottleneck occurs.

Redis I would use when the bottleneck is inside the application. For example, PrestaShop needs to repeatedly query data or perform calculations that we can temporarily store in memory. This way we avoid repetitive work and/or queries to the database. In the case of PrestaShop, PrestaShop's own cache/Symfony determines what data to cache, and Redis stores it.

For example, imagine that the product page needs to continuously query the available stock of a product or other data that is constantly queried: prices, configurations, sessions, search results, catalog data, etc. If that data is queried thousands of times, we can temporarily keep it in Redis and avoid repeating the query to MySQL.

Varnish I would use when the bottleneck is in generating the complete HTTP response. If a category page can be the same for many users, Varnish can directly return that response without the request reaching PHP/PrestaShop. But be careful, on web platforms where data may vary between users, it is not advisable to use Varnish lightly. For example, in a B2B environment, a category that shows products with different prices depending on the customer should not be served indiscriminately from the same HTTP cache, because you could end up showing one customer the price of another.

If the total response time is high

I would analyze both server processing and resource delivery, and study Varnish and CDN, in addition to the previous layers if necessary.

Here I would differentiate two parameters:

  • High TTFB ? mainly server/application problem.
  • Good TTFB but high total load ? problem likely in resources/frontend/network.

In other words, if TTFB is good but the page takes a long time to complete, you need to implement a CDN distribution layer and optimize resources. No more.

If there are slow SQL queries

I would first analyze the queries themselves and, when appropriate, use Redis to avoid repeating certain queries or calculations.

For example, a query that retrieves certain characteristics or information about a product and is executed thousands of times a day. If that data does not change continuously, we can temporarily save the result in Redis and avoid repeating the same query to MySQL.

Needless to say, that query must be well designed. If, for example, it lacks an index, using Redis to hide that problem is unprofessional.

If CPU usage is high

I would review OPCache and application cache to avoid unnecessary PHP processing.

If memory usage or PHP-FPM processes are high

I would study application cache, Redis, and Varnish to reduce the number of requests that need to reach PHP. Be careful with Varnish!

If there is a high number of requests to static resources

I would implement a CDN to distribute images, CSS, JavaScript, fonts, and other resources.

For example, an international store with customers in Spain, France, Portugal, Germany, etc., can serve images, CSS, JavaScript, and fonts from a CDN with servers or nodes distributed across Europe. Thus, a customer in Germany could receive those resources from a nearby node, instead of having to download them always from the origin server in Spain.

Conclusion

In this way, each cache layer responds to a specific problem detected during the measurement phase, rather than implementing all available technologies without really knowing what problem we are solving.

In the next post I will teach you how to configure each caching system.