Improving front-end performance for high-availability websites

Chris Kelly, our Senior Developer, gets technical about creating a scalable website that manages ultra-high loads and works for people with poor internet connections.

 

High-availability websites are crucially important for providing critical, time-sensitive information.

On a quiet day, across Victoria and its neighbouring states of SA and NSW, the VicTraffic platform displays upwards of 8,000 notifications about disruptions to roads in these areas. During an emergency event this can be much higher. Road-users can visit the site to rapidly identify any roads that are closed or where traffic flow is disrupted by viewing a map with simple icons, or reading a list of disruptions. 

Symbiote successfully delivered this VicTraffic project to the Victorian public in 2024.

This platform is an example of the type of site that needs to be robust, usable and trustworthy, because failing to communicate critical road information during emergencies could be a matter of life and death.

If a site like VicTraffic were to go offline due to high load, when people were seeking information about safer routes during a bushfire, extreme weather event, or other emergency, at-risk Victorians wouldn’t be able to access critical information about whether roads were open or closed. 

We know that many people in rural and regional areas have patchy internet access, so it was essential for us to build a product that scales in response to spikes in traffic (both the literal and digital kind!), while performing well on older devices and for users with poor connectivity.

Let’s dig into the technical side of how we solved some front-end challenges to radically improve the site’s performance so it would keep delivering critical data even during a sudden influx of hundreds, thousands or even millions of visitors.

 

Creating a scalable system

There are many factors involved in creating a scalable system. The handling of these extreme fluctuations in traffic requires a well-architected solution design from the ground up. Infrastructure, backend and front end all play their part. 

For the VicTraffic project, Symbiote leveraged AWS serverless architecture that is scalable by design. Each service was selected for its ability to automatically scale horizontally under load without any human intervention.

Horizontal scaling allows the site to handle increased demand by spreading out the workload among many instances, which only come online as needed. Typically the instance is only online for the time it takes to serve the request. This is in comparison to vertical scaling, where there are fewer instances but they are scaled up with additional resources such as CPU/memory during high load events. 

Horizontal scaling allows us to avoid the resource limitations of vertical scaling while also being cost effective and more fault tolerant.

For VicTraffic, heavy data processing is handled asynchronously as background jobs via EventBridge, Lamba, SQS, SNS, ElastiCache and S3. The data delivery side of the backend revolves around API Gateway, Lambda, Dynamo and RDS. We also use many other services within the AWS ecosystem to support these APIs and manage user-centric data.

On the front end, Symbiote made heavy use of canvas rendering, virtualized windows and a highly optimised React setup to minimise rerenders. The front end handles thousands upon thousands of disruptions at any given time, so we need to ensure a smooth, jank-free experience for all Victorians, regardless if they are on the latest iPhone or using older digital devices. 

What’s jank? I’m glad you asked.

 

Jitter and jank – addressing performance issues

Early in development it became apparent that the front end was suffering from two performance issues: jitter and jank. 

Each set of icons you see on the map in Image 1 indicates a different type of road-related situation or event that could affect traffic flow – these are collectively called ‘disruptions’.  

Jitter was a noticeable ‘laggy’ effect that occurred when performing visually intensive tasks such as panning and zooming a map containing many disruptions.

The main culprit causing the jitter was rendering the disruption markers and cluster bubbles in the DOM (Document Object Model) – as shown below in Image 1.

While the DOM makes sense for most typical sites made of simple windows and forms, it can be intense for the browser to move, zoom and render thousands of dynamic elements as a user navigates rapidly around a map. 

 

Image 1: The VicTraffic progressive web app displays all road disruptions in two ways – in a list on the left, and as disruption markers and cluster bubbles on the map on the right.

 

To resolve this, we shifted all disruption markers and clusters onto the canvas, embedding these elements as layers within the map itself. While more difficult to work with, the canvas is designed to handle graphically intense interactions, and it does it extremely well. This freed the DOM to handle the more routine elements of the site. 

We created several stress tests to prove the canvas version outperformed the DOM version. This included one test we affectionately nicknamed the ‘zombie outbreak’, where we loaded such an extreme amount of mock disruption data that it appeared to be some kind of apocalyptic event. 

View the ‘zombie outbreak’ stress test of road disruption data here. (G-rated, mp4 video that doesn’t contain actual zombies, just a lot of mock road disruption data on a map.)

 

Jank, on the other hand, makes a site appear to freeze temporarily. While there may be several reasons for this, it typically occurs when browser memory is saturated to the point that it has nothing left in the tank to process user events.

To address the jank situation, we sectioned off chunks of the application to monitor each major component’s memory usage over time with a combination of browser-based tooling and automated tools. More importantly, we monitored if the memory baseline stabilised over time. If it didn’t, it indicated memory leaks existed within the component. 

The cause of the memory leaks varied between components, but the most common causes were unnecessary data processing and unnecessary rerenders, or the latter causing the former and vice versa. We methodically resolved each memory leak by addressing the rerenders and removing all unnecessary data processing. 

This halved memory usage within the application, leaving users with a jank-free experience.

These were just some of the solutions we applied to improve the front end performance for this high-availability website.

 

 

Read the case study …

Previous
Previous

Cost-effective ways to keep your legacy systems working for you

Next
Next

Why our 4-day work week is so successful