Shopify库存预留难题:从Redis到MySQL,突破高并发交易瓶颈!
【导语:在电商系统中,库存预留操作至关重要。Shopify此前依赖Redis运行超卖保护系统,转向统一数据库战略时面临MySQL能否扛住规模的问题。经探索,Shopify实现了从Redis到MySQL的切换,为高吞吐互斥场景提供了新思路。】
Shopify原有的Redis系统中,每件商品有一个quantity key,预约库存执行DECR命令,释放执行INCR。但预约和库存账本分别存在于两个不同的系统,支付成功后更新MySQL和清理Redis无法在单一原子步骤中完成,可能导致超卖或欠卖。
此外,Redis模型不支持多仓库库存感知,还增加了单独维护一个集群的运营成本。
核心设计思路是“每件库存一行记录”,以10件库存的商品为例,新设计会有10行记录。预约3件意味着在单个事务中选取并移动3行,通过将预约和库存账本保持在同一数据库,获得了跨reserve和claim的ACID保证。
MySQL 8.0的SKIP LOCKED特性是实现可扩展性的关键,在高频预约场景下,不同事务之间不会相互阻塞。同时,为支撑超大规模场景,维护一个有限容量的可用行池,每种商品/仓库组合最多1000行。
在生产环境负载测试时,团队发现吞吐量远低于目标,但预约延迟(P90)可接受,CPU也未满载。经分析,其他业务逻辑长时间持有连接消耗了连接池,导致预约成为“压垮骆驼的最后一根稻草”。
清理Checkout路径后,主数据库的读取减少了50%,事务减少了33%。重新评估MySQL配置,增加线程并发配置,移除了此前未发现的瓶颈。
团队采用“影子模式”并行运行,每次预约同时写入Redis和MySQL,Redis保持为数据源。并排比较两个系统,验证MySQL产生了正确的业务结果且满足性能要求后,再将数据源切换为MySQL。整个切换过程逐步进行,从低流量Pod开始,逐步扩展到最高容量商家。
编辑观点:Shopify的实践表明,现有数据库也能处理高吞吐工作负载,解决问题需全面排查,真正的瓶颈可能藏在未关注之处。
