返回架构笔记
Arch Day 68

Arch Day 68: 库存系统设计

库存系统是管理商品从入库到出库全生命周期中数量状态的核心系统,需要在高并发下保证"不超卖、不少卖"的同时,实现全渠道(线上+门店+仓库)的统一库存视图和智能调配。

2026-06-06
第三阶段 - 零售域深度
库存系统超卖防止全渠道库存分布式扣减WMS

日期: 2026-06-06 (Day 68) 阶段: 第三阶段 - 零售域深度 标签: #库存系统 #超卖防止 #全渠道库存 #分布式扣减 #WMS


核心概念

一句话定义

库存系统是管理商品从入库到出库全生命周期中数量状态的核心系统,需要在高并发下保证"不超卖、不少卖"的同时,实现全渠道(线上+门店+仓库)的统一库存视图和智能调配。

为什么关注

  • 系统生死线:超卖是电商最严重的事故之一,直接影响用户体验和资金损失
  • 高并发挑战:秒杀场景下数十万QPS的库存扣减是分布式系统的经典难题
  • 全渠道趋势:即时零售要求门店+仓库+在途库存实时统一,技术复杂度极高
  • 架构典范:Redis预扣+DB持久化+补偿机制是分布式事务的经典范式
  • 面试高频:防超卖、库存扣减策略是系统设计面试的Top 3题目

误区与反模式

误区现实
库存就一个数字可售/实物/预占/在途/冻结各有不同含义和用途
直接UPDATE库存就行高并发下数据库锁竞争会导致性能崩溃
下单时扣库存最安全下单减/支付减/发货减各有trade-off
Redis能解决所有问题Redis预扣后还需要DB持久化和补偿机制
全渠道就是加个字段全渠道库存涉及多系统实时同步、共享规则、调配策略

知识点详解

1. 库存类型详解

库存类型层次:

┌─────────────────────────────────────────────┐
│                 库存类型体系                    │
│                                             │
│  ┌──────────────────────────────────┐      │
│  │  实物库存(Physical Inventory)     │      │
│  │  = 仓库中实际存在的商品数量        │      │
│  │  = 入库数 - 出库数               │      │
│  │  WMS系统管理                      │      │
│  └──────────────────────────────────┘      │
│           │                                  │
│           ▼                                  │
│  ┌──────────────────────────────────┐      │
│  │  可售库存(Available Inventory)    │      │
│  │  = 实物库存                       │      │
│  │    - 预占库存(订单锁定)           │      │
│  │    - 冻结库存(质量问题/纠纷)      │      │
│  │    + 在途库存(可配置是否算入)      │      │
│  │  = 用户可以购买的数量             │      │
│  └──────────────────────────────────┘      │
│                                             │
│  ┌──────────────────────────────────┐      │
│  │  预占库存(Reserved Inventory)     │      │
│  │  = 已下单但未支付/未发货的锁定量   │      │
│  │  = 有超时释放机制(如30分钟)       │      │
│  └──────────────────────────────────┘      │
│                                             │
│  ┌──────────────────────────────────┐      │
│  │  在途库存(In-Transit Inventory)   │      │
│  │  = 采购已发货但未到仓的数量       │      │
│  │  = 调拨在途中的数量               │      │
│  └──────────────────────────────────┘      │
│                                             │
│  ┌──────────────────────────────────┐      │
│  │  冻结库存(Frozen Inventory)       │      │
│  │  = 因质量/纠纷/审核被冻结的库存   │      │
│  │  = 不可售不可发                   │      │
│  └──────────────────────────────────┘      │
│                                             │
│  ┌──────────────────────────────────┐      │
│  │  安全库存(Safety Stock)           │      │
│  │  = 为防止缺货设置的最低库存水位   │      │
│  │  = 低于安全库存触发补货           │      │
│  └──────────────────────────────────┘      │
└─────────────────────────────────────────────┘

公式:
  可售库存 = 实物库存 - 预占库存 - 冻结库存
  实际可售 = 可售库存 + 在途库存(如果允许预售)

