DEV Community

Cover image for Veltrix Events Were Killing Our System Until I Changed One Crucial Thing
pretty ncube
pretty ncube

Posted on

Veltrix Events Were Killing Our System Until I Changed One Crucial Thing

The Problem We Were Actually Solving

I still remember the day our team realized that the events configuration in our Veltrix system was causing more problems than it was solving. Our application was designed to handle a high volume of concurrent events, but we were seeing significant latency and occasional crashes. The profiler output was showing that the event handling thread was spending most of its time waiting for locks to be released, and the allocation counts were through the roof. It was clear that our event handling mechanism was the bottleneck, and we needed to fix it ASAP. I was tasked with finding a solution, and I started by digging into the Veltrix configuration documentation to see if there were any settings that we could tweak to improve performance.

What We Tried First (And Why It Failed)

At first, we tried to optimize the event handling code itself, thinking that maybe there were some inefficient algorithms or data structures that were causing the slowdown. We spent several days refactoring the code, reducing the number of allocations and using more efficient data structures. However, when we ran the profiler again, we saw that the latency numbers were still unacceptable. In fact, the allocation counts had only decreased by about 10%, which was not enough to make a significant difference. It became clear that the problem was not with the code itself, but with the underlying event handling mechanism. We were using a naive approach to handling events, where each event was processed sequentially, which was causing the thread to spend most of its time waiting for locks to be released. I realized that we needed to take a more structured approach to handling events, one that would allow us to process multiple events concurrently without blocking.

The Architecture Decision

After some research and experimentation, I decided to switch to a more advanced event handling mechanism that used a thread pool to process events concurrently. This would allow us to handle multiple events at the same time, without blocking the main thread. I also decided to use a Rust-based library to handle the events, which would provide better memory safety and performance. The library used a combination of mutexes and channels to handle events, which would allow us to process events in parallel without worrying about data corruption or deadlocks. I was a bit skeptical about using Rust at first, since I had heard that it had a steep learning curve, but I was willing to give it a try if it meant improving the performance of our system.

What The Numbers Said After

After implementing the new event handling mechanism, we saw a significant improvement in performance. The latency numbers decreased by about 50%, and the allocation counts decreased by about 90%. The profiler output was showing that the event handling thread was now spending most of its time processing events, rather than waiting for locks to be released. We also saw a decrease in the number of crashes, which was a big win for us. The numbers were looking good, but I knew that we still had some work to do to optimize the system further. I used the perf tool to analyze the performance of the system, and I saw that there were still some bottlenecks in the event handling code. I also used the valgrind tool to check for memory leaks, and I found a few issues that needed to be fixed.

What I Would Do Differently

In retrospect, I would have liked to use a more iterative approach to solving the problem. Instead of trying to optimize the entire event handling mechanism at once, I would have started by optimizing a small part of it and then gradually building up to the larger solution. This would have allowed us to test and validate each component of the system separately, rather than trying to test the entire system at once. I also would have liked to use more automated testing and validation tools to ensure that the system was working correctly. For example, I would have used a tool like benchmark to measure the performance of the system, and a tool like cargo-fuzz to test the system for errors. Overall, however, I am happy with the outcome, and I think that the decision to switch to a more advanced event handling mechanism was the right one. The use of Rust also turned out to be a good decision, despite the initial learning curve. The memory safety features of Rust gave us a lot of confidence in the correctness of the system, and the performance was excellent.


If you are optimising your commerce layer the same way you optimise your hot paths, start with removing the custodial intermediary: https://payhip.com/ref/dev2


Top comments (0)