你以为高并发的库存系统离不开 Redis?Shopify 工程团队用一次「反向迁移」给出了另一种答案:他们把库存预留系统从 Redis 搬回 MySQL,并在 2025 年黑色星期五扛住了峰值——当时平台每分钟销售额达到 510 万美元。Shopify 支撑着美国超过 14% 的电商交易。

旧方案的问题出在「两套账」。库存计数存在 Redis 里(占用就减、释放就加),但真正的库存总账在 MySQL。两步没法打包成一个原子操作,一旦顺序出错,就会出现超卖(东西卖了却没从总账扣掉)或幽灵库存(扣了却还显示占用)。Redis 也不感知多仓库库存,还得单独养一个集群。
新方案靠的是 MySQL 8 的 SKIP LOCKED 特性。核心思路是「每个可售单元存一行」,而不是「每个商品存一行数量」。一件有 10 件库存的商品就对应 10 行,预留 3 件就是一次性锁 3 行、挪进预留表。为避免行数爆炸,每个商品/仓库最多维持 1000 行可用池,不够了再由补充进程从总账补齐。SKIP LOCKED 让并发请求跳过被锁的行、直接拿别的可用行,不用排队。
几个工程细节值得记:把主键改成复合主键(店铺、商品、分组、序号),每行锁从两把降到一把;把事务隔离级别从默认的「可重复读」降到「读已提交」,避开空表补充时的间隙锁死锁;统一「先删后插」的锁顺序,消除预留与扣减路径间的循环等待;再用 UNION ALL 把一单多件的查询合并成一次往返。
最有意思的是真瓶颈不在数据库。调完表结构,吞吐量还是卡在目标线下,CPU 也没跑满。团队给每条 SQL 打上业务标签(例如「conn_tag:checkout_completion」),在数据库代理层按调用方统计连接占用时长,才发现是结账链路上的其他环节长时间霸占连接。清理掉这些长事务后,主库读操作减少 50%、事务数减少 33%。
迁移采用影子模式:Redis 和 MySQL 双写一段时间,确认无误再逐步把「真相源」切到 MySQL,并保留一键回滚。
说白了,很多「必须上 Redis」的判断,只是因为当年 MySQL 还没有 SKIP LOCKED 这类能力;如今你手上的数据库往往就够用。真正的瓶颈常常藏在代码里的连接管理,而不是引擎本身。下次想引入新中间件之前,不妨先看看现有数据库的新特性和连接画像。
来源:Shopify 工程博客(作者 Emilie Noel,2026-05-12)