库存状态流转

stateDiagram-v2
    [*] --> 实物库存: 入库(采购/退货)
    实物库存 --> 可售库存: 上架
    可售库存 --> 预占库存: 下单预占
    预占库存 --> 可售库存: 超时释放/取消订单
    预占库存 --> 已出库: 发货出库
    可售库存 --> 冻结库存: 质量问题/纠纷
    冻结库存 --> 可售库存: 解冻
    冻结库存 --> 已报损: 报损处理
    已出库 --> [*]
    已报损 --> [*]

    note right of 预占库存: 超时自动释放(30min)
    note right of 冻结库存: 需审批解冻

2. 库存扣减策略

三种扣减策略对比

策略一:下单减(Order-time Deduction)
  ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐
  │ 下单  │───→│ 扣库存 │───→│ 支付  │───→│ 发货  │
  │      │    │(预占) │    │      │    │      │
  └──────┘    └──────┘    └──────┘    └──────┘
                │
                ├── 超时未支付 → 释放库存
                └── 取消订单 → 释放库存

  优点:用户体验好(下单即锁定)
  缺点:恶意下单占库存(竞争对手锁库存攻击)
  适用:常规商品、有超时释放机制

策略二:支付减(Payment-time Deduction)
  ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐
  │ 下单  │───→│ 支付  │───→│ 扣库存 │───→│ 发货  │
  │(不扣) │    │      │    │(实际扣)│    │      │
  └──────┘    └──────┘    └──────┘    └──────┘
                                │
                                └── 库存不足 → 退款

  优点:不怕恶意占库存
  缺点:支付成功但库存不足需要退款(体验差)
  适用:秒杀/限量商品(但需配合超卖处理)

策略三:发货减(Shipping-time Deduction)
  ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐
  │ 下单  │───→│ 支付  │───→│ 拣货  │───→│ 扣库存 │
  │(预占) │    │      │    │      │    │(实际扣)│
  └──────┘    └──────┘    └──────┘    └──────┘

  优点:与WMS实物库存完全同步
  缺点:预占期长、库存利用率低
  适用:高价值商品/B2B

策略选择决策矩阵

场景推荐策略原因
常规电商下单减体验好+超时释放
秒杀/限量下单减(严格)必须实时锁定
预售支付减无实物库存
B2B大宗发货减高价值需确认
即时零售下单减30分钟内完成
跨境电商支付减保税仓实物确认

3. 分布式库存扣减(核心)

Redis预扣 + DB持久化方案

高并发库存扣减架构:

┌──────────┐    ┌──────────┐    ┌──────────┐
│  用户请求  │───→│  API网关   │───→│  订单服务  │
│  (下单)   │    │          │    │          │
└──────────┘    └──────────┘    └─────┬────┘
                                      │
                                      ▼
                              ┌──────────────┐
                              │ Redis库存预扣  │
                              │              │
                              │ DECR操作     │
                              │ 原子性保证    │
                              │              │
                              │ if stock > 0:│
                              │   stock -= 1 │
                              │   return OK  │
                              │ else:        │
                              │   return FAIL│
                              └──────┬───────┘
                                     │
                          ┌──────────┤
                          │          │
                    成功(OK)     失败(FAIL)
                          │          │
                          ▼          ▼
                   ┌──────────┐  返回"库存不足"
                   │ MQ异步    │
                   │ 发送扣减  │
                   │ 消息      │
                   └────┬─────┘
                        │
                        ▼
                   ┌──────────┐
                   │ DB持久化  │
                   │          │
                   │ UPDATE   │
                   │ inventory │
                   │ SET stock │
                   │ = stock-1│
                   │ WHERE    │
                   │ stock > 0│
                   └──────────┘

Redis Lua脚本实现原子扣减

-- Redis Lua脚本:原子性库存预扣
-- KEYS[1] = 库存Key (如 "inventory:sku:12345")
-- ARGV[1] = 扣减数量

local stock = tonumber(redis.call('GET', KEYS[1]))

