第二章:库存系统架构演进——从单体到中台的蜕变之路
大家好,我是老张。今天咱们聊聊库存系统架构的演进历程。说实话,我从业这十几年,亲眼看着库存系统从“一个文件搞定”变成了“一个团队都搞不定”的庞然大物。这中间踩过的坑,够写一本小说了。
你想想看,一个电商平台的库存系统,从最初每天几百单,到后来双十一每秒几万单,架构不变能行吗?肯定不行。那咱们就从头捋一捋,看看这四代架构到底是怎么演进的。
2.1 单体架构:一切从简
最早期的库存系统,说白了就是一个大杂烩。订单、商品、库存、用户,全写在一个项目里。我记得2008年我刚入行时,公司那个库存系统就是一个Java Web项目,所有代码都在一个WAR包里。
2.1.1 单体架构长什么样?
简单来说,就是所有功能都塞进一个进程里。库存查询、库存扣减、库存预警,全在一个应用里跑。数据库也就一个MySQL实例,几张表搞定。
// 典型的单体库存系统代码结构
com.company.inventory/
├── controller/
│ ├── InventoryController.java // 库存接口
│ └── OrderController.java // 订单接口(也在同一个项目里)
├── service/
│ ├── InventoryService.java // 库存业务逻辑
│ └── OrderService.java // 订单业务逻辑
├── dao/
│ └── InventoryDao.java // 数据库操作
└── model/
└── Inventory.java // 库存实体类
你看,所有东西都在一起。开发的时候确实爽,本地启动一个Tomcat就能跑。但问题也来了——
2.1.2 单体架构的优缺点
| 优点 | 缺点 |
|---|---|
| 开发简单,上手快 | 耦合严重,改一处可能影响全局 |
| 部署方便,一个WAR包搞定 | 无法独立扩展,库存压力大时整个系统都得扩容 |
| 调试容易,本地就能跑 | 团队协作困难,代码冲突频繁 |
| 事务好控制,本地事务就够 | 技术栈绑定,想换语言?重写吧 |
我踩过的坑: 2012年在一家电商公司,双十一前夜改了一个库存扣减的逻辑,结果把订单模块的某个功能搞崩了。为什么?因为两个模块共享了一个静态变量。嗯,从那以后我养成了一个习惯——任何共享状态都要三思而后行。
2.2 垂直拆分:按业务切一刀
随着业务增长,单体架构扛不住了。我记得当时公司业务线多了起来,有自营、有第三方、有跨境。所有库存都混在一起,谁都不敢动。于是,垂直拆分来了。
2.2.1 什么是垂直拆分?
说白了,就是按业务领域把系统拆成多个子系统。库存系统独立出来,订单系统独立出来,商品系统也独立出来。每个系统有自己的数据库,通过API互相调用。
// 垂直拆分后的库存系统
// 库存系统独立部署,只负责库存相关逻辑
@RestController
@RequestMapping("/inventory")
public class InventoryController {
@Autowired
private InventoryService inventoryService;
@PostMapping("/deduct")
public Result deductStock(@RequestBody DeductRequest request) {
// 只做库存扣减,不关心订单
return inventoryService.deduct(request.getSkuId(), request.getQuantity());
}
@GetMapping("/query/{skuId}")
public Result queryStock(@PathVariable String skuId) {
return inventoryService.queryStock(skuId);
}
}
2.2.2 垂直拆分的优缺点
| 优点 | 缺点 |
|---|---|
| 系统解耦,各团队独立开发 | 跨系统调用变多,接口设计成关键 |
| 可以独立扩缩容,库存系统单独加机器 | 分布式事务问题出现,库存扣减和订单创建需要协调 |
| 技术栈可以不同,库存系统用Java,订单系统用Go都行 | 重复建设严重,每个系统都要做权限、日志、监控 |
| 故障隔离,库存系统挂了不影响订单查询 | 数据一致性难保证,库存扣减成功但订单创建失败怎么办? |
注意: 垂直拆分不是银弹。我见过一个团队把系统拆成了十几个子系统,结果每个子系统都自己写了一套库存扣减逻辑。你想想看,同样的业务逻辑重复了十几遍,这不是更乱了吗?
2.3 微服务架构:更细粒度的拆分
垂直拆分之后,大家发现每个子系统内部还是太臃肿。库存系统里,库存查询、库存扣减、库存预警、库存调拨,全在一个服务里。于是,微服务来了。
2.3.1 微服务怎么拆?
微服务的核心思想是:每个服务只做一件事,并且做好。库存系统可以拆成:
- 库存查询服务:只负责读,可以加缓存,扛高并发
- 库存扣减服务:负责写,需要保证数据一致性
- 库存预警服务:定时检查库存水位,触发补货
- 库存调拨服务:处理仓库间的库存转移
// 微服务架构下的库存扣减服务
// 独立部署,独立数据库
@Service
public class DeductStockService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private InventoryMapper inventoryMapper;
@Transactional
public boolean deduct(String skuId, int quantity) {
// 1. 先查缓存
Integer stock = (Integer) redisTemplate.opsForValue().get("stock:" + skuId);
if (stock == null || stock < quantity) {
return false;
}
// 2. 用分布式锁防止超卖
String lockKey = "lock:stock:" + skuId;
RLock lock = redissonClient.getLock(lockKey);
try {
lock.lock(5, TimeUnit.SECONDS);
// 3. 扣减数据库
int affected = inventoryMapper.deductStock(skuId, quantity);
if (affected > 0) {
// 4. 更新缓存
redisTemplate.opsForValue().decrement("stock:" + skuId, quantity);
return true;
}
return false;
} finally {
lock.unlock();
}
}
}
2.3.2 微服务的优缺点
| 优点 | 缺点 |
|---|---|
| 独立部署,快速迭代 | 分布式复杂性剧增,服务发现、配置中心、熔断降级都得搞 |
| 弹性伸缩,库存扣减服务可以单独扩到100台 | 数据一致性更难,最终一致性方案需要精心设计 |
| 故障隔离,库存查询服务挂了不影响扣减 | 运维成本高,几十个服务需要监控、日志、链路追踪 |
| 技术多样性,不同服务可以用不同语言 | 团队沟通成本增加,一个需求可能要协调多个服务 |
我的建议: 微服务不是越细越好。我曾经见过一个团队把库存服务拆成了20多个微服务,结果每次上线都要协调十几个团队。说白了,微服务的粒度应该以“业务边界”为准,而不是技术上的“能拆就拆”。
2.4 中台架构:能力复用
微服务之后,大家发现了一个新问题:公司有多个业务线,每个业务线都自己搞了一套库存服务。自营业务有库存,第三方业务有库存,跨境业务也有库存。虽然都是库存,但实现各不相同。于是,中台思想来了。
2.4.1 中台的核心是什么?
中台说白了就是“共享服务层”。把各个业务线通用的能力抽出来,形成一个统一的中台。库存中台提供统一的库存查询、扣减、预占等能力,所有业务线都调用同一个中台。
// 库存中台:统一对外接口
// 所有业务线都通过这个接口操作库存
@RestController
@RequestMapping("/inventory-center")
public class InventoryCenterController {
@Autowired
private InventoryCenterService centerService;
// 统一库存扣减接口
@PostMapping("/deduct")
public Result deduct(@RequestBody DeductRequest request) {
// request中包含业务线标识
String bizLine = request.getBizLine();
// 不同业务线可能有不同的扣减策略
return centerService.deduct(bizLine, request.getSkuId(), request.getQuantity());
}
// 统一库存查询接口
@GetMapping("/query")
public Result query(@RequestParam String bizLine, @RequestParam String skuId) {
return centerService.query(bizLine, skuId);
}
}
2.4.2 中台的优缺点
| 优点 | 缺点 |
|---|---|
| 能力复用,避免重复建设 | 中台容易变成“大泥球”,什么逻辑都往里塞 |
| 统一管控,库存规则一致 | 组织架构调整困难,需要打破部门墙 |
| 降低业务线开发成本 | 中台团队容易成为瓶颈,所有需求都得排队 |
| 数据统一,全局库存视图 | 中台变更影响所有业务线,上线风险大 |
我踩过的坑: 曾经参与过一个中台项目,中台团队把所有的业务逻辑都抽象成了“通用能力”。结果呢?通用是通用了,但每个业务线都要做定制化开发,最后中台代码里全是if-else判断业务线。嗯,中台不是万能药,过度抽象反而会害了自己。
2.5 总结:没有最好的架构,只有最合适的
说了这么多,你可能会问:到底该选哪种架构?我的答案是:看阶段。
- 初创期:单体架构就够了,别折腾。快速验证业务才是王道。
- 成长期:垂直拆分,按业务域切分。这时候团队开始扩张,需要明确分工。
- 爆发期:微服务架构,细粒度拆分。高并发、高可用是核心诉求。
- 成熟期:中台架构,能力复用。多业务线并行,需要统一管控。
记住一句话:架构是演进而来的,不是设计出来的。别一开始就想着搞个完美的中台,先把业务跑起来再说。
公众号:蓝海资料掘金营,微信deep3321