<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>高并发 &#8211; mylogs.cn</title>
	<atom:link href="https://mylogs.cn/tag/%e9%ab%98%e5%b9%b6%e5%8f%91/feed/" rel="self" type="application/rss+xml" />
	<link>https://mylogs.cn</link>
	<description>发现、记录、分享</description>
	<lastBuildDate>Sun, 09 Aug 2026 13:42:05 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>不用 Redis 也能扛住：Shopify 用 MySQL 重写库存预留</title>
		<link>https://mylogs.cn/shopify-mysql-replace-redis-inventory-reservations/</link>
					<comments>https://mylogs.cn/shopify-mysql-replace-redis-inventory-reservations/#respond</comments>
		
		<dc:creator><![CDATA[steve, zhang]]></dc:creator>
		<pubDate>Sun, 09 Aug 2026 13:41:52 +0000</pubDate>
				<category><![CDATA[科技]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Redis]]></category>
		<category><![CDATA[Shopify]]></category>
		<category><![CDATA[SKIP LOCKED]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[电商架构]]></category>
		<category><![CDATA[高并发]]></category>
		<guid isPermaLink="false">https://mylogs.cn/shopify-mysql-replace-redis-inventory-reservations/</guid>

					<description><![CDATA[你以为高并发的库存系统离不开 Redis？Shopify 工程团队用一次「反向迁移」给出了另一种答案：他们把库 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">你以为高并发的库存系统离不开 Redis？Shopify 工程团队用一次「反向迁移」给出了另一种答案：他们把库存预留系统从 Redis 搬回 MySQL，并在 2025 年黑色星期五扛住了峰值——当时平台每分钟销售额达到 510 万美元。Shopify 支撑着美国超过 14% 的电商交易。</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7883bfe992a&quot;}" data-wp-interactive="core/image" data-wp-key="6a7883bfe992a" class="wp-block-image size-large aligncenter wp-lightbox-container"><img fetchpriority="high" decoding="async" width="1200" height="669" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://mylogs.cn/wp-content/uploads/2026/08/c17aba3d4098b3bffac2723514f2b28a_header.webp" alt="不用 Redis 也能扛住：Shopify 用 MySQL 重写库存预留" class="wp-image-4200" style="max-width:100%;height:auto;" srcset="https://mylogs.cn/wp-content/uploads/2026/08/c17aba3d4098b3bffac2723514f2b28a_header.webp 1200w, https://mylogs.cn/wp-content/uploads/2026/08/c17aba3d4098b3bffac2723514f2b28a_header-300x167.webp 300w, https://mylogs.cn/wp-content/uploads/2026/08/c17aba3d4098b3bffac2723514f2b28a_header-1024x571.webp 1024w, https://mylogs.cn/wp-content/uploads/2026/08/c17aba3d4098b3bffac2723514f2b28a_header-768x428.webp 768w" sizes="(max-width: 1200px) 100vw, 1200px" /><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button><figcaption class="wp-element-caption">图片来源：Shopify</figcaption></figure>





<p class="wp-block-paragraph">旧方案的问题出在「两套账」。库存计数存在 Redis 里（占用就减、释放就加），但真正的库存总账在 MySQL。两步没法打包成一个原子操作，一旦顺序出错，就会出现超卖（东西卖了却没从总账扣掉）或幽灵库存（扣了却还显示占用）。Redis 也不感知多仓库库存，还得单独养一个集群。</p>



<p class="wp-block-paragraph">新方案靠的是 MySQL 8 的 SKIP LOCKED 特性。核心思路是「每个可售单元存一行」，而不是「每个商品存一行数量」。一件有 10 件库存的商品就对应 10 行，预留 3 件就是一次性锁 3 行、挪进预留表。为避免行数爆炸，每个商品/仓库最多维持 1000 行可用池，不够了再由补充进程从总账补齐。SKIP LOCKED 让并发请求跳过被锁的行、直接拿别的可用行，不用排队。</p>



<p class="wp-block-paragraph">几个工程细节值得记：把主键改成复合主键（店铺、商品、分组、序号），每行锁从两把降到一把；把事务隔离级别从默认的「可重复读」降到「读已提交」，避开空表补充时的间隙锁死锁；统一「先删后插」的锁顺序，消除预留与扣减路径间的循环等待；再用 UNION ALL 把一单多件的查询合并成一次往返。</p>



<p class="wp-block-paragraph">最有意思的是真瓶颈不在数据库。调完表结构，吞吐量还是卡在目标线下，CPU 也没跑满。团队给每条 SQL 打上业务标签（例如「conn_tag:checkout_completion」），在数据库代理层按调用方统计连接占用时长，才发现是结账链路上的其他环节长时间霸占连接。清理掉这些长事务后，主库读操作减少 50%、事务数减少 33%。</p>



<p class="wp-block-paragraph">迁移采用影子模式：Redis 和 MySQL 双写一段时间，确认无误再逐步把「真相源」切到 MySQL，并保留一键回滚。</p>



<p class="wp-block-paragraph">说白了，很多「必须上 Redis」的判断，只是因为当年 MySQL 还没有 SKIP LOCKED 这类能力；如今你手上的数据库往往就够用。真正的瓶颈常常藏在代码里的连接管理，而不是引擎本身。下次想引入新中间件之前，不妨先看看现有数据库的新特性和连接画像。</p>



<p class="has-small-font-size wp-block-paragraph">来源：Shopify 工程博客（作者 Emilie Noel，2026-05-12）</p>

]]></content:encoded>
					
					<wfw:commentRss>https://mylogs.cn/shopify-mysql-replace-redis-inventory-reservations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