if stock == nil then
    return -1  -- 库存Key不存在
end

if stock < tonumber(ARGV[1]) then
    return -2  -- 库存不足
end

-- 原子扣减
local newStock = redis.call('DECRBY', KEYS[1], ARGV[1])

if newStock < 0 then
    -- 极端情况兜底:回滚
    redis.call('INCRBY', KEYS[1], ARGV[1])
    return -2
end

return newStock  -- 返回扣减后库存

库存扣减完整流程(含补偿)

完整流程(含异常处理):

正常流程:
  1. 用户下单
  2. Redis预扣(Lua脚本原子操作)
  3. 创建订单(DB)
  4. 发送MQ消息(异步扣减DB库存)
  5. DB库存扣减(幂等)
  6. 返回下单成功

异常场景1:Redis预扣成功,创建订单失败
  → 补偿:Redis库存回补(INCRBY)
  → 触发:订单创建异常catch块

异常场景2:订单创建成功,MQ发送失败
  → 补偿:本地事务表(Outbox模式)
  → 定时任务扫描未发送的消息重试

异常场景3:MQ消息消费失败(DB扣减失败)
  → 补偿:MQ重试(最多N次)
  → 最终失败:告警+人工介入

异常场景4:订单超时未支付
  → 定时任务/延时队列扫描超时订单
  → Redis库存回补
  → DB库存回补
  → 订单状态→已取消

幂等保证:
  DB扣减时带上订单号作为幂等键
  UPDATE inventory SET stock = stock - 1
  WHERE sku_id = ? AND stock > 0
  AND NOT EXISTS (
    SELECT 1 FROM inventory_log WHERE order_id = ?
  )

数据一致性保证

Redis ↔ DB 一致性策略:

方案1:定时对账
  ├── 每小时/每天对比Redis和DB库存
  ├── 差异告警+自动修复(以DB为准)
  └── 适合:非极致准确场景

方案2:双写+补偿
  ├── Redis扣减 → MQ → DB扣减
  ├── 失败补偿(回滚Redis)
  └── 适合:主流电商

方案3:DB为准+缓存更新
  ├── DB扣减(悲观锁/乐观锁)
  ├── 成功后更新Redis
  └── 适合:低并发高准确场景

方案4:Outbox模式(最终一致)
  ├── DB扣减 + 写Outbox表(同一事务)
  ├── CDC(Change Data Capture) → MQ → 更新Redis
  └── 适合:强一致性要求

4. 全渠道库存

全渠道库存架构

全渠道库存统一视图:

┌─────────────────────────────────────────────────────┐
│                 全渠道库存中心                         │
│                                                     │
│  ┌───────────────────────────────────────────────┐ │
│  │              统一库存视图(ATP - Available to    │ │
│  │              Promise, 可承诺库存)               │ │
│  │                                               │ │
│  │  SKU-12345 全渠道可售: 150                     │ │
│  │  ├── 中心仓(上海): 80                          │ │
│  │  ├── 前置仓(浦东): 20                          │ │
│  │  ├── 门店A(南京路): 15                         │ │
│  │  ├── 门店B(淮海路): 10                         │ │
│  │  ├── 供应商在途: 25                            │ │
│  │  └── 预占已扣: -0                             │ │
│  └───────────────────────────────────────────────┘ │
│                                                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐       │
│  │ 线上渠道  │  │ 门店渠道  │  │ 即时零售  │       │
│  │ App/PC   │  │ POS系统  │  │ 闪购/到家 │       │
│  │          │  │          │  │          │       │
│  │ 可用:100 │  │ 可用:50  │  │ 可用:30  │       │
│  │(中心仓   │  │(门店库存 │  │(前置仓+  │       │
│  │+部分门店)│  │+调拨)    │  │ 最近门店) │       │
│  └──────────┘  └──────────┘  └──────────┘       │
│                                                     │
│  库存共享规则:                                      │
│  ├── 线上优先共享中心仓库存                          │
│  ├── 门店优先使用本店库存                            │
│  ├── 即时零售共享最近3km的库存                      │
│  ├── 安全库存互不侵占                              │
│  └── 库存不足时触发跨仓/跨店调拨                    │
└─────────────────────────────────────────────────────┘

