DEV Community

Cover image for Building a Treasure Hunt Engine That Doesn't Torpedo Your Server Scaling Efforts
mary moloyi
mary moloyi

Posted on

Building a Treasure Hunt Engine That Doesn't Torpedo Your Server Scaling Efforts

The Problem We Were Actually Solving

We had a robust recommendation engine, which we proudly called the "treasure hunt engine," because it used a complex algorithm to suggest relevant items to our users based on their search history and preferences. The problem was that this engine was causing our backend services to scale exponentially, leading to bottlenecks and eventual outages. Our metrics indicated that the search engine was responsible for a whopping 70% of our service calls, which was unsustainable in the long run. I recall our lead engineer proclaiming, "We're making a killing on search volume!" – and, in hindsight, that's when the trouble began.

What We Tried First (And Why It Failed)

Initially, we tried to optimize our search engine for better performance by tweaking the search algorithm and indexing schema. We used tools like Elasticsearch and Apache Solr to improve our search query performance, but it only led to a minor 3% reduction in latency. Our operators were ecstatic at first, but soon realized that the reduced latency was a drop in the ocean compared to the overall scaling issues. We also experimented with caching and pagination, but they only mitigated the symptoms rather than addressing the root cause. Our metrics showed a slight decrease in 99th percentile latency, but our server scaling events continued unabated.

The Architecture Decision

It was then that I made the call to decouple our recommendation engine from the main service. We implemented a queue-based architecture, where the main service would send search queries to a separate service (which we dubbed the "treasure hunt API"). This API would then process the queries and send back the results to the main service, which would render the pages. The result was a substantial reduction in our server scaling events, as the main service was now only responsible for rendering the UI, rather than processing complex search queries. Our metrics indicated a whopping 85% reduction in server scaling events, and our operators breathed a collective sigh of relief.

What The Numbers Said After

After implementing the new architecture, our metrics showed a significant improvement in our server scaling events. Our main service was now able to handle our user base without issues, and our recommendation engine was no longer the bottleneck it once was. We also saw a significant reduction in our latency, with the 99th percentile latency now sitting at a respectable 200ms. Our search volume was still high, but our service was now able to handle it without breaking a sweat. I recall our lead engineer saying, "We've got to get this tech out to production!" – and, in hindsight, that's when we finally got it right.

What I Would Do Differently

Looking back, I would have made the decision to decouple our recommendation engine from the main service much earlier in the development cycle. I would have also invested more time and resources in testing and validating our architecture before deployment. Our operators would have appreciated the reduced server scaling events and the improved latency, and our users would have enjoyed a seamless user experience. As for our lead engineer, I would have reminded him that it's not about the search volume – it's about designing a system that doesn't self-destruct when our user base surges.

Top comments (0)