In this lesson, you will learn how to intelligently distribute tasks across multiple Node.js consumer instances using three fundamental load-balancing strategies.
When you have a high volume of background jobs, sending them all to a single consumer creates a bottleneck. To scale horizontally, we employ load balancing algorithms to decide which worker instance receives the next message from the queue.
1. Round-Robin
This is the simplest approach: messages are distributed sequentially to consumers in a circular order.
- Best for: Homogeneous workloads where every task takes roughly the same amount of time to process.
- The logic:
nextConsumer = (lastIndex + 1) % totalConsumers.
2. Least-Loaded
Instead of rotating blindly, the dispatcher tracks how many active tasks each worker is currently handling. It dispatches the next message to the consumer with the lowest number of "in-flight" jobs.
- Best for: Heterogeneous workloads where some tasks are computationally expensive and others are trivial.
- Node.js implementation insight: You can maintain a local counter for each worker. When a job starts, increment; when the
ack(acknowledgment) is received, decrement.
// Conceptual Least-Loaded Dispatcher
const workers = [{ id: 1, load: 0 }, { id: 2, load: 0 }];
function dispatch(task) {
const target = workers.sort((a, b) => a.load - b.load)[0];
target.load++;
runTask(target, task).then(() => target.load--);
}
3. Sticky Worker (Consistent Hashing)
Sometimes, tasks must be processed by the same worker instance to leverage local caching or preserve state. Sticky routing uses the message metadata (like a tenantId or userId) to ensure that messages with the same key always go to the same consumer.
- Best for: Scenarios where warming up a cache or managing local memory state is critical for performance.
- The logic:
consumerIndex = hash(message.key) % totalConsumers.
Choosing the Right Strategy
- Use Round-Robin for simplicity when tasks are identical.
- Use Least-Loaded to prevent worker overload when task duration varies significantly.
- Use Sticky Routing only when your application architecture strictly requires data locality or stateful processing.
Key Takeaway: Select your balancing algorithm based on task duration variance; use Round-Robin for uniform loads, Least-Loaded for unpredictable processing times, and Sticky Routing when data locality is a performance requirement.