全渠道库存同步机制

库存同步方案:

实时同步(核心场景):
  ├── Redis发布/订阅(Pub/Sub)
  ├── 库存变更 → 发布事件 → 各渠道订阅
  ├── 延迟:毫秒级
  └── 适用:扣减/预占/释放

准实时同步(常规场景):
  ├── MQ消息(Kafka/RocketMQ)
  ├── 库存变更 → 发送消息 → 消费更新
  ├── 延迟:秒级
  └── 适用:入库/盘点/调拨

定时同步(兜底):
  ├── 定时全量对账
  ├── 差异修复
  ├── 频率:每小时/每天
  └── 适用:异常修复

Redis实时库存架构:
  ├── 使用Redis Hash存储各仓位库存
  │   HSET inventory:sku:12345 warehouse_01 80
  │   HSET inventory:sku:12345 store_01 15
  │   HSET inventory:sku:12345 store_02 10
  │
  ├── ATP计算(Lua脚本):
  │   遍历所有仓位 → 按渠道规则汇总
  │
  └── 地理位置索引(Redis GEO):
      找到用户最近的有库存门店/仓库

5. 库存预占与释放机制

预占/释放生命周期:

下单时预占:
  ├── 锁定库存(可售-1, 预占+1)
  ├── 记录预占明细(订单号/SKU/数量/时间)
  └── 设置超时时间(如30分钟)

支付成功确认:
  ├── 预占转为已售(预占-1)
  └── 触发发货流程

超时未支付释放:
  ├── 释放预占(预占-1, 可售+1)
  ├── 取消订单
  └── 通知用户

主动取消释放:
  ├── 用户取消订单
  ├── 释放预占(预占-1, 可售+1)
  └── 支付已扣则退款

超时释放实现方案:

方案A:延时队列(推荐)
  下单时发送延时消息(30min后消费)
  → 消费时检查订单状态
  → 未支付则释放库存

方案B:定时扫描
  定时任务每分钟扫描超时预占
  → 批量释放
  → 适合兜底

方案C:Redis过期事件
  设置预占key过期时间
  → 过期时触发keyspace notification
  → 释放库存
  → 注意:Redis过期不保证实时

6. WMS(仓储管理系统)概览

WMS核心功能:

┌────────────────────────────────────────────┐
│               WMS仓储管理系统               │
│                                            │
│  入库管理                                   │
│  ├── 采购入库(PO收货)                      │
│  ├── 退货入库(逆向物流)                    │
│  ├── 调拨入库(仓间调拨)                    │
│  ├── 质检(抽检/全检)                       │
│  └── 上架(分配库位)                        │
│                                            │
│  出库管理                                   │
│  ├── 波次规划(合并订单→拣货波次)           │
│  ├── 拣货(Pick)                            │
│  │   ├── 摘果法(按订单拣)                  │
│  │   ├── 播种法(按商品拣→分拨)            │
│  │   └── 混合法(先播种再摘果)             │
│  ├── 复核(验货)                            │
│  ├── 打包(Packing)                         │
│  └── 发货(交接快递)                        │
│                                            │
│  库内管理                                   │
│  ├── 盘点(周期盘点/全量盘点)              │
│  ├── 移库(库位调整)                        │
│  ├── 补货(高频区补货)                      │
│  └── 库位管理(区→排→架→层→位)            │
│                                            │
│  库位编码:                                 │
│  A-01-03-02-05                             │
│  区 排  架  层  位                          │
└────────────────────────────────────────────┘

WMS与库存系统的关系:
  库存系统:管"数量"(可售多少)
  WMS系统:管"位置"(在哪个库位)

  库存系统 = 逻辑库存(交易驱动)
  WMS系统 = 物理库存(实物驱动)

  两者通过"入库/出库/盘点"事件同步

7. 库存系统数据模型

