Course contentsShow
← Rust
Lesson 1759 of 1,91015. Performance and Architectural EngineeringFree lesson

Contention Management in Hotspots

Use sharded locking strategies to reduce collision rates in shared state.

In this lesson, you will learn how to use sharding to break up global lock contention by partitioning shared state into smaller, independent segments.

When multiple threads frequently access a single Mutex<T> or RwLock<T>, the lock itself becomes a bottleneck. Even if the actual work being performed inside the critical section is trivial, threads spend more time waiting for the lock than doing productive work. This is the classic "hotspot" contention problem.

The Sharding Strategy

Instead of protecting a single large structure with one lock, you split the data into NN distinct "shards." Each shard has its own independent lock. When a thread needs to access or modify a piece of data, it calculates which shard that data belongs to (typically using a hash function) and only acquires the lock for that specific shard.

This dramatically reduces the probability that two threads will attempt to acquire the same lock simultaneously, effectively increasing throughput by allowing parallel access to different parts of your data structure.

Practical Implementation

Consider a global cache. A naive implementation uses one Mutex. With sharding, we partition the data:

use std::sync::Mutex;
use std::collections::HashMap;

const NUM_SHARDS: usize = 16;

struct ShardedCache {
    shards: Vec<Mutex<HashMap<String, String>>>,
}

impl ShardedCache {
    fn get_shard_index(&self, key: &str) -> usize {
        // Simple hash to select the shard
        let mut hash = 0;
        for byte in key.bytes() { hash = hash.wrapping_add(byte as usize); }
        hash % NUM_SHARDS
    }

    pub fn insert(&self, key: String, value: String) {
        let idx = self.get_shard_index(&key);
        let mut shard = self.shards[idx].lock().unwrap();
        shard.insert(key, value);
    }
}

In this example, 16 threads can potentially perform operations concurrently, provided their keys map to different shards. The "cost" of this approach is a slightly more complex architecture and the potential for uneven distribution (if your hash function is poor), but the payoff is a significantly flatter contention profile under high load.

Key Takeaway: Sharding shared state into multiple isolated locks transforms a single global bottleneck into a granular, highly parallel system, minimizing the probability of thread collision.