User Notification Throttling System: Design and Implementation with Confluent Kafka

Abhishek Raviprasad
6 min readJun 15, 2023

--

Designing an effective user notification throttling system is crucial for applications that need to manage large-scale user notifications while ensuring optimal performance and user experience. This article explores the design and implementation of such a system using Confluent Kafka, a powerful distributed streaming platform.

By leveraging Kafka’s capabilities, we propose a scalable and reliable solution that provides fine-grained control over notification delivery rates, minimizes resource utilization, and ensures timely and relevant notifications for users. In this article let us discuss the key components, architectural considerations, and implementation details of this user notification throttling system, empowering developers to enhance their notification infrastructure for better user engagement and satisfaction.

Architecture

At a high level, the architecture of the user notification throttling system using Confluent Kafka can be described as follows:

The central component of the architecture is Confluent Kafka, which serves as the backbone of the project. The architecture consists of three main parts:

Router: This component is responsible for consuming messages produced by various services and writing the data to a persistent storage system such as MongoDB. Additionally, the router writes these messages to a master topic in the Throttler system. The router can also perform message enrichment or any other necessary customizations.

Throttler: The throttler system ensures that notifications are throttled at the user level, limiting the number of notifications a user receives within a specific time period. The consumer in the throttler system reads all messages from the master topic for a defined throttle duration (e.g., y minutes). It stores metadata about the number of messages per user in an in-memory database like Redis. If a message does not require throttling, it is passed on to the sender system. However, if throttling is necessary, the message is placed in a backup topic.

At the end of the throttle period, the consumer toggles between the master and backup topics and processes the messages from the backup topic. This ensures that all messages in the backup topic are completely processed whenever the throttler restarts.

Sender: This component reads messages forwarded to it by the throttler system and delivers the notifications to the respective users. The notification system can be designed to support various types of notifications such as pop-up notifications, emails, and more.

This architecture provides a scalable and efficient approach to handle large volumes of notifications while ensuring proper throttling based on user preferences. By leveraging the capabilities of Confluent Kafka, the system ensures reliable message processing and timely delivery of notifications to users, enhancing their overall experience.

Project

This project consists of 4 components at high level,
1. Producer
2. Router System
3. Throttler System
4. Sender System

Github link of the project can be found here.

Producer component is a Python process that utilizes the Faker module to generate user notifications randomly. It leverages the capabilities of the Faker module to create realistic user notifications. The user names and job titles are randomly selected from a predefined list, ensuring diversity and variety in the generated notifications. By incorporating the Faker module into the Producer code, the notifications become more authentic and engaging, enhancing the overall user experience.

We then use confluent_kafka library to Produce the messages to the Confluent Kafka topic.

producer = Producer(conf)
producer.produce(topic, key=user_id, value=value, callback=delivery_callback)

Router component is a Python process responsible for managing the flow of user notifications within the system. It incorporates a Kafka consumer that reads messages from the topic where the producers have written the user notifications.

The consumer within the Router system subscribes to the topic, efficiently retrieves the notification messages, and performs necessary processing tasks. It ensures that the notifications are appropriately transformed or enriched based on specific requirements. Once the processing is complete, the Router component seamlessly writes the modified notification messages to the master topic of the Throttler system.

By acting as a bridge between the producers and the throttler, the Router component ensures the smooth transfer of notifications from the initial topic to the dedicated master topic. This enables subsequent components to access and process the notifications effectively, facilitating the implementation of throttling mechanisms and the eventual delivery of notifications to users.

consumer = Consumer(conf)
consumer.subscribe(['producer_topic'], on_assign=reset_offset)
while True:
msg = consumer.poll(1.0)
if msg is None:
print("Waiting...")
elif msg.error():
print("ERROR: %s".format(msg.error()))
else:
# Extract the (optional) key and value, and print.
key = msg.key().decode('utf-8')
value = msg.value().decode('utf-8')
print("{thread_id} {thread_name} Consumed event from topic {topic}: key = {key} value = {value}".format(
thread_id=thread_id, thread_name=thread_name, topic=msg.topic(), key=key, value=value))

Throttler component plays a crucial role in regulating the delivery of user notifications. It is implemented as a Python process and encompasses a Kafka consumer along with two Kafka topics, namely the master topic and the backup topic.

The consumer within the Throttler subscribes to the master topic, where it receives incoming notification messages. It diligently processes each message and makes a decision based on predefined criteria. If a message needs to be delivered without throttling, it is passed on to the Sender system for further processing and eventual delivery to the user. On the other hand, if throttling is required, the message is carefully placed in the backup topic for subsequent handling.

To maintain necessary metadata about the number of notifications sent per user, the Throttler component utilizes Redis as an in-memory database. This allows efficient tracking and management of the notification count at the user level, ensuring compliance with throttling rules.

At the end of each throttle duration, the consumer within the Throttler toggles its subscription topic, switching between the master topic and the backup topic. This mechanism ensures that all backed-up messages are processed in a timely manner, guaranteeing that no notifications are left unattended.

By effectively leveraging Kafka topics, Redis, and the toggle mechanism, the Throttler component successfully implements throttling logic, enabling controlled and balanced delivery of user notifications.

Sender component plays a crucial role in delivering user notifications to the intended recipients. It comprises a Kafka consumer, a Kafka topic, and a notification sender process.

The consumer within the Sender component subscribes to the Kafka topic specific to the Sender component. It actively listens for incoming notification messages, ensuring prompt retrieval of the notifications from the topic. Once a notification is received, the Sender component triggers the notification sender process, which is responsible for delivering the notification to the end user.

The notification sender process can utilize various notification mechanisms such as email, push notifications, SMS, or any other suitable means of communication. It ensures that the notification is sent to the intended recipient promptly and accurately, providing a seamless user experience.

By leveraging Kafka’s messaging capabilities and incorporating a dedicated notification sender process, the Sender component ensures the reliable and efficient delivery of user notifications, catering to the specific needs of the application or system.

In conclusion, designing a user notification throttling system using Confluent Kafka offers significant benefits in managing and controlling the delivery of notifications to users. By incorporating key components such as the Producer, Router, Throttler, and Sender, we can achieve a robust and efficient notification system.

With Confluent Kafka’s powerful features and flexibility, developers can design and deploy scalable notification systems that meet the needs of modern applications.

This article presents a high-level design for a user notification throttling system using Confluent Kafka. It is important to note that the presented design serves as a starting point and may require adjustments based on specific production requirements and the volume of notifications for each use case.

Continuous improvement and feedback are vital in refining the design and optimizing its performance. Therefore, I welcome any suggestions, insights, and feedback from readers to enhance and strengthen the user notification throttling system. By collaborating and iterating on the design, we can further optimize resource utilization, ensure scalability, and improve the overall user experience.

I would like to give a special shoutout to Apna’s platform team for sharing this problem statement during the recent Confluent Kafka Data World Tour. Their real-world challenges and insights have inspired the design of this user notification throttling system using Confluent Kafka.

Happy reading :-)

--

--

Abhishek Raviprasad

Senior Solution Engineer at Infoworks.io, 4+ years of big data/ETL data warehouse experience building data pipelines