Arch Day 114
Arch Day 114: 系统设计面试(5):设计全渠道零售平台
Arch Day 114: 系统设计面试(5):设计全渠道零售平台
2026-07-22
第四阶段 - 高阶融合系统设计全渠道统一商务OMS库存协同面试
日期: 2026-07-22 (Day 114) 阶段: 第四阶段 - 高阶融合 标签: #系统设计 #全渠道 #统一商务 #OMS #库存协同 #面试
面试场景设定
面试题目
"请在45分钟内设计一个全渠道零售平台,支持线上商城、移动App、线下门店POS、小程序等多渠道统一运营。日均订单量100万+,SKU数500万+,门店2000+家,会员数5000万+。"
时间分配(45分钟)
| 阶段 | 时间 | 重点 |
|---|---|---|
| 需求澄清 | 5min | 确认边界、约束、优先级 |
| 高层架构 | 8min | C4 Context + Container |
| 核心域设计 | 15min | 商品/库存/订单/会员/营销 |
| 数据架构 | 7min | 数据流/一致性/同步策略 |
| 集成架构 | 5min | 渠道接入/第三方/POS |
| 扩展讨论 | 5min | 演进/容灾/性能/追问应对 |
第一步:需求澄清(5分钟)
1.1 必须澄清的问题
作为高级架构师,需求澄清环节体现的是业务理解力和架构敏感度。以下是必须向面试官确认的关键问题:
问题1: 渠道范围
"除了线上商城、App、POS、小程序,是否还包括直播电商、社区团购、
B2B批发等渠道?" → 影响渠道接入层设计
问题2: 全渠道深度
"全渠道是指'展示统一'还是'库存打通'?客户能否线上下单、门店取货?
能否门店下单、快递到家?" → 影响履约系统复杂度
问题3: 库存模式
"门店库存和电商仓库库存是否打通?是否支持门店发货?
门店既是销售点又是履约点?" → 影响库存架构
问题4: 会员体系
"线上线下会员是否已统一?积分/优惠券是否跨渠道通用?" → 影响会员域
问题5: 现有系统
"是从零设计还是在现有系统上改造?有哪些遗留系统必须兼容?" → 影响集成策略
问题6: 非功能性约束
"大促峰值倍率?(通常10-50倍日常)数据合规要求?跨区域部署?"
1.2 假设与约束(面试官确认后)
| 维度 | 假设 |
|---|---|
| 渠道 | 线上商城 + App + 小程序 + 2000+门店POS |
| 模式 | 全渠道库存打通,支持全渠道履约(门店发货/门店自提/仓库发货) |
| 规模 | 日均100万单,大促10倍(1000万单/天),500万SKU,5000万会员 |
| 现状 | 已有遗留ERP和POS系统,需要兼容 |
| 一致性 | 库存:强一致(不超卖) / 会员积分:最终一致 / 订单:强一致 |
1.3 核心挑战识别
全渠道零售平台相比单渠道电商,面临五大特有挑战:
挑战1: 统一库存视图
├── 问题: 500万SKU × 2000+门店 = 100亿级库存记录
├── 难点: 门店库存实时性差,POS离线时库存不同步
└── 要求: 全局可售库存实时计算
挑战2: 智能订单路由
├── 问题: 一个订单可能由仓库、门店、多个来源混合履约
├── 难点: 路由策略需要综合考虑距离/库存/成本/时效
└── 要求: 毫秒级路由决策
挑战3: 线下POS离线能力
├── 问题: 门店网络中断时仍需正常收银
├── 难点: 离线期间的库存扣减/会员积分如何处理
└── 要求: 离线模式 + 重连后数据合并
挑战4: 数据一致性
├── 问题: 同一商品在多渠道展示/定价/促销可能不同
├── 难点: 跨渠道价格一致性 vs 渠道差异化定价
└── 要求: 统一商品主数据 + 渠道差异化规则
挑战5: 秒杀/大促场景
├── 问题: 线上线下同时秒杀,库存如何分配和协同
├── 难点: 预分配 vs 实时共享的权衡
└── 要求: 弹性库存分配策略
第二步:高层架构(8分钟)
2.1 C4 Context 图(系统上下文)
┌─────────────────────────────────────────┐
│ 外部用户/系统 │
├─────────────────────────────────────────┤
│ │
┌──────────┐ │ ┌──────────┐ ┌──────────┐ │
│ 线上顾客 │────▶│ │ Web商城 │ │ App │ │
└──────────┘ │ └──────────┘ └──────────┘ │
│ │ │ │
┌──────────┐ │ ┌──────────┐ ┌──────────┐ │
│ 门店顾客 │────▶│ │ 小程序 │ │ POS终端 │ │
└──────────┘ │ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ 全渠道零售平台 (OCP) │ │
│ │ Omni-Channel Platform │ │
│ └─────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 支付系统 │ │ 物流系统 │ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ ERP(遗留) │ │ WMS │ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 短信/推送 │ │ 数据平台 │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────┘
2.2 C4 Container 图(系统容器)
┌─────────────────────────────────────────────────────────────────────┐
│ 全渠道零售平台 (OCP) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────── 渠道接入层 ──────────────────────┐ │
│ │ API Gateway │ BFF(Web) │ BFF(App) │ BFF(POS) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────── 业务服务层 ──────────────────────┐ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐│ │
│ │ │ 商品服务 │ │ 库存服务 │ │ 订单服务 │ │ 会员服务 ││ │
│ │ │ Product │ │Inventory │ │ Order │ │ Member ││ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘│ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐│ │
│ │ │ 营销服务 │ │ 搜索服务 │ │ 履约服务 │ │ 支付服务 ││ │
│ │ │Promotion │ │ Search │ │Fulfill │ │ Payment ││ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘│ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 门店服务 │ │ 价格服务 │ │ │
│ │ │ Store │ │ Price │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────── 基础设施层 ──────────────────────┐ │
│ │ 消息队列(Kafka) │ 缓存(Redis) │ 配置中心 │ 注册中心 │ │
│ │ 对象存储(OSS) │ 分布式ID │ 链路追踪 │ 日志中心 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────── 数据存储层 ──────────────────────┐ │
│ │ MySQL集群 │ ES集群 │ Redis集群 │ TiDB │ HBase │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
2.3 架构风格选择(ADR-114-01)
决策记录:
| 项目 | 内容 |
|---|---|
| 决策 | 采用"领域驱动的微服务 + 事件驱动"混合架构 |
| 背景 | 全渠道平台涉及多个业务域,各域演进节奏不同 |
| 选项 | A) 单体 B) 微服务 C) 事件驱动 D) 混合架构 |
| 选择 | D) 域内同步调用,域间事件驱动 |
| 理由 | 域内强一致需求用同步RPC;域间解耦用事件;兼顾一致性和可用性 |
| 风险 | 事件丢失/重复——Kafka幂等+Exactly-once语义 |
第三步:核心域设计(15分钟)
3.1 领域划分(DDD战略设计)
┌─────────────────────────────────────────────────────────────┐
│ 全渠道零售平台 - 限界上下文 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 核心域 (Core Domain) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 库存上下文 │ │ 订单上下文 │ │ 履约上下文 │ │
│ │ Inventory │ │ Order │ │ Fulfillment │ │
│ │ Context │ │ Context │ │ Context │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 支撑域 (Supporting Domain) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 商品上下文 │ │ 会员上下文 │ │ 营销上下文 │ │
│ │ Product │ │ Member │ │ Marketing │ │
│ │ Context │ │ Context │ │ Context │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ 通用域 (Generic Domain) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 支付上下文 │ │ 门店上下文 │ │ 价格上下文 │ │
│ │ Payment │ │ Store │ │ Price │ │
│ │ Context │ │ Context │ │ Context │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
3.2 核心域一:统一库存
统一库存是全渠道平台最核心也最复杂的域,需要在多个物理仓/门店之间提供一个统一的"可售库存"视图。
库存模型设计
┌─────────────────────────────┐
│ 全局可售库存池 │
│ Global Available Inventory │
│ = Σ(各节点可售) - Σ(预留) │
└───────────┬─────────────────┘
│
┌─────────────────┬───┴────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 中心仓库 │ │ 区域仓库 │ │ 门店(×2000) │
│ CDC │ │ RDC(×10) │ │ Store │
│ │ │ │ │ │
│ 实物库存 │ │ 实物库存 │ │ 实物库存 │
│ - 在库 │ │ - 在库 │ │ - 在库 │
│ - 在途 │ │ - 在途 │ │ - 在途 │
│ - 锁定 │ │ - 锁定 │ │ - 锁定 │
│ - 残次 │ │ - 残次 │ │ - 残次 │
│ │ │ │ │ │
│ 可售库存 │ │ 可售库存 │ │ 可售库存 │
│ = 在库-锁定 │ │ = 在库-锁定 │ │ = 在库-锁定 │
│ -安全库存 │ │ -安全库存 │ │ -门店预留 │
└──────────────┘ └──────────────┘ └──────────────┘
库存分层架构
┌─────────────────────────────────────────────────┐
│ 库存服务分层架构 │
├─────────────────────────────────────────────────┤
│ │
│ L1: 热点库存缓存 (Redis) 延迟: <1ms │
│ ├── 秒杀商品库存 │
│ ├── Top1000热卖品库存 │
│ └── 各渠道可售库存快照 │
│ │
│ L2: 全局可售库存 (TiDB/分库分表) 延迟: <10ms │
│ ├── SKU+仓库维度库存记录 │
│ ├── SKU+门店维度库存记录 │
│ └── 渠道预分配记录 │
│ │
│ L3: 实物库存 (WMS/POS) 延迟: 分钟级 │
│ ├── 仓库WMS系统的精确库存 │
│ └── 门店POS系统的精确库存 │
│ │
│ 同步策略: │
│ L3→L2: 增量事件驱动 + 定时全量校准(每日) │
│ L2→L1: 变更事件实时推送 + TTL过期刷新 │
└─────────────────────────────────────────────────┘
库存扣减核心流程
客户下单
│
▼
┌──────────────────┐
│ 1. 查询可售库存 │ ← Redis L1层(热点) / TiDB L2层(普通)
│ 判断是否可售 │
└────────┬─────────┘
│ 可售
▼
┌──────────────────┐
│ 2. 预扣(锁定) │ ← Redis DECR原子操作(热点) / DB行锁(普通)
│ 设置超时释放 │ 超时时间: 15min (支付窗口)
└────────┬─────────┘
│ 锁定成功
▼
┌──────────────────┐
│ 3. 创建订单 │ ← 订单服务
│ 等待支付 │
└────────┬─────────┘
│
┌────┴────┐
│ │
支付成功 超时/取消
│ │
▼ ▼
┌────────┐ ┌────────┐
│确认扣减 │ │释放库存 │ ← 定时任务扫描 + MQ事件双保险
│实际出库 │ │恢复可售 │
└────────┘ └────────┘
ADR-114-02:库存一致性策略
| 项目 | 内容 |
|---|---|
| 决策 | 采用"预扣+确认/释放"两阶段模式,热点商品用Redis Lua脚本 |
| 背景 | 全渠道库存不能超卖,但门店库存同步有延迟 |
| 选项 | A) 强一致(分布式锁) B) 最终一致(异步) C) 两阶段预扣 |
| 选择 | C + 热点加速 |
| 理由 | A性能差,B可能超卖,C兼顾一致性和性能 |
| 补偿 | 极端情况超卖 → 自动转缺货处理 → 客服补偿 |
3.3 核心域二:智能订单路由
全渠道最关键的差异化能力——当客户下单后,系统需要决定从哪个节点(仓库/门店)发货。
订单路由决策引擎
客户订单
│
▼
┌────────────────┐
│ 订单路由引擎 │
│ (规则+算法) │
└────────┬───────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 可行性筛选 │ │ 成本计算 │ │ 时效预估 │
│ │ │ │ │ │
│ • 有库存?│ │ • 物流成本│ │ • 配送时长│
│ • 可配送?│ │ • 仓储成本│ │ • 承诺时效│
│ • 合规? │ │ • 人力成本│ │ • 客户预期│
└──────────┘ └──────────┘ └──────────┘
│ │ │
└───────────────┼───────────────┘
▼
┌────────────────┐
│ 综合评分排序 │
│ Score = │
│ w1×成本 + │
│ w2×时效 + │
│ w3×门店负荷 + │
│ w4×库存深度 │
└────────┬───────┘
│
▼
┌────────────────┐
│ 最优履约方案 │
│ (可能拆单) │
└────────────────┘
路由策略配置
{
"routing_rules": [
{
"name": "就近门店优先",
"condition": "order.type == 'SAME_DAY' && store.distance < 5km",
"priority": 1,
"weight": {
"cost": 0.3,
"speed": 0.5,
"store_load": 0.2
}
},
{
"name": "仓库发货",
"condition": "order.type == 'STANDARD'",
"priority": 2,
"weight": {
"cost": 0.5,
"speed": 0.3,
"inventory_depth": 0.2
}
},
{
"name": "拆单履约",
"condition": "no_single_source_can_fulfill",
"priority": 3,
"max_split": 3,
"split_cost_threshold": "15元"
}
]
}
3.4 核心域三:统一订单
全渠道订单状态机
┌──────────────────────────────────────────────────────────────────┐
│ 全渠道订单状态机 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ 线上渠道: │
│ 待支付 → 已支付 → 已路由 → 仓库拣货 → 已发货 → 已签收 → 已完成 │
│ │ │ │
│ ├→ 取消(未支付) ├→ 门店拣货 → 待自提 → 已取货 → 已完成 │
│ │ │ │
│ └→ 超时关闭 └→ 门店发货 → 配送中 → 已签收 → 已完成 │
│ │
│ 门店POS渠道: │
│ 扫码/选品 → 结算 → 已支付 → 已完成 │
│ │ │
│ └→ 挂单(暂存) → 恢复 → 结算 → 已支付 → 已完成 │
│ │
│ 门店线上化(导购下单): │
│ 导购选品 → 客户确认 → 已支付 → 按路由履约... │
│ │
│ 逆向流程(所有渠道): │
│ 申请退款/退货 → 审核 → [退货:待收货→已收货] → 退款 → 已退完 │
└──────────────────────────────────────────────────────────────────┘
订单数据模型
-- 主订单表(渠道无关)
CREATE TABLE order_master (
order_id BIGINT PRIMARY KEY, -- 分布式ID
parent_order_id BIGINT, -- 拆单时的父订单ID
channel ENUM('WEB','APP','MINI','POS','GUIDE'),
store_id INT, -- 关联门店(POS/自提)
member_id BIGINT NOT NULL,
status VARCHAR(32) NOT NULL,
total_amount DECIMAL(12,2),
discount_amount DECIMAL(12,2),
pay_amount DECIMAL(12,2),
fulfill_type ENUM('WAREHOUSE','STORE_SHIP','STORE_PICKUP','MIXED'),
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
INDEX idx_member (member_id, created_at),
INDEX idx_store (store_id, created_at)
) PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at));
-- 订单明细表
CREATE TABLE order_item (
item_id BIGINT PRIMARY KEY,
order_id BIGINT NOT NULL,
sku_id BIGINT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(12,2),
discount_amount DECIMAL(12,2),
fulfill_node_id INT, -- 实际履约节点(仓库/门店)
status VARCHAR(32),
FOREIGN KEY (order_id) REFERENCES order_master(order_id)
);
-- 履约单表(与订单1:N关系,拆单后每个履约节点一张)
CREATE TABLE fulfillment_order (
fulfill_id BIGINT PRIMARY KEY,
order_id BIGINT NOT NULL,
node_type ENUM('CDC','RDC','STORE'),
node_id INT NOT NULL,
status VARCHAR(32),
expected_ship DATETIME,
actual_ship DATETIME,
tracking_no VARCHAR(64),
INDEX idx_node (node_id, status)
);
3.5 核心域四:统一会员
┌─────────────────────────────────────────────────┐
│ 统一会员体系 │
├─────────────────────────────────────────────────┤
│ │
│ 身份统一层: │
│ ┌─────────────────────────────────────────┐ │
│ │ 会员ID (唯一) │ │
│ │ ├── 手机号(主标识) │ │
│ │ ├── 微信OpenID │ │
│ │ ├── 支付宝ID │ │
│ │ ├── 门店会员卡号(历史) │ │
│ │ └── App注册ID │ │
│ │ │ │
│ │ OneID策略: 以手机号为主键做身份合并 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ 权益统一层: │
│ ┌─────────────────────────────────────────┐ │
│ │ 统一积分: 线上线下同规则累积、同规则兑换 │ │
│ │ 统一等级: 基于全渠道消费+互动行为 │ │
│ │ 统一券: 跨渠道核销,门店扫码/线上自动抵扣 │ │
│ │ 统一画像: 全渠道行为合并分析 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ 数据同步: │
│ ┌─────────────────────────────────────────┐ │
│ │ 线上 → 实时事件 → 会员服务 │ │
│ │ POS → 交易完成推送 → 会员服务 │ │
│ │ 会员服务 → 变更事件 → CDP/数仓 │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
3.6 核心域五:统一营销
┌─────────────────────────────────────────────────────┐
│ 统一营销引擎 │
├─────────────────────────────────────────────────────┤
│ │
│ 促销规则引擎: │
│ ├── 满减 (全渠道/指定渠道) │
│ ├── 折扣 (品类折扣/单品折扣) │
│ ├── 买赠 (买A送B / 买N送1) │
│ ├── 优惠券 (全渠道券/渠道专属券/门店券) │
│ └── 组合优惠 (套装价/加购价) │
│ │
│ 优惠计算顺序 (叠加规则): │
│ 1. 单品促销 (单品折扣/限时特价) │
│ 2. 品类促销 (满减/满折) │
│ 3. 订单促销 (全场满减) │
│ 4. 优惠券抵扣 (最多叠加2张) │
│ 5. 积分抵扣 │
│ │
│ 互斥规则: │
│ - 同类型促销不叠加,取最优 │
│ - 限时秒杀与其他促销互斥 │
│ - 员工内购不参与促销 │
│ │
│ 渠道差异化: │
│ - 同一促销可配置"适用渠道" │
│ - 门店可叠加"门店专属活动" │
│ - 线上可叠加"新人首单优惠" │
└─────────────────────────────────────────────────────┘
第四步:数据架构(7分钟)
4.1 数据流全景
┌──────────────────────────────────────────────────────────────────────┐
│ 数据流全景 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 数据源层 │
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │线上订单│ │POS交易│ │用户行为│ │库存变动│ │会员变更│ │
│ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Kafka 事件总线 │ │
│ │ Topics: │ │
│ │ order.created / order.paid / order.fulfilled │ │
│ │ pos.transaction / inventory.changed │ │
│ │ member.registered / member.level_changed │ │
│ └────────────────────┬────────────────────────────┘ │
│ │ │
│ ┌────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 实时流处理│ │ 数据同步 │ │ 事件消费 │ │
│ │ Flink │ │ CDC→数仓 │ │ 业务订阅 │ │
│ │ │ │ │ │ │ │
│ │ 实时指标 │ │ ODS→DWD │ │ 积分累加 │ │
│ │ 实时风控 │ │ →DWS→ADS │ │ 库存同步 │ │
│ │ 实时推荐 │ │ │ │ 消息通知 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Redis │ │ 数仓/湖仓 │ │ 业务DB │ │
│ │ 实时看板 │ │ 离线分析 │ │ 状态更新 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────────────────┘
4.2 数据一致性方案
| 场景 | 一致性要求 | 方案 | 说明 |
|---|---|---|---|
| 库存扣减 | 强一致 | Redis Lua + DB事务 | 不允许超卖 |
| 订单创建 | 强一致 | 本地事务 + Outbox模式 | 订单+事件原子写入 |
| 跨域协同 | 最终一致 | Saga编排 | 订单→库存→支付→履约 |
| 会员积分 | 最终一致 | 异步消息 + 对账 | 允许秒级延迟 |
| POS离线 | 冲突合并 | CRDT + 时间戳 | 重连后自动合并 |
| 报表数据 | T+0/T+1 | Flink实时 + 批量校准 | 实时看板+次日精确 |
4.3 数据分库分表策略
订单库: 按 member_id 取模分128库,按月分表
→ 同一会员的订单在同一库,方便查询"我的订单"
→ 跨用户查询走ES二级索引
库存库: 按 sku_id 取模分64库
→ 同一SKU的所有节点库存在同一库,方便全局可售计算
会员库: 按 member_id 取模分32库
→ 会员数据天然按用户隔离
商品库: 按 category_id 分库,全量缓存到Redis/ES
→ 商品数据读多写少,重缓存轻DB
第五步:集成架构(5分钟)
5.1 渠道接入层(BFF模式)
┌──────────────────────────────────────────────────────┐
│ 渠道接入层 │
├──────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ API Gateway (Kong/APISIX) │ │
│ │ • 统一鉴权 (JWT/OAuth2) │ │
│ │ • 限流熔断 (渠道级+接口级) │ │
│ │ • 协议转换 (HTTP/gRPC/WebSocket) │ │
│ │ • 灰度路由 (渠道级灰度发布) │ │
│ └────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌──────────┐ │
│ │BFF-Web │ │BFF-App │ │ BFF-POS │ │
│ │ │ │ │ │ │ │
│ │GraphQL │ │REST API│ │gRPC+离线 │ │
│ │SSR支持 │ │推送支持 │ │本地缓存 │ │
│ │SEO优化 │ │离线包 │ │断网续作 │ │
│ └────────┘ └────────┘ └──────────┘ │
│ │
│ POS BFF 特殊处理: │
│ • 离线模式: 本地SQLite存储 + 重连后同步 │
│ • 数据预加载: 门店商品/价格/促销离线缓存 │
│ • 冲突解决: 以POS交易时间为准,库存差异通知人工 │
└──────────────────────────────────────────────────────┘
5.2 POS离线方案(ADR-114-03)
| 项目 | 内容 |
|---|---|
| 决策 | POS采用"离线优先"架构,本地SQLite + 增量同步 |
| 背景 | 门店网络不稳定,断网时不能停止收银 |
| 方案 | 离线时本地完成交易,联网后批量上传 |
| 冲突 | 库存冲突—离线期间线上可能卖光→人工调整 |
| 保障 | 离线交易有唯一编号,防重复上传 |
POS离线同步流程:
正常模式:
POS → API Gateway → 后端服务 → 实时处理
网络中断:
POS → 本地SQLite (交易/库存/会员操作) → 本地打印小票
→ 心跳检测网络状态
网络恢复:
POS → 读取离线队列 → 按时间顺序批量上传
→ 后端幂等处理(按交易号去重)
→ 冲突检测(库存不足→标记异常→通知店长)
→ 同步最新数据(商品/价格/库存/会员)到本地
5.3 与遗留系统集成
┌─────────────────────────────────────────────┐
│ 集成策略: 绞杀者模式(Strangler) │
├─────────────────────────────────────────────┤
│ │
│ 阶段1: 门面层 (3个月) │
│ ├── 在旧系统前加API Gateway │
│ ├── 新请求走新服务,旧请求转发旧系统 │
│ └── ERP数据通过CDC同步到新平台 │
│ │
│ 阶段2: 核心迁移 (6个月) │
│ ├── 订单服务切到新平台 │
│ ├── 库存服务切到新平台 │
│ ├── 新老系统双写过渡期 │
│ └── 比对校验无差异后切流 │
│ │
│ 阶段3: 全量切换 (3个月) │
│ ├── 会员/营销/商品全部切到新平台 │
│ ├── 旧ERP降级为"记账系统" │
│ └── POS终端升级为新客户端 │
│ │
│ 阶段4: 下线旧系统 (持续) │
│ ├── 旧系统数据归档 │
│ ├── 逐步下线旧接口 │
│ └── 旧ERP仅保留财务模块 │
└─────────────────────────────────────────────┘
第六步:扩展讨论(5分钟)
6.1 从单渠道到全渠道的演进策略
2025-2026年行业趋势表明,全渠道已从"锦上添花"变为"生存必需"。根据BigCommerce 2026年报告,全渠道零售不再是竞争优势而是baseline。关键演进路径:
Level 0: 多渠道独立运营 (Multi-Channel)
└── 各渠道独立系统,数据不通,体验割裂
Level 1: 数据层打通 (Cross-Channel)
└── 统一会员ID,数据汇总到数仓,但系统仍独立
Level 2: 业务层打通 (Omni-Channel)
└── 统一库存+统一订单+跨渠道履约+统一会员权益
Level 3: 体验层统一 (Unified Commerce)
└── 客户无感切换渠道,导购/客服看到全渠道视图
└── AI驱动个性化,线上线下实时联动
Level 4: 智能商务 (Intelligent Commerce) [2025-2026趋势]
└── AI Agent自主完成推荐/客服/履约决策
└── 预测性补货+动态定价+自动营销
└── AR/VR虚拟试穿试用融入购物流程
6.2 性能与容量规划
日均100万单的技术指标:
QPS估算:
下单高峰(集中在10小时): 100万/10h/3600s ≈ 28 QPS (日常)
大促峰值(10倍): 280 QPS
秒杀尖峰(100倍): 2800 QPS
查询类请求(20:1读写比): 5.6万 QPS
容量规划:
订单DB: 100万单/天 × 365天 = 3.65亿行/年 → 分库分表
库存记录: 500万SKU × 2010节点 = 100亿行 → TiDB
会员数据: 5000万会员 → 分库
缓存: Redis集群 256GB+ (热点商品+库存+会员)
服务实例数:
订单服务: 16实例 (4C8G)
库存服务: 32实例 (高频+高一致性)
商品服务: 8实例 (读密集+缓存)
搜索服务: ES 12节点集群
面试官常见追问
追问1: "库存协同——线上线下同时秒杀,库存怎么分配?"
回答策略:
方案: 弹性库存预分配 + 实时回流
1. 活动前: 按渠道历史占比预分配
线上70% + 门店20% + 共享池10%
2. 活动中: 动态调整
某渠道售罄 → 从共享池补充
共享池空了 → 跨渠道"借调"(需另一渠道同意)
3. 防超卖:
每个渠道有独立的Redis计数器
共享池有独立计数器 + 分布式锁
跨渠道借调需要两阶段确认
4. 兜底:
极端情况允许1%超卖 → 自动触发缺货处理流程
追问2: "订单路由——如果门店拒绝接单怎么办?"
门店拒单处理:
1. 自动重路由: 拒单后立即选择次优节点
2. 超时机制: 门店10分钟未确认自动重路由
3. 拒单惩罚: 频繁拒单影响门店评分→降低路由优先级
4. 人工兜底: 三次重路由失败转人工客服协调
5. 数据分析: 记录拒单原因(缺货/忙/距离)优化路由策略
追问3: "离线POS重连后,发现库存已被线上卖光怎么办?"
冲突场景: 门店离线卖了10件A商品,但线上已卖光
处理策略:
1. 承认离线交易(已完成的不回撤)
2. 库存记为负数,标记"超卖"
3. 触发紧急补货流程
4. 如果补货不及时 → 从其他门店调拨
5. 长期方案: 门店为离线模式预留安全库存
离线可售 = 实际库存 - 安全预留(如30%)
追问4: "秒杀场景如何设计?"
全渠道秒杀 = Day 76秒杀架构 + 多渠道库存分配
关键补充:
1. 秒杀库存独立管理(不走普通库存流程)
2. 门店秒杀: 限本店购买,门店独立库存计数
3. 线上秒杀: Redis Lua扣减 + 异步落DB
4. 跨渠道秒杀: 共享库存池 + 渠道限购
5. 防黄牛: 同一会员跨渠道限购(统一会员ID实现)
追问5: "数据一致性——订单创建失败但库存已扣怎么办?"
Saga模式补偿:
正向流程: 扣库存 → 创建订单 → 扣款
补偿流程: 退款 ← 取消订单 ← 恢复库存
具体实现:
1. 编排器(Orchestrator)控制Saga流程
2. 每一步操作都有对应的补偿操作
3. 操作日志记录完整(便于排查和重试)
4. 幂等设计(补偿操作可以重复执行)
5. 超时策略(步骤超时自动触发补偿)
代码示例:
saga = Saga.create("CREATE_ORDER")
.step(inventoryService::reserve, inventoryService::release)
.step(orderService::create, orderService::cancel)
.step(paymentService::charge, paymentService::refund)
.build();
完整答案回顾检查清单
| 检查项 | 是否覆盖 |
|---|---|
| 需求澄清(展示沟通能力) | ✅ |
| 高层架构(C4 Context + Container) | ✅ |
| 领域划分(DDD限界上下文) | ✅ |
| 核心域设计(库存/订单/会员/营销/履约) | ✅ |
| 数据模型(表结构/分库策略) | ✅ |
| API设计(BFF模式/渠道差异化) | ✅ |
| 数据一致性(Saga/事件/补偿) | ✅ |
| 集成策略(遗留系统/POS离线) | ✅ |
| ADR决策记录 | ✅ |
| 非功能性(性能/容量/可用性) | ✅ |
| 演进策略(分阶段迁移) | ✅ |
| 追问准备 | ✅ |
与前四次系统设计的对比
| 维度 | 本次(全渠道) | 核心差异 |
|---|---|---|
| 领域复杂度 | ★★★★★ | 最复杂——涉及线上+线下+物流+门店 |
| 一致性挑战 | ★★★★★ | 最难——跨渠道库存+离线POS |
| 集成复杂度 | ★★★★★ | 最复杂——遗留系统+第三方+POS |
| 面试展示度 | ★★★★★ | 体现全栈架构能力 |
面试技巧: 全渠道题目最能体现"业务架构+技术架构"双重能力。不要一上来就画微服务,先用5分钟展示你对零售业务的理解(渠道、库存、履约),再展开技术方案。面试官考的不仅是"你会画架构图",更是"你理解业务"。
今日总结
关键收获
- 全渠道的核心不是"多渠道接入",而是"统一商务"——统一库存、统一订单、统一会员、统一履约
- 库存是全渠道最核心也最难的域——需要在实时性、一致性、性能三者间精细权衡
- POS离线是全渠道特有的挑战——离线优先架构 + CRDT + 冲突合并
- 智能订单路由是全渠道差异化能力——从"就近发货"到"全局最优"
- 演进策略比目标架构更重要——从单渠道到全渠道需要分阶段迁移,不能Big Bang
五次系统设计总结
至此,五次系统设计面试练习全部完成:
| 次序 | 主题 | 核心考点 |
|---|---|---|
| 1 | 支付系统 | 金融一致性/幂等/对账 |
| 2 | 核心银行 | 记账引擎/批处理/高可用 |
| 3 | 电商平台 | 高并发/搜推/促销 |
| 4 | 供应链 | 仓储/物流/预测 |
| 5 | 全渠道 | 统一商务/库存协同/线下集成 |
这五个主题覆盖了金融+零售两大领域的核心架构场景,足以应对绝大多数系统设计面试。
明日预告: Day 115 - 业务架构面试专题,15道精选业务架构面试题,涵盖TOGAF、能力建模、价值流、Wardley Map等核心主题。