

Join the discussion
Write your take first — we'll ask for email only when you're ready to publish.
- Hacker News
- Makes sense... if you are counting something in MySQL and now your counter is in Redis that's already strange
But I guess the point is that even in the MySQL scenario the 'reserved_quantities' is almost like a temporary table so either way is not the 'Real' inventory
by firasd - Could not they shard the inventory table by shop_id? As I understand, the order includes only items from one store, so there is no need to keep all the stores in a single table.
Also, I wonder why they could not have a row status (available/reserved) and UPDATE it instead of deleting the rows.
by codedokode - They never said they don’t shard it, however this doesn’t solve the problem they were facing. Even if they have a single store (therefore a single shard), the burst demand may be high for the item in that shop, which creates contention for “remaining item quantity” resource. Their solution spreads this contention across several rows.
> Also, I wonder why they could not have a row status (available/reserved) and UPDATE it instead of deleting the rows.
This requires a row per item unit, doesn’t it? If you have 50k units you’ll have to track status of every item, meaning 50k rows. They also mention this as a rationale to use at most 1k rows, and treat it as a buffer.
by soontimes - "But the hardest lesson wasn't about database design. It was discovering that the real bottleneck wasn’t what we were observing and measuring."by zhivota
- It's honestly weird Claude converges on this language because it's incredibly wordy and hard to parse.
One would think semantic density would win out in training.
by paytonjjones - But was it load bearing?by Horffupolde
- I wonder how we could handle that in a simpler way with durable workflows (e.g. Temporal, Restante, DBOS) – which are similar to Erlang processes but with persistent disk storage. This could avoid the need to maintain the 1000 row inventory.
Perhaps each shopping cart would have its own workflow, and the inventory item would have one as well. Then, whenever a customer put an item in their cart, their cart workflow would send a signal to the inventory item workflow and wait for the response. The inventory item workflow would maintain a ledger controlling to which cart each unit goes, and it could batch the writes to this table. This way, even if 100k customers try to purchase the same item in the same second, it should handle the load.
After the batch is written to the ledger, the inventory item workflow would reply signals to each cart workflow confirming that the reservation was completed. The end-to-end latency from the consumer point of view would be a fraction of a second, without needing the 1000-row hot-inventory heuristic.
- simplerby kandros
- Durable workflows are different, not necessarily simpler, imo. Unless the team is already familiar with them, I wouldn’t introduce one just for this. You also have to account for the infrastructure needed to run and manage the durable workflow itself, which adds complexity.by azuanrb
- Why is it so hard for many people to accept, that this is a solution for a specific problem of shopify? They did not say that Redis is bad and MySql is good. They only a solve their problem.by progx
- Even the good teams may make bad choices, that's why it is interesting to read their ideas and discuss themby gregoriol
- Is it really the right choice to drop Redis and go back to a disk based relational database just to wrap transactions into a single unit?
Redis handles tens of thousands of concurrent connections in a single event loop, while MySQL uses one thread per connection. No matter how I look at it, that seems like a step backward.
Of course, performance isn't everything. And if performance isn't a problem, having everything in one place does make it easier to reason about. But I'm worried that under spike traffic, this approach might actually cause more problems.
I think putting a scheduling layer in front of the DB would be a better approach. The application server could handle concurrent connections and only write to MySQL when correctness is actually needed. That seems like a cheaper way to do it. but is it different for large-scale enterprise distributed systems?
by jdw64 - Redis doesn't have transactions and persistence.
No persistence means the data gets lost if machine shuts down or process crashes. Furthermore, after restart you will need to regenerate the data which can take time. That's why Redis is a cache and not a database. You can fix the persistence issue (Redis can write WAL log, don't remember if it does fsync or not), but then Redis won't be able to handle those thousands of concurrent connections.
Redis (and other NoSQL storages) don't have some magic architecture that gives them advantages over SQL databases. They just cut corners on ACID guarantees and skip fsync. Once you start doing fsync, your transaction throughput will drop to SQL database level.
Redis also doesn't have transactions which means every app error damages the data. You will spend engineer hours investigating and fixing the problems. Transactions save so much time and worries.
by codedokode - not the best design to have 1000 rows for each shop*SKU combination. If a candidate proposed this solution during Shopify's System Design interview, i doubt he would be vetted for Senior+ position.
Instead of having 1000 rows per shop*SKU, why not just have one row per shopping cart*SKU?
That way a single row would represent a single cart, and will hold info of multiple items of the same SKU.
No need a cludge with 1000 rows limit and replenishment process. Instead of dealing with N rows, you always deal with a single row.
by bijowo1676 - > Instead of having 1000 rows per shopSKU, why not just have one row per shopping cartSKU?
At what point that row is inserted?
by soontimes - And that's why these interviews can be stupid, you can mention the real solution and interviewers might reject because it's not the textbook solution
But the real world is different
by raverbashing - Others are almost never as dumb as you hoped, and you’re rarely ever as smart as you think.by matwood
- Your mental model here is mapping too close to an actual cart in a retail, at a in person, setting.
The assumption that a SKU maps 1 to 1 to a cart item is flawed.
If the first item in the cart is a bundle of SKU-A and SKU-B, the second item is a bundle of SKU-A and SKU-C and the third item is 5xSKU-B where do you do you keep the re-agregation of the SKU-X's to track them?
This is without accounting for item location in the reservation - and rules that may apply around that.
You haven't even gotten to the part where different customers will have different rules around shipping from different locations - because that can eat into margins.
You're also making a bunch of other assumptions around transaction flow and where carts are actually stored (and how they get converted to an invoice, with payment attached) that likely do not hold true.
Could you do it more like what you're sugesting -- maybe -- but only in a single tenant system.
by zer00eyz - I have never worked anywhere where describing how their system actually works would pass the company's own system design interview
- > not the best design [...]
So those engineers at Shopify worked hard for months on a more performant system, but they missed the obvious structure? They chose a complex denormalization for no good reason?
It may be true, but I think it's presumptuous to belittle their work when we have only partial information. My guess is that they had good reasons to think that the more obvious ways would not scale.
And from reading your comments in this thread, I believe your structure would fail at their scale. A SQL query that uses 2 sub-queries with "group by" is probably too heavy. From the post, at peaks there would be millions of active shopping carts.
BTW, I suspect most orders are just for 1 or 2 of each item, so the denormalization is not as heavy as it seems.
by idoubtit - My main takeaway from this post is that in 2026 we haven't developed enough technology to scalably and durably handle concurrently decrementing a single number. This has caused multiple organizations to develop database hacks (the multiple rows) or complex architectural solutions (redis) which destroy the atomicity of the process.by jhhh
- The benefit of per row is that you can tag additional info like reserved user id etc, which you would have to track somewhere anyway.by winrid
- It seems there could be a simpler solution.
1. Deduct the reservation from the inventory when the user starts to order, but in the same txn also maintain a separate row for the in progress order flow. 2. If the order flow is aborted or times out have a background process that returns these to the inventory.
That seems simpler than this approach and involves no locking. Though their presented approach is also reasonable, there must be some reason not to choose a simpler flow. It is not that difficult to have a gc service that scales, but may be they didn't want to separate that.
by isignal - I was investigating Durable Objects (DO) and had Fable walk me through where in my app they might be appropriate. One place had a dependency with billing (where I use a transaction now) and the proposed re-work to allow for concurrent editing with DO looked very much like this, reservations with idempotency keys. And if you add hierarchical allotments then it scales pretty well.
I disagree with the other posters about the bg process, if you have any bg processing already you should be able to handle the few edge cases without too much trouble.
- now you have two problems. what happens when your reservation system backs up?by vxxzy
- Can you clarify why this involves no locking? There can still be 2 actors fighting for the same row.by soontimes
- The moment you added a background process you just replaced the complexity.
1. Backgrounds process can back up
2. They need context of the user and need to switch context per user
3. What if they fail, you create some DLQ or another process to handle the failure
4. Who looks on those failure and how do they act
TLDR; there is always a cost
by sandeepkd - My understanding is: your proposal is not very different from what Shopify is doing except they are tracking 'reserved units' (one per row) and you are proposing tracking 'orders' as the temporary state to then reconcile back with inventory quantities.by firasd
- Mostly unrelated but shopify is incredibly annoying. They introduced this delivery tracking app called "shop" and it has become unavoidable when buying electronics from china. Recently looked at it with mitmproxy and it ships home more than gets shipped to me.by sureglymop
- Mood. It's not just over-seas. With a domestic courier they still use dark-ui to hide the tracker link via "shop".by doublerabbit