DEV Community

Cover image for Category: Events
ruth mhlanga
ruth mhlanga

Posted on

Category: Events

The Problem We Were Actually Solving

In our previous implementations, we had been focusing on building the individual components of our event-driven system, such as the message broker, the event store, and the processing pipeline. We had chosen to use a default configuration for each of these components, assuming that it would be sufficient for our needs. However, as our system grew, we began to encounter issues that were not immediately apparent in the default configuration.

For example, our message broker was configured to buffer 10,000 messages at a time, which seemed like a reasonable number at first. However, as the volume of events increased, we began to experience message delays of up to 30 seconds, resulting in inconsistent results and frustrated users. Similarly, our event store was configured to store events for 30 days, which was based on a default retention period recommended by the vendor. However, as we analyzed our event data, we realized that we only needed to store events for 14 days, which would have saved us over 50% of our storage costs.

What We Tried First (And Why It Failed)

We attempted to address these issues by tweaking the default configuration of our individual components. For example, we increased the buffer size of our message broker to 50,000 messages, which seemed like a reasonable increase at the time. However, this change had unintended consequences, such as increased latency and resource utilization. We also attempted to reduce the retention period of our event store to 14 days, but this caused issues with our downstream processing pipeline, which relied on the historical event data.

The Architecture Decision

After struggling with these issues for several months, we finally realized that our default config approach was fundamentally flawed. We needed to adopt a more structured approach to our event-driven architecture, one that took into account the specific requirements of our system. We decided to adopt a hybrid architecture that combined the best of both batch and streaming processing, using Apache Kafka as our message broker and a custom-built event processing pipeline.

One of the key decisions we made was to adopt a topic-based partitioning strategy, where each event was assigned to a specific topic based on its type. This allowed us to scale our processing pipeline horizontally, while also reducing the load on our message broker. We also implemented a dynamic partitioning strategy, where the number of partitions was automatically adjusted based on the volume of events.

What The Numbers Said After

After implementing our new architecture, we saw a significant reduction in event delays and a corresponding increase in processing throughput. Our processing pipeline was able to handle over 1 million events per second, while our message broker was able to handle over 500,000 events per second. We also saw a significant reduction in storage costs, thanks to our reduced retention period and more efficient storage schema.

In terms of specific metrics, we saw a reduction in average event processing time from 30 seconds to 2 seconds, a reduction in message delays from 30 seconds to 1 second, and a reduction in storage costs by over 50%.

What I Would Do Differently

Looking back, I wish we had adopted a more structured approach to our event-driven architecture from the start. We could have saved ourselves months of frustration and resource utilization, not to mention the costs associated with rebuilding our system for the third time.

If I were to do it again, I would start by defining a clear set of requirements for our event-driven system, including performance, scalability, and consistency. I would then use these requirements to inform our architecture decisions, including the choice of message broker, event store, and processing pipeline. I would also adopt a more formal approach to testing and validation, to ensure that our system is meeting our performance and scalability requirements.

Ultimately, building an event-driven system requires a deep understanding of the underlying architecture decisions and tradeoffs. It is not just about choosing the right technology, but about designing a system that meets the specific requirements of your use case. By adopting a more structured approach to event-driven architecture, we can build systems that are more scalable, more efficient, and more reliable.

Top comments (0)