Distributed counters pattern in Firebase - Time & Space Complexity
When using distributed counters in Firebase, it's important to understand how the number of operations grows as the counter updates increase.
We want to know how the work changes when many increments happen across multiple shards.
Analyze the time complexity of the following Firebase distributed counter update.
const shardId = Math.floor(Math.random() * numShards);
const shardRef = db.collection('counters').doc(counterId).collection('shards').doc(shardId.toString());
await shardRef.update({ count: firebase.firestore.FieldValue.increment(1) });
This code increments one shard's count randomly to spread load and avoid contention.
Look at what repeats when many increments happen.
- Primary operation: One update call to a single shard document per increment.
- How many times: Once per increment, distributed randomly across shards.
Each increment triggers exactly one update to one shard document.
| Input Size (n) | Approx. API Calls/Operations |
|---|---|
| 10 | 10 update calls |
| 100 | 100 update calls |
| 1000 | 1000 update calls |
Pattern observation: The number of update calls grows directly with the number of increments.
Time Complexity: O(n)
This means the total work grows linearly with the number of increments made.
[X] Wrong: "Updating one shard means the total work stays constant no matter how many increments happen."
[OK] Correct: Each increment still requires one update call, so total work grows with increments, not stays fixed.
Understanding how distributed counters scale helps you design systems that handle many users updating data without slowing down.
"What if we increased the number of shards? How would that affect the time complexity of increments?"
Practice
Solution
Step 1: Understand the problem with single counters
Single counters cause write conflicts when many users update at once.Step 2: How distributed counters solve this
Splitting the count into shards lets many users write to different parts, avoiding conflicts.Final Answer:
To avoid write conflicts by splitting counts into multiple shards -> Option AQuick Check:
Distributed counters = avoid conflicts [OK]
- Thinking it speeds up authentication
- Confusing with file storage
- Assuming it reduces bandwidth
Solution
Step 1: Identify how shards are stored
Each shard is stored as a separate document to allow independent updates.Step 2: Why multiple documents
Multiple documents reduce write conflicts by spreading writes across shards.Final Answer:
Multiple documents each representing a shard -> Option CQuick Check:
Shards = multiple documents [OK]
- Using a single document for all shards
- Confusing shards with user profiles
- Thinking shards are stored in storage buckets
const shardId = Math.floor(Math.random() * 5);
const shardRef = firestore.collection('counters').doc('counter1').collection('shards').doc(shardId.toString());
await shardRef.update({ count: firebase.firestore.FieldValue.increment(1) });Solution
Step 1: Understand shard selection
The code picks a random shard ID between 0 and 4 to update.Step 2: What update does
It increments the count field in that shard by 1, avoiding conflicts.Final Answer:
It increments the count in a random shard to reduce write conflicts -> Option AQuick Check:
Random shard increment = reduce conflicts [OK]
- Thinking it updates all shards at once
- Assuming shardId type causes error
- Believing it resets count instead of incrementing
Solution
Step 1: Check how total count is calculated
Total count must be the sum of all shard counts.Step 2: Identify missing sum
If you read only one shard or forget to sum, total will be wrong.Final Answer:
You forgot to sum all shard counts when reading the total -> Option BQuick Check:
Sum all shards for total [OK]
- Assuming incrementing same shard causes wrong total
- Confusing single document with shards
- Thinking random shard increments cause errors
Solution
Step 1: Understand update strategy
Incrementing a random shard spreads writes and avoids conflicts.Step 2: Understand read strategy
Summing all shards gives accurate total, though slightly delayed.Step 3: Why other options fail
Incrementing all shards wastes writes; single document causes conflicts; sequential increments cause bottlenecks.Final Answer:
Increment a random shard on each update and sum all shards when reading total -> Option DQuick Check:
Random increment + sum shards = best balance [OK]
- Trying to increment all shards each time
- Using single document counter under high load
- Incrementing shards in fixed order causing bottlenecks
Ready to prove it?
Pass the test and this pattern moves unknown
