Implement and compare round-robin and consistent hashing
Company: DoorDash
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Overview: This question evaluates a candidate's ability to implement and reason about load balancing algorithms (round-robin and consistent hashing), covering competencies in data structures, hashing, concurrency, correctness, and unit testing.
Read the full DoorDash Software Engineer interview experience this question came from
Part 1: Round-Robin Load Balancer Simulator
Constraints
- 0 <= len(nodes) <= 10^4
- 0 <= requests <= 10^4
- start_index is -1, or 0 <= start_index < len(nodes)
- Node status is a string; only 'UP' counts as available
Examples
Input: ([('A', 'UP'), ('B', 'UP'), ('C', 'UP')], -1, 5)
Expected Output: (['A', 'B', 'C', 'A', 'B'], 1)
Explanation: Normal round-robin over three healthy nodes.
Input: ([('A', 'UP'), ('B', 'DOWN'), ('C', 'UP')], -1, 4)
Expected Output: (['A', 'C', 'A', 'C'], 2)
Explanation: Node B is skipped every time, and the index must persist across picks.
Hints
- Do not reset the index for every request; it should continue from the last successful selection.
- For one request, you never need to inspect more than n nodes. If none are 'UP', append None.
Part 2: Consistent Hashing with Virtual Nodes
Constraints
- 0 <= len(initial_nodes) <= 10^3
- 1 <= virtual_nodes <= 100
- 0 <= len(operations) <= 10^4
- Operation type is one of 'ADD', 'REMOVE', 'GET'
- Adding an existing node or removing a missing node should leave the ring unchanged
Examples
Input: (['A', 'B', 'C'], 2, [('GET', 'bZ', []), ('GET', 'dZ', []), ('GET', 'dZ', ['B']), ('REMOVE', 'B'), ('GET', 'dZ', []), ('ADD', 'D'), ('GET', 'iZ', [])])
Expected Output: ['A', 'B', 'C', 'C', 'D']
Explanation: Shows basic lookup, fallback when the initial target is down, removal, and later addition.
Input: ([], 3, [('GET', 'abc', []), ('ADD', 'A'), ('GET', 'abc', ['A']), ('GET', 'abc', [])])
Expected Output: [None, None, 'A']
Explanation: Edge case: empty ring first, then the only node is temporarily down.
Hints
- Keep the ring sorted so you can binary-search the first virtual node whose position is >= the key hash.
- If the first matching node is down, walk clockwise through the ring and stop after one full cycle.
Part 3: Choose Between Round-Robin and Consistent Hashing
Constraints
- 0 <= len(scenarios) <= 10^5
- 1 <= n, v <= 10^6
- 0 <= r, k, c, h, f <= 10^9
- a is either 0 or 1
- Use 64-bit integer arithmetic
Examples
Input: ([(4, 10, 100, 1000, 2, 1, 5, 3)],)
Expected Output: ['consistent_hashing']
Explanation: High churn plus cache affinity favors consistent hashing despite its ring cost.
Input: ([(4, 10, 100, 1000, 0, 0, 0, 0)],)
Expected Output: ['round_robin']
Explanation: No cache affinity and no membership changes make round-robin cheaper.
Hints
- You can compute ceil(log2(x)) for x > 0 as (x - 1).bit_length().
- Evaluate both formulas exactly for each scenario, then compare and handle the tie case.