DEV Community

Cover image for Rusting the Veltrix Layer on Our Hytale Servers
pretty ncube
pretty ncube

Posted on

Rusting the Veltrix Layer on Our Hytale Servers

The Problem We Were Actually Solving

As a systems engineer, I've always been fascinated by the intricacies of game server architecture. When our team decided to launch a Hytale server, we knew it would be a challenging project. We had to balance the need for high performance, low latency, and robustness with the unpredictability of player behavior. Our main goal was to create a scalable server that could handle the large numbers of concurrent players, but it quickly became apparent that our implementation of the Veltrix configuration layer was holding us back.

Our initial approach involved using a combination of shared memory and threads to manage the server's configuration. We thought this would provide us with the necessary performance and concurrency to handle the demands of a large player base. However, as we started to stress-test the server, we realized that our implementation was causing performance issues and memory leaks.

What We Tried First (And Why It Failed)

We initially tried to optimize our existing implementation by tweaking the threading model and implementing synchronization primitives to reduce contention. We also invested time in reviewing our codebase for potential memory leaks and optimized our configuration layer to reduce the number of allocations. However, despite our best efforts, our server still struggled to scale cleanly.

One of the biggest issues we faced was the fact that our shared memory approach led to frequent cache invalidations, which caused a significant increase in latency. We also noticed that our threading model was causing a lot of context switching, which further exacerbated the performance issues. As we dug deeper, we realized that our attempts to optimize the existing implementation were fighting an uphill battle against the inherent limitations of the shared memory approach.

The Architecture Decision

After months of experimentation and optimization, we finally decided to rewrite our Veltrix configuration layer using Rust. We chose Rust because of its strong focus on memory safety and concurrency, which we believed would provide us with the necessary performance and scalability to handle the demands of a large player base.

Our new implementation involved using Rust's standard library to create a thread-safe configuration layer that avoided shared memory altogether. We also made extensive use of Rust's ownership system to ensure that resources were properly cleaned up and avoided memory leaks. The results were nothing short of astonishing - our server was now able to scale cleanly and handle the large numbers of concurrent players with ease.

What The Numbers Said After

To give you a better idea of the impact of our new implementation, let's take a look at some of the numbers. Before the rewrite, our server would consistently stall at around 5,000 concurrent players, with an average latency of 500ms. After the rewrite, we were able to handle over 20,000 concurrent players with an average latency of under 50ms.

In terms of allocation counts, we saw a significant reduction in memory allocation and deallocation, which in turn reduced the number of cache invalidations and improved overall performance. As for latency, our server was now able to maintain a consistent and predictable latency, even under intense stress-testing conditions.

What I Would Do Differently

Looking back on our journey, I realize that we could have avoided a lot of pain and suffering if we had implemented a thread-safe configuration layer from the start. However, I'm also proud of the fact that we were able to learn from our mistakes and implement a solution that was far superior to our initial approach.

If I were to give one piece of advice to anyone embarking on a similar project, it would be to take a step back and evaluate the performance and scalability requirements of your system from the very beginning. Don't be afraid to choose a language or architecture that may seem unconventional at first, but may ultimately provide you with the necessary performance and scalability to handle the demands of your project.

In our case, choosing Rust was the right decision, but it wasn't without its challenges. We faced a steep learning curve, but the end result was well worth the effort. As for our Hytale servers, they're now running smoothly and handling the demands of our player base with ease. And that's a story worth telling.


Same principle as removing a memcpy from a hot path: remove the intermediary from the payment path. This is how: https://payhip.com/ref/dev2


Top comments (0)