1) 【一句话结论】
采用微服务架构,通过异步解耦(Kafka)、缓存分层(Redis)、数据库分库分表(MySQL),结合集群部署实现高可用,在双十一等大促期间通过负载均衡(Nginx)和动态扩容保障低延迟与高吞吐,并设计异常回滚机制确保数据一致性。
2) 【原理/概念讲解】
老师口吻解释各组件作用:
- 前端:Nginx作为反向代理和负载均衡,分发请求到后端微服务,处理静态资源(如商品图片),提升首屏加载速度。
- 后端:微服务拆分(订单服务、库存服务、支付服务等),每个服务独立部署,降低耦合,便于按需动态扩容(如双十一时增加订单服务实例)。
- 缓存:Redis用于缓存高频访问数据(如订单状态、商品信息、库存数量),减少数据库压力。策略:读从缓存,写更新缓存(设置TTL避免数据过期不一致);通过布隆过滤器防缓存击穿(预过滤无效请求),随机过期时间防缓存雪崩(避免集中过期)。
- 消息队列:Kafka用于异步处理订单状态变更(如订单创建后发送库存扣减消息),解耦订单与库存服务,避免同步调用阻塞主流程。特性:高吞吐、持久化、可扩展,支持消费端幂等性(确保消息重复消费不重复操作)。
- 数据库:MySQL分库分表(水平分库按订单ID哈希,分表按时间维度),读写分离(主库写,从库读,主从复制提升读性能)。主从复制保证数据一致性,分库分表处理百万级订单数据。
- 数据一致性:采用最终一致性,订单创建后异步扣减库存,库存服务消费时检查订单ID(幂等性),避免重复扣减;异常时订单服务回滚订单状态(如库存扣减失败,删除订单记录并更新缓存为“已取消”)。高可用通过集群部署(如Nginx多实例、Redis哨兵、Kafka集群),确保服务不中断。
3) 【对比与适用场景】
| 组件 | 定义 | 特性 | 使用场景 | 注意点 |
|---|
| Redis | 基于内存的键值存储,支持数据结构 | 低延迟、高并发读写,持久化(RDB/AOF) | 高频读(订单状态、商品信息)、缓存 | 需设置TTL,防数据不一致;需防缓存击穿(布隆过滤器)、雪崩(随机过期) |
| MySQL | 关系型数据库,事务支持 | 数据持久化、事务一致性、读写分离 | 写操作(订单创建、库存扣减)、主数据存储 | 分库分表提升大数据量处理能力;主从复制提升读性能 |
| Kafka | 分布式消息系统 | 高吞吐、持久化、可扩展、消费端幂等 | 大促期间高并发消息处理(订单状态变更) | 消费端需幂等性,监控队列积压;需设置重试机制(如指数退避) |
| Nginx | 反向代理、负载均衡、静态资源处理 | 高并发连接、反向代理、负载均衡 | 分发请求、处理静态资源、负载均衡 | 需配置负载均衡策略(如轮询、权重),防单点故障 |
4) 【示例】
订单创建流程(含库存扣减失败回滚):
- 前端请求:
POST /order/create,参数:userId=1, goodsId=1001, quantity=2。
- Nginx负载均衡将请求转发至订单服务。
- 订单服务检查用户余额(缓存中,若缓存无则从数据库读),若余额足够:
a. 发送消息到库存扣减队列(Kafka主题:order_stock_decrease),消息体:{orderId:12345, goodsId:1001, quantity:2}。
b. 订单服务在数据库主库执行事务:插入订单记录(订单表),事务提交后更新缓存(订单状态为“待支付”)。
- 库存服务消费消息:
a. 检查订单是否存在(幂等性,通过订单ID),若存在跳过。
b. 扣减库存(库存表),更新缓存(库存数量)。若扣减失败(如库存不足),库存服务发送失败消息到重试队列。
- 订单服务消费库存扣减结果:
a. 若成功,发送订单状态更新消息(Kafka主题:order_status_update),消息体:{orderId:12345, status:"待支付"}。
b. 若失败(库存不足),订单服务回滚订单状态(数据库删除订单记录,缓存更新为“已取消”)。
- 支付服务消费状态更新消息,处理支付。
5) 【面试口播版答案】
“面试官您好,针对百万级订单系统,我设计的架构是微服务+分布式组件。前端用Nginx负载均衡分发请求,后端拆分为订单、库存、支付等微服务。缓存用Redis缓存订单和库存数据,减少数据库压力。消息队列用Kafka异步处理订单状态变更,解耦服务。数据库用MySQL分库分表,读写分离提升性能。数据一致性通过最终一致性实现,订单创建后异步扣减库存,用幂等性避免重复操作;若库存扣减失败,订单服务会回滚订单状态(删除订单记录并更新缓存为‘已取消’),确保数据一致。高可用通过集群部署(如Nginx多实例、Redis哨兵、Kafka集群),以及K8s动态扩容,保障双十一期间低延迟和高吞吐。”
6) 【追问清单】
- 问:消息队列的延迟问题如何解决?
答:通过增加消费线程数(如从4个增加到8个)、调整Kafka分区数(16个增加到32个),设置消息重试机制(指数退避,如1秒、2秒),并监控队列积压(如使用Kafka监控工具)确保延迟在可接受范围内。
- 问:缓存预热的具体实现?
答:凌晨0点执行定时任务,预加载热门商品信息(前1000款)和常用优惠券(前50款)到Redis,减少大促期间缓存穿透。
- 问:库存扣减失败时订单回滚的流程?
答:订单服务监听库存扣减失败消息,触发事务删除订单记录并更新缓存为“已取消”状态,确保数据一致性。
- 问:数据库分库分表的具体策略?
答:订单表按订单ID哈希分库(如100个库),按时间维度分表(按年/月),读写分离主从复制。
7) 【常见坑/雷区】
- 未考虑库存扣减失败回滚,导致订单与库存数据不一致。
- 缓存未设置TTL,导致数据过期不一致。
- 消息队列未幂等性,导致重复扣减库存。
- 数据库单点故障,未做读写分离或主从复制。
- 未做负载均衡,单台服务器压力过大导致延迟。