The need for speed
People tend to be impatient. If a delay is introduced into any process, whether it be driving on the road or being placed on hold, a person’s satisfaction goes down. The same holds true for the internet.
According to research by Google, 53% of site visits are abandoned if pages take longer than 2 seconds to load, and a 2-second delay in load times result in abandonment rates of up to 87%.
On top of customer satisfaction, search engine rankings are heavily impacted by site performance. Getting ranked higher than your competitors equates to more visibility and more revenue. This is why we constantly strive to improve Spokeo’s tech stack and get our pages to load as fast as possible.
Where it all began
Spokeo has been using Ruby on Rails (RoR) since 2006 to serve it’s massively-scaled dynamic website with billions of unique URLs.
Rails is a model–view–controller (MVC) framework, providing default structures for a database, a web service, and web pages. By using Rails, you can stand up a new website very quickly. It’s very developer friendly and allows for quick turnaround time from an idea’s inception to its implementation. As one of the most popular MVC frameworks, Rails should be applauded for its role in bringing Spokeo to where we are today.
However, RoR has some drawbacks as well:
- The web server’s boot speed is incredibly slow.
- The built-in rendering engine performs poorly.
- Ruby is bad at multithreading.
These bottlenecks are not significant when compared to the valuable time savings for developers when creating an application – however they start to become an important constraint as a website becomes mature, full-featured, and heavily-trafficked.
The Crux of the problem
HAML. When spoken out loud it sounds delicious. This HTML Abstraction Language is the RoR standard that Spokeo has historically used to build its web page templates. This worked as a solution for a long time. However, as the HAML templates got more complex, the slower our pages became. We noticed that there was a linear increase in render times as the number of partials (template files included from within other template files) increased in our HAML templates. For example, a template would have the following: layout → header → content(table, loop → row partial) → footer
All of this could easily translate into 20-30 partials. As more page elements get added, the page slows down further.
[Caption]: Photo by Radowan Nakif Rehan
Ruby is not thread safe. The Rails framework protects us from this fact by wrapping everything in a giant mutex lock. In order to serve the high demands of web traffic, we turn to multiple processes. After a while it becomes inefficient to scale. You’re spending a ton of time spawning new processes which use up precious system resources.
We want to improve webpage rendering times, but we don’t want to throw the baby out with the bathwater. Spokeo leverages much of the Rails framework, and we exhaustively benchmarked all parts of our application. After years of refinements, we determined that the final and best opportunity lied in swapping the ‘View’ part of Rails MVC with something faster. Let’s use Node.js!
There are many advantages to using Node.js:
- Non blocking I/O
- Excellent asynchronous request handling
- Low memory footprint
- Smarter caching
- Superior connection handling capability (a result of the above factors)
By using Node.js and leveraging React to render our pages we can have our cake and eat it too. And so we built an internal microserver for rendering, code-named “Salsa”.
Salsa is a Node app which leverages React to render pages. What we discovered after our testing is that the render time did not increase linearly with the number of components on the page, unlike HAML.
Now we get to keep the slick Model and Controller aspects of Rails while using the superior speed of Node.js for the View, and we can boost our site performance and scale more requests!