🎓 A1Learner
🔍
0 of 64 lessons completed

Design Shopify

Shopify is a platform that runs many separate online stores for many separate sellers. Multi-tenancy means those stores share one running platform while each store's data, traffic, and settings stay separate.

The ask

Shopify runs online stores for sellers who never operate servers. A seller signs up, adds products, and sells under a personal storefront.

Multi-tenancy means many separate customers, called tenants, share one running platform. Each store is one tenant.

Sharing the platform keeps each store cheap to run. Separation keeps each store safe from the others.

One store's data must never appear in another store's pages. That rule covers products, orders, customers, and reports.

One store's busy day must never slow another store down. Isolation covers traffic as well as data.

Estimate the scale

The platform runs 1,000,000 stores. The average store takes 100 orders a day.

1,000,000 stores x 100 orders = 100,000,000 orders a day across the platform.

100,000,000 orders / 86,400 seconds = 1,157 orders per second.

Traffic is deeply uneven across stores. Most stores are quiet on any given day, and a few stores are enormous.

Averages therefore mislead capacity planning. The design must hold both the steady total and one store's sudden burst.

API and data

Every request carries a store ID. The store ID comes from the signed-in session or the storefront address, never from a field the buyer can edit.

Get storefront takes a store ID and a page name. It returns that store's products, prices, and theme settings.

Place order takes a store ID, a cart, and an idempotency key. The order belongs to that store alone from the first write.

Every stored record carries its store ID in its key. Products, orders, customers, and discounts all follow the same rule.

A settings record holds the store's theme, tax rules, and payment details. Settings are data, so one shared program serves every store's look.

High-level design

One shared set of app servers runs every store. A request arrives with a store ID, and the servers load only that store's data.

Stores are grouped onto database shards by store ID. One shard holds many stores, and consistent hashing places each store on exactly one shard.

Storefront pages are cached per store. The cache key includes the store ID, so pages from different stores can never mix.

Background jobs carry a store ID as well. Reports, exports, and emails for one store run inside that store's limits.

Very large stores can move to a shard of their own. The move changes placement, not the program or the data shape.

Data isolation

The store ID is checked on every read and every write. A query without a store ID is rejected before it reaches the database.

Isolation is tested like a security boundary. Automated checks send one store's credentials against another store's records and require refusal.

Backups and restores also respect the boundary. A restore for one store writes only that store's rows.

Platform staff tools show one store at a time. Even support access follows the same store ID rule.

Deep dive: one store's sale

A noisy neighbour is one tenant whose heavy traffic harms the other tenants sharing the platform. One store's sale is the classic case.

The sale scenario is stark. One store takes 1,000,000 orders in its sale hour.

1,000,000 orders / 3,600 seconds = about 278 orders per second for that one store.

1,000,000 sale orders / 100 normal daily orders = 10,000 times its normal daily count, inside one hour.

That one store alone produces a large share of the whole platform's order flow. Without isolation, its checkout queue fills the shared workers.

Per-store rate limits cap the requests one store can push through shared paths. The cap rises for a store's own paid plan, never without bound.

Queues are fair across stores. Workers take jobs in turns across stores, so a sale store's report waits behind its share, not ahead of everyone.

The sale store can also be moved early. A store that announces a sale is placed on roomier shards before the sale starts.

Storefronts and checkout

Storefront reads are mostly cache hits. Product pages change rarely, and each store's popular pages stay warm in its own cache space.

Checkout stays store-scoped end to end. Stock, discounts, and taxes all come from the one store's records.

Themes change how a store looks, not how the platform runs. A theme is stored settings and templates, applied at render time.

Extra store features arrive as add-on apps with limited permissions. An add-on sees only the store that installed it, through the same store ID checks.

When parts fail

A failed shard takes its stores offline, not the whole platform. Replicas of the shard take over, and other shards never notice.

Sharding contains failure by placement. Grouping stores is what keeps one failure small.

A runaway job is stopped by its store's limits. The platform kills the job and keeps the store's neighbours running.

A bad platform release reaches stores in waves. A small group of stores gets the release first, and a fault stops the rollout before most stores see it.

Evaluation and trade-offs

Sharing one platform trades isolation effort for low cost. Every query pays a store ID check, and every store avoids running private servers.

Grouping many stores per shard trades placement flexibility for efficiency. A giant store can earn a private shard, at a higher operating cost.

Per-store limits trade one store's peak for everyone's steadiness. A sale store is slowed before its neighbours are.

The design fits because the tenant boundary is one simple rule everywhere. The store ID rides on every request, record, cache entry, and job.

Scale of the platform

WorkCountRate
Stores1,000,000—
Orders, all stores100,000,000 a day1,157 per second
Orders, one sale hour1,000,000278 per second

Exercise

One store starts a huge sale while the other stores stay quiet. What protects the quiet stores?