-- 分区策略(数据量大时启用) ALTERTABLE price_calendar PARTITIONBYRANGE (TO_DAYS(date)) ( PARTITION p202604 VALUES LESS THAN (TO_DAYS('2026-05-01')), PARTITION p202605 VALUES LESS THAN (TO_DAYS('2026-06-01')), PARTITION p202606 VALUES LESS THAN (TO_DAYS('2026-07-01')), PARTITION pmax VALUES LESS THAN MAXVALUE );
-- reserve_stock.lua (原子库存预占) local sku_key = KEYS[1] -- inventory:sku:12345 local reserve_key = KEYS[2] -- reserve:uuid-xxx local expire_zset_key = KEYS[3] -- reserve:expiry
local quantity = tonumber(ARGV[1]) local reserve_data = ARGV[2] -- JSON序列化的预占数据 local expires_at = tonumber(ARGV[3]) -- Unix时间戳 local ttl = tonumber(ARGV[4]) -- 15分钟
-- 检查库存 local available = tonumber(redis.call('HGET', sku_key, 'available')) ifnot available or available < quantity then return {err = 'insufficient_stock'} end
flowchart TB
subgraph Client
U[商城 Web / App]
end
subgraph Edge
G[API Gateway]
end
subgraph MerchandisingQuery["导购查询服务"]
Q[Query 理解]
R[Recall / ES]
P[Rank: 粗排 / 精排 / 重排]
H[Hydrate 编排]
end
subgraph ReadDeps["读依赖(弱一致为主)"]
PC[商品读服务 / 批量详情]
PR[计价只读接口]
INV[库存摘要接口]
MK[营销圈品与标签只读]
CFG[运营配置 / 加权]
end
ES[(Elasticsearch)]
U --> G --> Q --> R
R --> ES
R --> P --> H
H --> PC
H --> PR
H --> INV
H --> MK
P --> CFG
flowchart LR
subgraph Recall["召回 (ES)"]
A[候选集 N]
end
subgraph Coarse["粗排"]
B[截断 M]
end
subgraph Fine["精排"]
C[Top K]
end
subgraph Rerank["重排"]
D[Top P 返回页]
end
A --> B --> C --> D
阶段
典型输入
典型输出
说明
粗排
ES 召回前 N(如 500~2000)
截断到 M(如 200)
主要用 _score + 简单线性特征(销量、上架时间)可在 ES function_score 或应用内完成
sequenceDiagram
participant L as 上架 / 商品领域服务
participant MQ as 消息总线 (如 Kafka)
participant W as 索引构建 Worker
participant ES as Elasticsearch
L->>MQ: 商品或上架状态变更事件
MQ->>W: 至少一次投递
W->>W: 幂等:比较 version / updated_at
W->>ES: bulk index / update / delete
ES-->>W: ack
5.3 列表请求路径(序列图)
sequenceDiagram
participant U as 用户
participant G as Gateway
participant M as 导购查询服务
participant ES as Elasticsearch
participant H as 计价 / 库存 / 营销只读
U->>G: 搜索 / 列表请求 + query_id
G->>M: 鉴权、限流、透传实验桶
M->>M: Query 理解
M->>ES: DSL 召回 + 粗排字段
ES-->>M: hits + sort keys
M->>M: 精排 / 重排
M->>H: batch hydrate(限时)
H-->>M: 部分成功
M-->>G: 列表 DTO + rank_version
G-->>U: 响应
UPDATE shopping_cart SET quantity = #{newQuantity}, version = version +1, updated_at = NOW() WHERE user_id = #{userID} AND sku_id = #{skuID} AND version = #{expectedVersion};
若更新行数为 0,表示并发冲突,返回前端重试。
3.5 购物车核心场景详解
3.5.1 未登录加购流程
sequenceDiagram
participant U as 用户(未登录)
participant F as 前端
participant C as 购物车服务
participant R as Redis
U->>F: 点击"加入购物车"
F->>F: 检查本地是否有 cart_token
alt 无 cart_token
F->>C: POST /cart/add-anonymous
C->>C: 生成 cart_token(UUID)
C->>R: HSET cart:token:{token} {sku_id} {qty}
C-->>F: 返回 cart_token
F->>F: 存储 cart_token 到 Cookie/LocalStorage
else 已有 cart_token
F->>C: POST /cart/add (带 cart_token)
C->>R: HINCRBY cart:token:{token} {sku_id} {qty}
end
C-->>U: "加购成功"
graph LR
subgraph 购物车商品
A[SKU1 店铺A]
B[SKU2 店铺A]
C[SKU3 店铺B]
end
subgraph 拆单预览
D[订单1: 店铺A SKU1+SKU2 运费12元]
E[订单2: 店铺B SKU3 运费8元]
end
A --> D
B --> D
C --> E
sequenceDiagram
participant U as 用户
participant C as 购物车服务
participant R as Redis
participant P as 商品中心 (27)
U->>C: 查看购物车
C->>R: HGETALL cart:{user_id}
R-->>C: {sku1: qty1, sku2: qty2}
C->>P: POST /product/batch-get ([sku1, sku2])
P-->>C: [{sku1: {title, img, status}}, ...]
C-->>U: 购物车列表(含商品信息)
graph LR
A[接收供应商数据] --> B{商品存在?}
B -->|否| C[创建新商品 - 走上架流程]
B -->|是| D[计算差异]
D --> E{需要审核?}
E -->|否| F[直接更新]
E -->|是| G[创建变更审批单]
G --> H[推送审核队列]
H --> I{审核结果}
I -->|通过| F
I -->|驳回| J[记录驳回原因]
2.3 运营编辑(日常维护)
运营编辑是指运营人员对已上线商品进行日常维护和批量管理的过程。
业务语义
已上线商品的日常维护,包括:
单品编辑:修改商品标题、描述、价格、库存等
批量操作:批量调价、批量上下架、批量修改类目
触发方式
graph LR
A[运营后台手动操作] --> C[批量操作服务]
B[批量Excel导入] --> C
C --> D[生成操作批次ID]
D --> E[流式解析数据]
E --> F[Worker Pool 并发处理]
graph TD
A[批量操作提交] --> B[解析数据]
B --> C[Worker Pool 并发处理]
C --> D{需要审核?}
D -->|否| E[直接更新]
D -->|是| F[创建变更审批单]
F --> G[审核流程]
G --> H{审核结果}
H -->|通过| E
H -->|驳回| I[记录失败原因]
E --> J[更新批量操作状态]
I --> J
graph TD
A[商品变更] --> B{风险评估}
B -->|风险极低| C[免审核 - 直接生效]
B -->|风险低| D[自动审核 - 规则引擎]
B -->|风险中| E[人工审核 - 推送审核队列]
B -->|风险高| F[严格审核 - 多级审核]
C --> G[更新数据库]
D --> H{规则通过?}
H -->|是| G
H -->|否| E
E --> I[审核员认领]
I --> J{审核通过?}
J -->|是| G
J -->|否| K[驳回]
F --> L[一级审核]
L --> M[二级审核]
M --> J
graph LR
A[商品变更] --> B[风险评估]
B --> C{需要审核?}
C -->|否| D[直接更新]
C -->|是| E[创建审批单]
E --> F[推送 Kafka 队列]
F --> G[审核 Worker 消费]
G --> H[分配审核员]
H --> I[审核员审核]
I --> J{审核结果}
J -->|通过| K[应用变更]
J -->|驳回| L[记录驳回原因]
K --> M[发送通知]
L --> M
graph LR
A[商品状态变更] --> B[发布生命周期事件]
B --> C[Kafka Topic]
C --> D[搜索引擎 ES]
C --> E[缓存系统 Redis]
C --> F[推荐系统]
C --> G[通知系统]
D --> H[同步商品索引]
E --> I[更新热点商品缓存]
F --> J[更新推荐池]
G --> K[发送商家通知]
graph TD
A[幂等性设计] --> B[请求层幂等]
A --> C[任务层幂等]
A --> D[数据层幂等]
B --> B1[HTTP 幂等性 Key]
B --> B2[API 限流]
C --> C1[唯一任务标识符]
C --> C2[任务状态判断]
D --> D1[唯一索引]
D --> D2[乐观锁 version]
D --> D3[状态机校验]
graph TD
A[商品中心] --> A1[商品主数据管理]
A --> A2[生命周期管理]
A --> A3[审核流程]
A --> A4[数据分发]
B[定价引擎] --> B1[促销价格计算]
B --> B2[阶梯价格计算]
B --> B3[动态定价]
C[库存系统] --> C1[库存扣减]
C --> C2[库存预占]
C --> C3[库存对账]
D[营销系统] --> D1[满减活动]
D --> D2[优惠券]
D --> D3[拼团活动]
E[搜索引擎] --> E1[全文检索]
E --> E2[相关性排序]
A -.事件.-> B
A -.事件.-> C
A -.事件.-> D
A -.事件.-> E
职责边界划分原则
单一数据源(Single Source of Truth):
商品基础信息:商品中心
价格信息:定价引擎
库存信息:库存系统
促销信息:营销系统
避免职责重叠:
商品中心只存储商品基础价格(base_price),不负责促销价格计算
商品中心只缓存库存快照,不负责库存扣减
通过事件解耦:
商品中心发布事件,下游系统监听并更新本地数据
避免直接调用下游系统的修改接口
6.2 与定价引擎的协作
协作场景
商品中心与定价引擎的协作场景包括:
商品上架时初始化价格:新商品上架时,需要在定价引擎中创建价格记录
运营批量调价:运营批量修改商品价格,需要同步到定价引擎
供应商同步价格变更:供应商同步价格变更,需要通知定价引擎
查询最终价格:用户浏览商品时,需要查询促销后的最终价格
协作模式
sequenceDiagram
participant OP as 运营系统
participant PC as 商品中心
participant PE as 定价引擎
participant Kafka as Kafka
participant Cache as Redis缓存
Note over OP,Cache: 场景1:商品上架时初始化价格
OP->>PC: 1. 创建商品(含基础价格)
PC->>PC: 2. 保存商品到数据库
PC->>PE: 3. 同步调用:初始化价格
PE->>PE: 4. 创建价格记录
PE-->>PC: 5. 返回成功
PC->>Kafka: 6. 发布 ProductCreated 事件
Note over OP,Cache: 场景2:价格变更
OP->>PC: 1. 修改商品基础价格
PC->>PC: 2. 更新商品表
PC->>Kafka: 3. 发布 ProductPriceChanged 事件
Kafka->>PE: 4. 定价引擎消费事件
PE->>PE: 5. 更新价格记录
PE->>Kafka: 6. 发布 PriceUpdated 事件
Kafka->>Cache: 7. 缓存系统更新缓存
Note over OP,Cache: 场景3:查询最终价格
OP->>PC: 1. 查询商品详情
PC->>Cache: 2. 查询缓存
alt 缓存命中
Cache-->>PC: 3a. 返回缓存数据
else 缓存未命中
PC->>PE: 3b. RPC 调用:查询最终价格
PE-->>PC: 4b. 返回促销价格
PC->>Cache: 5b. 更新缓存
end
PC-->>OP: 6. 返回商品详情(含最终价格)
graph TD
A[商品数据变更需求] --> B{商品是否存在?}
B -->|不存在| C[商品上架流程]
B -->|存在| D{数据来源?}
D -->|供应商系统| E{商品是否存在?}
E -->|不存在| F[供应商同步 - 创建]
E -->|存在| G[供应商同步 - 更新]
D -->|运营后台| H[运营编辑流程]
D -->|商家Portal| I{商品状态?}
I -->|DRAFT/REJECTED| C
I -->|其他状态| H
-- 1. 获取普通库存和营销库存 local available = tonumber(redis.call('HGET', key, 'available') or0) local promo = tonumber(redis.call('HGET', key, promotion_id) or0) local total = available + promo
-- 2. 检查库存 if book_num > total thenreturn-1end
-- 3. 优先扣营销库存,不足时扣普通库存 if promo >= book_num then redis.call('HINCRBY', key, promotion_id, -book_num) else redis.call('HSET', key, promotion_id, 0) redis.call('HINCRBY', key, 'available', -(book_num - promo)) end
// BAD: one struct serves two contexts with conflicting meanings type Product struct { ID string Title string PriceCent int64// pricing in order context WarehouseQty int// stock in inventory context — coupling contexts }
合规 sketch:不同 BC 使用不同模型与防腐层翻译;集成通过 API、消息或显式 ACL。
1 2 3 4 5 6 7 8 9 10 11 12 13
// GOOD: separate models + explicit mapping at boundary type catalog.ProductView struct { ID, Title string }
type ordering.OrderLine struct { ProductID string UnitPrice Money SnapshotTitle string// captured at order time, not live catalog coupling }
type inventory.StockUnit struct { SKU string OnHand int }
评审追问:若两个 BC 必须共享标识符,是共享 ID 还是共享 富模型?前者常见且可接受,后者往往是边界溃缩的信号。
// BAD: line exported and mutated from outside aggregate type Order struct { ID string Lines []*OrderLine // exported slice of mutable lines } type OrderLine struct { SKU string Qty int }
funcSomeHandler() { o := &Order{ID: "1", Lines: []*OrderLine{{SKU: "A", Qty: 1}}} o.Lines[0].Qty = 999// invariant broken: no route through Order root }
funcNewClient(host string, port int, opts ...clientOption) *Client { c := &Client{host: host, port: port, timeout: 5 * time.Second} for _, o := range opts { o(c) } return c }
# 动态规划 asyncdefhandle_alert(alert): for i inrange(max_iterations): action = await llm.decide_next_action(context) if action == "final_answer": return result result = await execute_tool(action) context.append(result)
关键差异:
传统后端:编译时确定流程
Agent 系统:运行时动态规划
应对策略:
设置最大迭代次数
检测循环和死锁
提供流程可视化
7.2 后端工程师的优势
作为后端工程师,你在 Agent 开发中有独特的优势:
优势 1:系统设计能力
1 2 3 4 5 6 7 8
传统后端技能 → Agent 应用
分布式系统设计 → Multi-Agent 协调 消息队列 → Agent 异步处理 缓存策略 → Semantic Cache 限流熔断 → LLM 调用保护 数据库设计 → Memory System API 设计 → Tool System
Claude Code是Anthropic推出的AI编程助手,与传统IDE集成的AI工具不同,它直接在终端运行,能够自主规划步骤、读写代码、执行命令、操作git,完成完整的开发循环。Boris Cherny(Claude Code创建者)公开表示,使用Opus 4.5后就再也没有手写过一行代码,47天里有46天都在使用。
func(p *CircuitBreakerProcessor) Process(ctx context.Context, fsCtx *FlashSaleContext) error { // 检查熔断器状态 if p.circuitBreaker.IsOpen() { return fmt.Errorf("circuit breaker is open for %s", p.wrapped.Name()) } // 执行原始 Processor err := p.wrapped.Process(ctx, fsCtx) // 记录结果 if err != nil { p.circuitBreaker.RecordFailure() } else { p.circuitBreaker.RecordSuccess() } return err }
// 熔断器实现 type CircuitBreaker struct { failureCount int failureThreshold int state string// "closed", "open", "half_open" lastFailureTime time.Time timeout time.Duration mu sync.Mutex }
// internal/infrastructure/persistence/model/activity_po.go package model
type ActivityPO struct { ID int64`gorm:"column:id;primaryKey"` Name string`gorm:"column:name"` StartTime time.Time `gorm:"column:start_time"` EndTime time.Time `gorm:"column:end_time"` Status int`gorm:"column:status"` MaxDraws int`gorm:"column:max_draws"` }
flowchart TD
A[识别子域] --> B{直接影响收入/利润/核心指标?}
B -->|是| C{竞品难以模仿?}
B -->|否| D{业务必需?}
C -->|是| E[核心域候选]
C -->|否| F{变化频繁?}
D -->|是| G{有业务特色?}
D -->|否| H[通用域]
F -->|是| I[支撑域]
F -->|否| H
G -->|是| I
G -->|否| H
E --> J{团队投入意愿高?}
J -->|是| K[确认:核心域]
J -->|否| L[降级:支撑域]
style K fill:#ffcdd2,stroke:#c62828,stroke-width:3px
style I fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
style H fill:#bbdefb,stroke:#1565c0,stroke-width:2px
sequenceDiagram
participant App as Application
participant DB as MySQL
participant Relay as Outbox Relay
participant MQ as Kafka
App->>DB: BEGIN TX
App->>DB: INSERT orders (聚合数据)
App->>DB: INSERT outbox (领域事件)
App->>DB: COMMIT TX
loop 定期轮询
Relay->>DB: SELECT * FROM outbox WHERE status='pending'
Relay->>MQ: Publish(event)
MQ-->>Relay: ACK
Relay->>DB: UPDATE outbox SET status='sent'
end
flowchart LR
subgraph 写路径 Command Side
A[Client] -->|Command| B[Command Handler]
B --> C[Domain Model / Aggregate]
C --> D[(Write DB - MySQL)]
C -->|Domain Event| E[Event Bus]
end
subgraph 读路径 Query Side
E -->|同步/异步投影| F[Read Model Builder]
F --> G[(Read DB - ES/Redis)]
H[Client] -->|Query| I[Query Handler]
I --> G
end
flowchart LR
A[Event Store / MQ] --> B[Projector]
B --> C[(Read DB)]
B --> D{事件类型路由}
D -->|OrderPlaced| E[创建订单读模型]
D -->|ItemAdded| F[更新商品明细]
D -->|OrderCancelled| G[标记订单取消]
graph TB
subgraph "Clean Architecture 提供分层骨架"
direction TB
E[Entity Layer]
U[Use Case Layer]
A[Adapter Layer]
F[Framework Layer]
F --> A --> U --> E
end
subgraph "DDD 填充业务建模"
direction TB
AG[Aggregate Root]
VO[Value Object]
DE[Domain Event]
DS[Domain Service]
end
subgraph "CQRS 优化数据流转"
direction TB
CMD[Command Path]
QRY[Query Path]
end
E --- AG
E --- VO
U --- CMD
U --- QRY
U --- DE
U --- DS
角色
职责
Clean Architecture(架构底座)
定义目录结构和依赖方向,确保领域层位于中心,不依赖外部技术
DDD(核心建模)
在 Entity 和 Use Cases 层中,利用聚合根、实体和领域服务编写复杂的业务逻辑
CQRS(数据流转)
在 Use Cases 层进行读写拆分:写操作走 DDD 的领域模型(Command),读操作绕过复杂的领域模型,直接通过 DTO 投影(Query)到前端
adapter/outbound/ ├── persistence/ # Write DB (MySQL) ├── readmodel/ # Read DB (ES/Redis) └── projection/ # Event → Read Model
收益:写操作保证事务一致性,读操作针对查询优化。两者可以独立扩展。
演进决策树
flowchart TD
A[当前是三层架构] --> B{测试困难? 换存储/框架?}
B -->|是| C[阶段 1: Clean Architecture]
B -->|否| A
C --> D{业务规则复杂? Service 层膨胀?}
D -->|是| E[阶段 2: + DDD]
D -->|否| C
E --> F{读写矛盾? 查询需要宽表?}
F -->|是| G[阶段 3: + CQRS]
F -->|否| E
funcUpdateStatus(taskID int64, fromStatus, toStatus int, action string)error { result, err := db.Exec(` UPDATE listing_task_tab SET status = ?, version = version + 1, updated_at = NOW() WHERE id = ? AND status = ? AND version = ? `, toStatus, taskID, fromStatus, currentVersion)
if result.RowsAffected() == 0 { return errors.New("concurrent modification or status changed") }