chris@gmail.com and divide it by 4 to get a remainder. You need a deterministic rule that converts any arbitrary value into a number so you can pick a shard and ensure even distribution.
That rule is a hash function. A hash function takes an input (like chris@gmail.com) and returns a reproducible digest (a sequence of bytes or a hex string). Convert that digest to an integer and take the remainder modulo the number of shards to get a shard index. Crucially, the hash must be deterministic: applying it to the same key always yields the same value so the user always maps to the same shard.
Most languages provide well-tested hashing libraries. In Python, use hashlib (MD5, SHA-1, SHA-256, etc.) for deterministic hashing. Avoid Python’s built-in hash() for sharding because it is salted per interpreter process and will produce different values across restarts — unsuitable for persistent, cross-process routing.
Use deterministic hash functions (from
hashlib) for sharding. Avoid Python’s built-in hash() for persistent or cross-process sharding because it is salted per interpreter process.- MD5 is fast and evenly distributes keys; collision resistance is usually not required for sharding.
- If you need cryptographic guarantees, use SHA variants (e.g., SHA-256).
- The important properties for sharding are determinism and a uniform distribution across shards.
- Hash the shard key (e.g., user ID or email).
- Convert the hash digest to a numeric value (e.g.,
int(hex_digest, 16)). - Compute
numeric_hash % num_shards. - Use the remainder as the shard index (0..N-1).

- Do not hash. Assign each shard a contiguous range of values.
- Example: split by date into quarterly shards (Jan–Mar, Apr–Jun, Jul–Sep, Oct–Dec) if most queries request date ranges.
- Pros: Range queries (e.g., “all my March transactions”) hit a single shard, making them efficient.
- Cons: Writes tend to concentrate on the current range, producing write hotspots.

- Maintain a central lookup (directory) that maps each key (customer, group, etc.) to a shard ID.
- Flexible: you can route very large customers to dedicated shards by updating the directory.
- Pros: Manual control over placement, easy to isolate hot customers.
- Cons: Every request must consult the directory; the directory becomes critical infrastructure and must be highly available and fast.

- Place data by region (Europe, Asia, US) to reduce latency and meet residency requirements.
- Often implemented as two-level routing: first route by region, then within the region use hashing or range sharding to spread load.
- Pros: Lower latency and easier compliance with regional regulations.
- Cons: Adds complexity to routing and cross-region queries.

Which method should you use?
- Range sharding: choose this when most queries are range-based (dates, numeric ranges).
- Hashing: ideal when most queries are single-key lookups (user profiles, item lookups).
- Directory sharding: useful when a small number of tenants are huge and must be placed manually.
- Geographic sharding: use when latency or legal/regulatory requirements demand regional placement; commonly implemented as region-first, then hash within the region.
- Application server: Common choice — the app computes the shard and opens a connection to the right database. Pros: low latency, simple. Cons: changes to shard topology require app deployments or a dynamic config mechanism.
- Middleware / Router / Proxy: A routing layer (API gateway, DB proxy, or service mesh) can centralize routing logic and shard configuration. Pros: simpler operational changes, single place to update topology. Cons: adds another network hop and operational component.
- Directory service: For directory sharding, a fast, highly available lookup service (cached aggressively) is required before the app can connect to the target shard.
- Keep the routing logic deterministic and stateless when possible so any machine can route requests locally.
- Version your shard-mapping logic and provide a migration plan when changing shard counts (see consistent hashing or resharding patterns).
- Cache directory lookups with TTLs to reduce lookup overhead and protect the directory from high traffic.
- Python hashlib docs: https://docs.python.org/3/library/hashlib.html
- Database sharding (overview): https://en.wikipedia.org/wiki/Shard_(database)
- MD5 (brief): https://en.wikipedia.org/wiki/MD5
hashlib) gives even distribution and simple, local routing.