Shard by shop: Shopify
Shopify split its MySQL fleet into pods by shop, then routed each request to the pod that owns it.
Shopify ran one large MySQL database until 2015, when buying a bigger server stopped being an option. The team sharded by shop_id, then went further: each shard became a pod with its own database, cache, and app servers. A load balancer component called Sorting Hat reads the shop from the request and adds a header that sends it to the right pod.
The system#
The pod is the unit of isolation. A pod holds a subset of shops, its own MySQL shard, Redis, and Memcached, and it can run anywhere. App servers and job workers are shared across pods, so a flash sale in one pod can use capacity from the rest of the region. In 2024 the platform peaked at 489 million requests a minute at the edge, 117 million a minute at app servers, and 14.8 trillion database queries over the weekend.
The board#
Drag to pan. Hold Ctrl or Cmd and scroll to zoom.
| Where | Setting | Value | Why |
|---|---|---|---|
| Load Balancer | Policy | least-conn | The load balancer sends each request to a copy with room, as Sorting Hat sends each shop to its pod. |
| App Server | Instance size | large | Large, because the monolith does the work for every shop. |
| App Server | Copies | 4 | The stateless app servers are shared across pods, so the board keeps them in one group. |
| Cache | Engine | memcached | Memcached scales with cores, which suits a cache shared by many app servers. |
| Cache | Cache strategy | aside | The app fills the cache on a miss and writes to the database, so the cache holds what shoppers read. |
| Cache | TTL (seconds) | 60 | A minute keeps catalog reads hot without long staleness. |
| Cache | Instance size | medium | Medium, sized for the hot catalog and shop rows. |
| Database | Shards | 4 | Each shard is another MySQL database, and the shops divide across them as they do across pods. |
| Database | Shard key | tenant | A tenant key keeps one shop’s rows together, which is the pod boundary. A huge shop can still make its shard the busy one, which is why Shopify gives big merchants their own pod. |
| Database | Engine | mysql | MySQL, the engine Shopify runs, with cheaper writes and online schema changes. |
| Database | Instance size | medium | Medium for each shard, so a hot shard shows. |
| Queue | Dead-letter queue | On | A job that keeps failing is parked, not retried forever. |
| Queue | Max length | 10000 | A full queue refuses work instead of hiding a growing backlog. |
| Worker | Instance size | small | Small, because a job is one shop’s work at a time. |
| Worker | Copies | 3 | Shared workers drain the queue for every pod. |
Research this Design needs: Load balancing, Caching, Message queues, Background jobs, Checkout, Sharding, Caching, Message queues, Background jobs.
The Database has four shards on a tenant key, which is the pod boundary. The Load Balancer stands for Sorting Hat, the Cache is the per-pod Redis and Memcached, and the Queue and Workers are the shared job tier. The Payment Provider answers checkouts.
Why it works#
A tenant key keeps one shop's rows on one shard, so most queries stay local and a failure stays inside one pod. The trade is the hot tenant: one huge shop can still make its shard the busy one, which is why Shopify gives big merchants a dedicated pod. Shard the database covers the general trade.
Where the game stops#
The board shards the database but keeps one set of app servers, because Quorum has no pod-level app tier. It also has no Sorting Hat, so the shard key does the routing that the header does at Shopify. The caption is Quorum's result, not Shopify's traffic.
Sources#
A Pods Architecture To Allow Shopify To Scale, Shopify Engineering: the pod, Sorting Hat, and why sharding alone was not enough.
Shard Balancing: Moving Shops Confidently with Zero-Downtime at Terabyte-scale, Shopify Engineering: how a shop moves between pods.
How we prepare Shopify for BFCM, Shopify Engineering: the 2024 peak numbers and the 2025 test plan.