-- 核心库存表(逻辑库存)
CREATE TABLE inventory (
    id              BIGINT PRIMARY KEY AUTO_INCREMENT,
    sku_id          BIGINT NOT NULL,
    warehouse_id    BIGINT NOT NULL,     -- 仓库/门店ID
    channel_code    VARCHAR(32),          -- 渠道(ALL/ONLINE/STORE)

    -- 库存量
    total_stock     INT NOT NULL DEFAULT 0,  -- 实物库存
    available_stock INT NOT NULL DEFAULT 0,  -- 可售库存
    reserved_stock  INT NOT NULL DEFAULT 0,  -- 预占库存
    frozen_stock    INT NOT NULL DEFAULT 0,  -- 冻结库存
    intransit_stock INT NOT NULL DEFAULT 0,  -- 在途库存

    -- 安全库存
    safety_stock    INT NOT NULL DEFAULT 0,  -- 安全库存线

    -- 版本(乐观锁)
    version         INT NOT NULL DEFAULT 0,

    -- 时间
    created_at      DATETIME NOT NULL,
    updated_at      DATETIME NOT NULL,

    UNIQUE KEY uk_sku_warehouse (sku_id, warehouse_id, channel_code),
    KEY idx_sku (sku_id),
    KEY idx_warehouse (warehouse_id)
);

-- 库存操作日志(审计追踪)
CREATE TABLE inventory_log (
    id              BIGINT PRIMARY KEY AUTO_INCREMENT,
    sku_id          BIGINT NOT NULL,
    warehouse_id    BIGINT NOT NULL,
    order_id        VARCHAR(64),          -- 关联订单号(幂等键)
    operation_type  VARCHAR(32) NOT NULL,  -- RESERVE/CONFIRM/RELEASE/FREEZE...
    quantity         INT NOT NULL,          -- 变更数量(正=增/负=减)
    before_stock    INT NOT NULL,          -- 变更前库存
    after_stock     INT NOT NULL,          -- 变更后库存
    operator        VARCHAR(64),           -- 操作人/系统
    remark          VARCHAR(256),          -- 备注
    created_at      DATETIME NOT NULL,

    UNIQUE KEY uk_order_operation (order_id, operation_type),
    KEY idx_sku_time (sku_id, created_at)
);

-- 库存预占明细(超时释放)
CREATE TABLE inventory_reservation (
    id              BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_id        VARCHAR(64) NOT NULL UNIQUE,
    sku_id          BIGINT NOT NULL,
    warehouse_id    BIGINT NOT NULL,
    quantity         INT NOT NULL,
    status          VARCHAR(16) NOT NULL,  -- RESERVED/CONFIRMED/RELEASED
    expire_at       DATETIME NOT NULL,     -- 过期时间
    created_at      DATETIME NOT NULL,
    updated_at      DATETIME NOT NULL,

    KEY idx_expire (status, expire_at),
    KEY idx_order (order_id)
);

对比分析

库存扣减方案对比

方案并发支持一致性复杂度适用场景
DB悲观锁(SELECT FOR UPDATE)低(~1K QPS)低并发/B2B
DB乐观锁(版本号)中(~5K QPS)中等并发
Redis预扣+DB异步高(~100K QPS)最终一致高并发电商
Redis预扣+Lua极高(~500K QPS)最终一致秒杀/闪购
Redis+DB双写(分布式事务)中高极高金融级

全渠道库存方案对比

方案实时性复杂度成本适用
各渠道独立库存-渠道差异大
统一库存中心秒级主流电商
Redis实时+DB持久毫秒级中高即时零售
事件驱动(CDC)准实时中高新建系统

架构设计实操

设计目标

设计一个"全渠道库存系统",支持:

  1. 多仓多渠道统一库存视图(ATP)
  2. 高并发库存扣减(10万+ QPS)
  3. 预占/释放机制(超时自动释放)
  4. WMS集成(入库/出库同步)

系统架构

全渠道库存系统架构:

