Vue Storefront performance tests and architecture ready for traffic peaks
I always wondered: how about creating a tool that you can just drop-in in front of your eCommerce solution during periods of massive traffic peaks (e.g. Black Friday, Cyber Monday) to save sales. I’m thinking about the bulletproof solution that works even when the servers are down.
Following this path led me to the Vue Storefront architecture. To be honest, that was the initial goal of the project, not to enable PWA features, but to create a headless solution that’s a remedy for performance issues.
Studies show that more than half of sites are abandoned if the page load time is longer than 3s. What’s more, 75% of mobile sites load longer than 10s. At the same time, the average load time is 19 seconds. It’s not much better even with a 4G a-connection — 14 seconds.
Add to this the fact that 40% of major eCommerce companies experience periods of website downtime during seasonal traffic peaks. More than half, at 56%, noted that their website experienced longer loading times during seasonal peaks.
This means almost all eCommerce sites perform at a fraction of their business capabilities.
One of the building blocks for the Vue Storefront project was to make it bulletproof. I mean, really bulletproof: massively scalable and offline ready — meaning that the app can work even when the servers are down.
One of the key architectural principles was to make it resilient and asynchronous.
Each layer is designed to be independent of the performance and availability of the others.
It’s not a kind of “eCommerce theme” but a fully-fledged application that can even calculate taxes, cart totals, and process checkouts, fully on its own. Therefore, it could work even without an internet connection. The Orders that are made by users are queued on the client’s side, in case the API is down or there is no network connection. They are queued server-side as well (vue-storefront-api queues the orders into a Redis-based queue). Orders are sent to the eCommerce backend asynchronously to not rely on the backend response times.
All the data is provided as JSON feeds from the second layer — vue-storefront-api. Of course, there is a cache in the middle. We’re using indexedDB, the in-browser database, to store products, categories, and user data, and using Service Workers to synchronize the local vs. server data.
The Vue Storefront API is a Node.js, REST and GraphQL compliant API which is also a Proxy layer separating the eCommerce backend specifics from Vue Storefront frontend logic. That means you can plug in Vue Storefront to Magento2, Pimcore, etc. just by switching the data connector. We’re currently working on WooCommerce, BigCommerce, and Shopify connectors that will be released under opens-source licenses, probably this year.
All the static information — like products, categories, and other meta attributes — are synced with an Elastic Search NoSQL database, providing a query response time of around 0.1–0.3s on average (no cache) — even with hundreds of thousands of products. Elastic, with its query language, gives us flexibility with querying data so we don’t have to rely on any platform-related REST API queries or SQL.
The whole communication is queued using a special purpose frontend library called “syncTasks”. That was one of the key frontend design principles when designing the frontend. This means that most interactions are performed in under 100ms (which makes it “instantaneous” for the user), and just after that, synchronized with the backend.
The application is also stateless/sessionless so it’s extremely easy to scale horizontally. Additionally, we’re providing a dynamic SSR cache (a kind of output cache which is invalidated with changes regarding the specific products/categories included in each particular output page).
Recently we’ve launched our cloud offer — StorefrontCloud.io — for providing an efficient and scalable Vue Storefront hosting service. It’s based on Kubernetes + AWS. We’ve recently done some load and performance tests to check the results.
StorefrontCloud.io is very scalable and we performed the tests with the minimal hardware resources booked — just to focus on the application performance.
You can read more on the Storefront Cloud architecture here.
The env. resources:
- The vue-storefront Pod was limited to 1GB RAM + 1 CPU core,
- The vue-storefront-api Pod was limited to 512MB RAM + 0.5 (500 millicores) CPU core,
- The elasticsearch Pod was limited to 1GB RAM + 0.5 (500 millicores) CPU core.
So in total, it was 2.5GB of RAM + 2 CPU cores — a pretty minimal setup. It sounds like my desktop computer configuration from 2003 :-)
We scaled the Pods linearly to 3 instances of each (front + api) — load balanced through a Kubernetes Service object. So the app has in total 7.5GB of RAM + 6 CPU cores in the cluster.
We were using the Gatling testing suite to execute the tests, run from two separate testing nodes (outside the Kubernetes cluster).
We ran a few scenarios:
- StorefrontCloudLoadTesting: home page -> category -> product -> add to cart
- StorefrontCloudPerformanceTesting: 10 times per user: home -> category -> product add to cart
- StorefrontCloudStressTesting: we’ve been adding users incrementally with a 10s time-span and repeating 10 times: home -> category -> product -> add to cart
We ran the tests over and over, changing the number of concurrent users and requests.
Here we have the results for the Storefront Cloud Performance Testing run with over 2000 concurrent users (please note that the results are from one of two test servers — so you should multiply them by 2 to get the load which was put on StorefrontCloud).
We’ve achieved about 17 325 req/s with 48 348 active users at the peak with the performance test. The average error rate with all types of tests was under 1% (which is a very good result)
All the results with just 7.5GB RAM + 6 CPUs. As we’re on Amazon Cloud we can scale the resources up, almost without limits.