┌──────────────────────────────────────────────────┐
│                  接入层                             │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐         │
│  │ 订单服务 │  │ 门店POS │  │ WMS系统  │          │
│  │(扣减请求)│  │(门店扣减)│  │(入出库)  │          │
│  └────┬────┘  └────┬────┘  └────┬────┘         │
└───────┼────────────┼────────────┼────────────────┘
        │            │            │
┌───────┼────────────┼────────────┼────────────────┐
│       ▼            ▼            ▼                │
│  ┌──────────────────────────────────────────┐   │
│  │           库存服务(核心)                   │   │
│  │                                          │   │
│  │  ┌──────────┐ ┌──────────┐             │   │
│  │  │ 库存扣减  │ │ 库存查询  │             │   │
│  │  │ (写路径)  │ │ (读路径)  │             │   │
│  │  └──────────┘ └──────────┘             │   │
│  │                                          │   │
│  │  ┌──────────┐ ┌──────────┐             │   │
│  │  │ 预占管理  │ │ ATP计算  │              │   │
│  │  │ (锁定/释放│ │ (可售计算)│              │   │
│  │  └──────────┘ └──────────┘             │   │
│  │                                          │   │
│  │  ┌──────────┐ ┌──────────┐             │   │
│  │  │ 库存调配  │ │ 库存预警  │             │   │
│  │  │ (调拨/补货│ │ (安全库存)│             │   │
│  │  └──────────┘ └──────────┘             │   │
│  └──────────────────────────────────────────┘   │
│                                                  │
│  ┌──────────────────────────────────────────┐   │
│  │           数据层                          │   │
│  │                                          │   │
│  │  ┌──────────┐ ┌──────────┐             │   │
│  │  │  Redis   │ │  MySQL   │              │   │
│  │  │ (热库存   │ │ (持久化   │              │   │
│  │  │  实时扣减 │ │  主数据)  │              │   │
│  │  │  ATP缓存) │ │          │              │   │
│  │  └──────────┘ └──────────┘             │   │
│  │                                          │   │
│  │  ┌──────────┐ ┌──────────┐             │   │
│  │  │  Kafka   │ │ ES(可选)  │             │   │
│  │  │ (事件流   │ │ (库存搜索 │             │   │
│  │  │  异步同步)│ │  分析)    │              │   │
│  │  └──────────┘ └──────────┘             │   │
│  └──────────────────────────────────────────┘   │
└──────────────────────────────────────────────────┘

ADR: 库存扣减方案选型

## ADR-068: 高并发库存扣减方案

### 状态: 已采纳

### 上下文
需要支持秒杀/大促场景下10万+ QPS的库存扣减,
同时保证不超卖和最终一致性。

### 可选方案
A. MySQL悲观锁(SELECT FOR UPDATE)
B. MySQL乐观锁(版本号)
C. Redis预扣(Lua脚本) + MySQL异步持久化
D. Redis预扣 + 分布式事务(TCC/Saga)

### 决策
采用方案C:Redis预扣 + MySQL异步持久化

### 理由
1. Redis单机支持50万+ QPS,满足性能要求
2. Lua脚本保证原子性(查+扣在一个命令)
3. MySQL异步写入不影响主路径性能
4. 补偿机制保证最终一致性
5. 方案D虽然一致性更强,但复杂度和延迟不可接受

### 补偿机制
1. Redis预扣成功但订单创建失败 → Redis回补
2. MQ消息丢失 → Outbox模式 + 定时扫描
3. DB扣减失败 → MQ重试(最多3次) + 人工告警
4. Redis/DB不一致 → 定时对账(每小时)

### 后果
- Redis和MySQL之间存在短暂不一致窗口(秒级)
- 需要完善的补偿和对账机制
- Redis数据需要持久化保护(AOF/RDB)
- 需要监控Redis↔MySQL库存差异

AI增强实践

AI在库存管理中的应用

2025-2026年AI库存管理应用:

1. 需求预测(Demand Forecasting)
   ├── 时序模型:Prophet/LSTM/Transformer
   ├── 特征:历史销量+季节性+促销+天气+事件
   ├── 粒度:SKU × 仓库 × 天
   ├── 准确率:70-85%(SKU级别)
   └── 应用:自动补货/安全库存动态调整

2. 智能补货(Auto Replenishment)
   ├── 基于预测自动生成补货订单
   ├── 考虑:供应商交期+运输时间+成本
   ├── 强化学习优化补货策略
   └── 减少40-60%的缺货和50%+过剩

3. 库存分配优化
   ├── 多仓多渠道最优分配
   ├── 考虑:距离+成本+时效
   ├── 实时动态调整
   └── 线性规划/整数规划

4. 库位优化
   ├── 热度分析:高频商品→黄金库位
   ├── 拣货路径优化(TSP变体)
   ├── 动态库位调整
   └── 减少拣货时间30%+

5. 异常检测
   ├── 库存差异自动发现
   ├── 盗损预测
   ├── 系统Bug导致的数据异常
   └── 实时告警

实际案例(2025-2026):
├── Amazon:ML驱动的库存预置(发货前预测)
├── Walmart:AI补货系统减少20%库存周转天数
├── 美团:前置仓智能选品+动态库存
└── Redis ATP(Available to Promise)解决方案

与Web3/DeFi的关联

区块链在库存管理中的应用

区块链库存/供应链场景:

1. 供应链透明(Traceability)
   ├── 商品从产地→工厂→仓库→消费者全链路上链
   ├── 每次流转记录不可篡改
   ├── 消费者扫码查看完整溯源信息
   └── 案例:VeChain(奢侈品溯源)

2. 去中心化库存共享
   ├── 多方共享库存信息(不需要信任)
   ├── 智能合约自动撮合供需
   ├── 供应商/分销商/零售商实时同步
   └── 减少牛鞭效应(信息不对称导致的波动)

3. Token化库存金融
   ├── 库存作为抵押品Token化
   ├── 仓单Token(WRT, Warehouse Receipt Token)
   ├── 供应链金融:应收账款Token化→DeFi借贷
   └── 案例:Centrifuge(供应链资产代币化)

4. DeFi与库存的类比
   ├── 库存预占 ≈ DeFi中的Token锁定(Staking)
   ├── 全渠道库存 ≈ 跨链流动性
   ├── 安全库存 ≈ 最低质押率
   └── 库存调拨 ≈ 跨链桥接

库存系统 vs DeFi流动性池:
  ├── 可售库存 ≈ Pool中的可用流动性
  ├── 预占库存 ≈ 锁仓中的Token
  ├── 超卖 ≈ 流动性枯竭
  ├── 补货 ≈ LP注入流动性
  └── 安全库存 ≈ 最低流动性要求

今日思考

三个深度问题

  1. Redis预扣方案的"阿喀琉斯之踵":Redis是内存数据库,如果Redis宕机,预扣的库存数据可能丢失。虽然有AOF/RDB持久化,但仍有秒级数据丢失窗口。在双11/618这种极致场景下,如何设计Redis的高可用方案?Sentinel还是Cluster?需要Redis和DB之间什么级别的一致性保证?

  2. 全渠道库存的"公平性"问题:当一个SKU的库存有限时,线上(App)和线下(门店)都在争抢同一份库存。如何设计公平的库存共享规则?是给每个渠道预留安全库存(效率低但公平),还是先到先得(效率高但某渠道可能总是抢不到)?这个问题有最优解吗?

  3. "不超卖"vs"不少卖"的trade-off:为了绝对不超卖,很多系统设计得过于保守(如库存预留过多、扣减条件过严),导致明明有库存却显示"缺货"(少卖)。少卖的损失(GMV损失)可能远大于超卖的损失(退款+补偿)。如何量化这个trade-off并找到最优平衡点?


面试题准备

面试题1: 库存超卖如何防止?

30秒回答: 防止超卖的核心方案是"Redis Lua原子预扣"。用Lua脚本在Redis中原子性地执行"查询库存→判断是否充足→扣减"三步操作,利用Redis单线程模型保证并发安全。扣减成功后异步同步到MySQL持久化。配合超时释放机制(延时队列)回收未支付的预占库存。这个方案可以支撑10万+QPS的并发扣减。

2分钟详细回答: 防超卖可以从四个层次来保障:

第一层:Redis原子预扣。用Lua脚本在Redis中实现原子性的"查+扣"操作。Lua脚本在Redis中是串行执行的(单线程模型),天然保证并发安全。一个Lua脚本调用完成"检查库存→扣减→返回结果",中间不会被其他请求打断。

第二层:DB最终一致性。Redis预扣成功后,通过MQ异步发送扣减消息到MySQL。MySQL端使用乐观锁(WHERE stock > 0)二次校验。通过Outbox模式+重试保证消息不丢失。

第三层:预占超时释放。下单后设置30分钟超时。通过延时队列(RocketMQ延时消息或Redis过期)在超时后检查订单状态,未支付则自动释放Redis和DB库存。

第四层:定时对账。每小时对比Redis和MySQL库存,差异告警并自动修复(以MySQL为准)。

追问准备

  • Q: Redis宕机怎么办?
  • A: Redis Cluster模式(3主3从)+AOF持久化。主节点宕机秒级切换到从节点。AOF配置为everysec(最多丢1秒数据)。极端情况下从DB重新加载库存到Redis。
  • Q: 秒杀场景有什么特殊处理?
  • A: 秒杀提前加载库存到Redis,设置秒杀专用Key,配合前端限流(按钮灰化/验证码)和后端限流(令牌桶),将QPS控制在Redis可承受范围内。

面试题2: 全渠道库存协同的核心挑战?

30秒回答: 全渠道库存协同的核心挑战有三个:一是实时性——线上/门店/前置仓的库存变更需要秒级同步到统一视图,延迟会导致超卖或少卖;二是共享规则——同一份库存给不同渠道分配多少,需要平衡公平性和利用率;三是异构系统集成——门店POS、中心仓WMS、前置仓系统的数据格式和更新频率不同,统一同步的技术复杂度很高。

2分钟详细回答: 全渠道库存协同可以从"统一、共享、同步"三个维度分析:

统一视图(ATP):需要构建一个统一的"可承诺库存"视图,汇聚中心仓、前置仓、门店、供应商在途等所有库存源。这要求一个实时计算引擎,根据渠道规则动态计算每个渠道的可售量。Redis是主流选择,用Hash结构存储各仓位库存。

共享规则:最大挑战是定义渠道间的库存共享和隔离规则。常见模式有"共享池"(所有渠道共享)、"渠道隔离"(各渠道预分配)、"混合模式"(安全库存隔离+溢出共享)。混合模式是实践中的最优解,但参数调优是一个持续过程。

实时同步:不同库存源的更新频率不同——电商下单扣减是毫秒级,门店POS扣减是秒级,WMS入库是分钟级。需要分层同步策略:高频操作走Redis实时同步,低频操作走MQ准实时同步,定时全量对账兜底。

追问准备

  • Q: 即时零售的库存要求有什么特殊?
  • A: 即时零售对库存精度要求极高(30分钟送达,不能到了发现没货),需要门店级别的实时库存。技术上要求POS系统实时上报销售数据,库存系统秒级更新。同时需要LBS(基于位置服务)找到最近的有库存门店。

学习资源

资源类型说明
Redis ATP解决方案文档Redis官方库存方案
美团库存系统设计博客即时零售库存实践
System Design Handbook: Inventory指南库存系统设计教程
VeChain Supply Chain项目区块链供应链溯源
Apache ShardingSphere框架分库分表(库存表)
RocketMQ延时消息文档预占超时释放

明日预告

Day 69: 订单系统设计

  • 订单创建与拆分逻辑
  • 订单状态机(正向+逆向)
  • 分布式订单ID生成
  • 订单与库存/支付/物流的协同
  • 高并发订单创建(削峰/限流/异步)