1、服务如何实现灰度发布(面试+电商中台必背,极简满分版)
一、灰度发布是什么
灰度发布 = 让新版本服务只给一部分用户/流量使用 ,观察没问题再全量。
目的:降低发布风险、不影响全部用户、出问题快速回滚。
二、实现灰度的 4 种核心方案(背这4个就够)
1. 基于流量比例灰度(最简单)
- 按百分比切流量
- 比如 10% 流量进新版本,90% 进旧版本
- 适合:无状态服务、通用接口、大促前验证
2. 基于用户特征灰度(最常用)
- 按用户属性路由
- 用户ID、手机号、城市、设备、内部测试账号
- 电商常用:先给内部员工 → 老用户 → 全量
- 优点:精准、可定向验证
3. 基于请求参数/Header 灰度(最灵活)
- 请求头带标记:
gray: true/version: v2 - API网关/中间件识别 Header,自动路由到新版本
- 适合:API网关、中台服务、微服务统一入口
4. 基于机器/实例灰度(最稳定)
- 一部分服务器部署新版本,一部分旧版本
- 网关把流量打到对应机器组
- 适合:核心服务(订单、库存、支付)不允许出错
三、企业级标准灰度流程(背这个)
- 网关/配置中心定义规则(比例/用户/Header)
- 流量调度:符合规则 → 新版本,否则 → 旧版本
- 监控:日志、错误率、响应时间
- 验证没问题 → 逐步放大流量
- 出问题 → 一键切回旧版本(秒级回滚)
2、如何解决超卖问题 + 可直接背的代码实现(电商面试必考压轴题)
一、什么是超卖?
库存只有 5 件,并发下单时,最后卖出去 7 件 ,这就是超卖。
根本原因:并发下,读取库存 → 减库存 不是原子操作。
二、解决超卖的 3 种方案(从简单到企业级)
1. 数据库乐观锁(最简单、推荐)
原理 :
更新库存时,用 WHERE 库存 > 0 保证原子性。
只有库存足够时,才允许扣减。
SQL 核心(必背)
sql
UPDATE product SET stock = stock - 1
WHERE id = ? AND stock > 0;
判断返回的影响行数(affected_rows)
=1 扣减成功
=0 扣减失败
2. Redis 分布式锁(高并发首选)
原理 :
用 Redis 锁把"查库存 + 扣减"变成串行,同一时间只有一个请求能执行。
适合秒杀、高并发商品。
步骤
- 加锁(SETNX)
- 查询库存
- 扣减库存
- 释放锁
3. Redis 预减库存(速度最快)
把库存放 Redis,用 DECR 原子操作扣减。
低于 0 就回滚 + 拒绝下单。
三、企业级最常用方案:数据库乐观锁(代码实现)
Python 伪代码(可直接背)
python
def reduce_stock(product_id):
# 关键:原子更新 + 库存判断
sql = """
UPDATE product
SET stock = stock - 1
WHERE id = %s AND stock > 0
"""
# 执行SQL
affected_rows = db.execute(sql, product_id)
# 返回结果
return affected_rows > 0
使用
python
if reduce_stock(1001):
创建订单...
else:
返回"库存不足"
四、高并发方案:Redis 分布式锁(代码实现)
python
def create_order(product_id):
lock_key = f"lock:product:{product_id}"
# 1. 加锁(SETNX 原子操作)
lock_success = redis.set(lock_key, "1", ex=5, nx=True)
if not lock_success:
return "系统繁忙,请稍后再试"
try:
# 2. 查询库存
stock = redis.get(f"stock:{product_id}")
if int(stock) <= 0:
return "库存不足"
# 3. 扣减库存
redis.decr(f"stock:{product_id}")
# 4. 创建订单
create_order_db(...)
return "下单成功"
finally:
# 5. 释放锁
redis.delete(lock_key)
五、面试官最爱听的标准答案(背这段)
超卖的根本原因是并发下库存扣减不具备原子性 。
解决方案有三种:
- 数据库乐观锁 :通过
WHERE stock > 0原子更新,简单可靠。 - Redis分布式锁:高并发下串行化扣减,适合秒杀场景。
- Redis预扣库存:利用DECR原子操作,速度最快。
企业级最佳实践 :
Redis预扣库存 + 数据库最终一致性保证,既保证性能又保证数据安全。
3、API网关的实现(电商/中台面试必考大题,直接背这套就满分)
一、API网关是什么(一句话)
API网关是微服务的统一入口 ,所有客户端(前端/APP/第三方)请求都先经过网关,再路由到对应的后端服务。
作用:统一收口、统一治理、解耦业务。
二、API网关必须实现的 8 大核心功能(背这个)
- 请求路由
根据路径/服务名转发到对应微服务(最核心) - 统一鉴权
登录校验、Token解析、权限判断 - 限流、熔断、降级
防止流量打崩服务(电商大促必备) - 日志、监控、链路追踪
统一记录请求日志、耗时、异常 - 请求响应统一处理
参数校验、返回格式统一、跨域、脱敏 - 灰度发布
根据Header/用户/比例路由到新版本 - 协议转换
HTTP → gRPC、REST → GraphQL - 黑白名单、限流防刷
三、企业级API网关实现方案(3种,面试必说)
1. 自研网关(中小型公司/中台定制)
- Nginx + Lua / Python/Node.js 开发
- 轻量、灵活、适合业务定制(权限、配置、规则引擎)
2. 开源网关(主流)
- Spring Cloud Gateway(Java生态)
- Kong Gateway
- APISIX(国产、高性能、云原生)
3. 云厂商网关
- 阿里云API网关、腾讯云API网关
四、自研API网关 标准实现流程(面试满分流程)
自研网关流程:
1. 请求入口
接收所有前端请求 GET /api/order/create
2. 全局中间件执行(按顺序)
- 黑白名单过滤
- 限流(令牌桶/漏桶)
- 跨域处理
- Token鉴权、解析用户信息
3. 请求路由匹配
根据路径规则:
/api/product/** → 商品服务
/api/order/** → 订单服务
4. 转发请求到微服务
- 负载均衡(轮询/权重)
- 协议转换
- 请求头透传(userId、gray标记)
5. 响应处理
- 统一包装返回格式
{code,data,msg} - 异常捕获、错误码统一
- 日志记录、耗时上报
6. 返回给前端
五、网关实现关键技术(面试加分)
- 路由匹配:前缀匹配、正则匹配
- 限流算法:令牌桶、漏桶
- 鉴权:JWT、OAuth2.0
- 负载均衡:RoundRobin、Weight、IPHash
- 熔断降级:Sentinel、Hystrix
- 动态配置:配置中心热更新路由/规则
六、最简单 Python 伪代码实现(理解就满分)
python
# API网关核心流程
def gateway_middleware(request):
# 1. 限流
if rate_limit_over(request):
return 429 "请求频繁"
# 2. 鉴权
token = request.headers.get("token")
if not verify_token(token):
return 401 "未登录"
# 3. 路由转发
if request.path.startswith("/api/order"):
return forward_to_order_service(request)
if request.path.startswith("/api/product"):
return forward_to_product_service(request)
# 4. 统一返回格式
return {
"code": 200,
"data": response_data,
"msg": "success"
}
七、面试万能满分回答(直接背)
API网关是微服务统一入口 ,实现统一路由、鉴权、限流、监控、灰度、日志等能力。
实现方式分为自研、开源网关、云网关 。
核心流程是:请求→限流→鉴权→路由→转发→响应处理 。
在电商中台里,网关能统一管控所有业务接口,提升系统安全性、稳定性、可扩展性。
4、服务熔断、降级、限流
一、一句话区分三者(面试官最爱)
- 限流 :不让多余请求进来(控制流量)
- 熔断 :下游挂了,我立刻停止调用(保护自己)
- 降级 :顶不住了,舍弃非核心功能(保主线)
二、限流(Rate Limit)
是什么
控制接口最大访问QPS,超过直接拒绝,防止把服务打崩。
常见场景
- 商品详情、下单接口、秒杀
- 网关统一限流
实现方案(背3个)
- 令牌桶算法(最常用,允许突发流量)
- 漏桶算法(匀速限流)
- 滑动窗口(精确控制)
实现位置
- API网关层(统一限流,推荐)
- 服务单体接口
代码思路(Python伪代码)
python
def rate_limit(user_id):
key = f"limit:{user_id}"
count = redis.incr(key)
if count == 1:
redis.expire(key, 1) # 1秒窗口
return count <= 100 # 每秒最多100次
三、熔断(Circuit Breaker)
是什么
调用下游服务错误率太高 → 直接断开调用 → 快速失败
避免一个下游故障拖垮整个调用链。
状态(必背)
- 关闭(Closed):正常调用
- 开启(Open):错误率达标,熔断,不调用
- 半开(Half-Open):放少量请求试探,恢复则关闭熔断
触发条件
- 错误率 > 50%
- 超时率过高
- 异常太多
作用
防止级联故障,雪崩效应
四、降级(Degradation)
是什么
压力大/下游故障 → 舍弃非核心功能 → 保证核心流程可用
降级场景(电商必背)
- 关闭商品推荐
- 关闭营销活动信息
- 关闭评论、收藏展示
- 关闭日志、非核心统计
- 返回兜底数据、缓存数据
原则
丢车保帅,保订单、保库存、保支付核心链路!
五、三者执行顺序(面试必考)
- 最先限流(不让多余请求进来)
- 中间熔断(下游不行就停)
- 最后降级(非核心功能砍掉)
六、企业级通用实现方案
1. 网关层统一处理
- 限流:IP限流、用户限流、接口限流
- 熔断:调用下游服务异常自动熔断
- 降级:返回默认数据、静态数据
2. 组件实现
- Sentinel(阿里,主流)
- Resilience4j
- Hystrix(旧)
3. 配置化
通过配置中心动态开关,无需重启服务。
七、面试万能满分回答(直接背这段)
限流 是控制请求QPS,防止流量过大打垮服务,常用令牌桶实现。
熔断 是下游服务错误率过高,自动停止调用,快速失败,防止服务雪崩。
降级 是系统压力大时,舍弃非核心功能,保证核心订单、支付、库存流程可用。
执行顺序:限流 → 熔断 → 降级,一般在API网关统一实现,配合配置中心动态生效。
八、电商场景总结(加分)
大促高并发时:
- 限流防止流量洪峰
- 熔断防止下游服务拖垮主线
- 降级 关闭商品推荐、营销信息,保订单、保库存、保支付
5、如何保证接口幂等性(防重复下单/重复退款)+ 代码实现
一、什么是接口幂等性?
一次请求 和 多次请求,结果完全一样,不会重复执行。
- 重复下单 → 只生成 1 个订单
- 重复退款 → 只退 1 次钱
- 重复支付 → 只扣 1 次款
核心:防重复操作!
二、幂等性 4 种实现方案(背这 4 个)
1. 唯一索引 / 唯一约束(最简单)
数据库建唯一索引,重复插入直接报错。
适用:订单号、退款单号。
2. 分布式锁(Redis)(最常用)
加锁 → 执行 → 释放锁。
重复请求过来,拿不到锁,直接返回"已处理"。
3. 请求唯一标识 Token 机制(电商下单标准方案)
前端先获取 token → 下单时带上 token → 后端验证并删除 token。
这是企业级下单、支付标准方案。
4. 状态机幂等(订单/退款必用)
根据状态判断:
- 已支付 → 不能再支付
- 已退款 → 不能再退款
- 已取消 → 不能再取消
三、企业级标准方案:Token 机制(防重复下单)
流程(面试必说)
- 进入下单页,前端请求后端获取 order_token
- 后端生成唯一 ID,存入 Redis(过期时间 10 分钟)
- 前端下单时带上
order_token - 后端原子删除(DEL) token
- 删除成功 → 允许下单
- 删除失败 → 重复请求,直接返回
为什么用 DEL?
因为 DEL 是原子操作,高并发下只会成功一次!
四、代码实现(Python 可直接背)
1)获取 Token
python
# 前端进入下单页时调用
def get_order_token():
token = str(uuid.uuid4())
# 存入Redis,10分钟过期
redis.setex(f"order:token:{token}", 600, "1")
return token
2)下单接口(幂等核心)
python
def create_order(token, product_id, user_id):
# ==================== 幂等核心 ====================
# 原子删除 token,成功=第一次,失败=重复请求
success = redis.delete(f"order:token:{token}")
if not success:
return "重复下单,请不要重复提交"
# =================================================
# 正常下单逻辑
stock_ok = reduce_stock(product_id)
if not stock_ok:
return "库存不足"
order_id = create_order_db(user_id, product_id)
return {"order_id": order_id, "msg": "下单成功"}
五、防重复退款:分布式锁实现
原理
同一个退款单号,同一时间只能处理一次。
python
def refund(refund_no, order_id, amount):
lock_key = f"lock:refund:{refund_no}"
# 加锁(原子操作,5秒过期)
lock = redis.set(lock_key, "1", ex=5, nx=True)
if not lock:
return "重复退款请求"
try:
# 查询订单状态
order = get_order(order_id)
if order.status != "PAID":
return "订单不可退款"
# 执行退款
do_refund(order_id, amount)
return "退款成功"
finally:
# 释放锁
redis.delete(lock_key)
六、数据库唯一索引方案(兜底保障)
sql
-- 订单表,order_sn 唯一索引,防止重复插入
ALTER TABLE `order` ADD UNIQUE INDEX `uk_order_sn` (`order_sn`);
代码捕获唯一索引异常:
python
try:
db.insert(order)
except DuplicateKeyError:
return "订单已存在"
七、面试万能满分回答(直接背)
接口幂等性是一次和多次请求结果一致,防止重复下单、重复退款。
常用方案有四种:
- Token 机制:前端获取token,后端原子删除保证只执行一次(下单标准方案)
- 分布式锁:同一请求同时只有一个能执行
- 唯一索引:数据库层面防重复
- 状态机判断:根据状态拒绝重复操作
企业级下单流程标准方案:Token + Redis 原子删除 + 数据库唯一索引。
6、订单完整状态机实现
一、先背:订单标准 6 大状态(必背)
- 待付款(UNPAID)
- 待发货(PAID / PENDING_SHIP)
- 待收货(SHIPPED)
- 已完成(COMPLETED)
- 已取消(CANCELLED)
- 售后中(AFTER_SALE)
二、完整状态流转图(面试口述满分)
标准流转(背这个流程)
- 创建订单 → 待付款
- 支付成功 → 待发货
- 商家发货 → 待收货
- 用户确认收货 → 已完成
- 超时未支付 / 主动取消 → 已取消
- 已完成/待收货 → 申请售后 → 售后中
三、状态机核心设计原则(面试加分)
- 状态不可乱跳
必须按流程走,不能从"待付款"直接跳到"已完成"。 - 事件驱动
支付、发货、收货、取消都是事件,触发状态变更。 - 幂等安全
重复事件不重复执行。 - 状态判断前置
操作前必须校验当前状态是否允许。
四、代码实现(Python 可直接背)
1. 定义状态常量
python
# 订单状态
STATUS_UNPAID = 0 # 待付款
STATUS_PENDING_SHIP = 1 # 待发货
STATUS_SHIPPED = 2 # 待收货
STATUS_COMPLETED = 3 # 已完成
STATUS_CANCELLED = 4 # 已取消
STATUS_AFTER_SALE = 5 # 售后中
2. 定义状态机允许流转规则(核心!)
python
# 订单状态机:key=当前状态,value=允许跳转的目标状态
ORDER_STATE_MACHINE = {
STATUS_UNPAID: [STATUS_PENDING_SHIP, STATUS_CANCELLED],
STATUS_PENDING_SHIP: [STATUS_SHIPPED, STATUS_CANCELLED], # 未发货可取消
STATUS_SHIPPED: [STATUS_COMPLETED, STATUS_AFTER_SALE],
STATUS_COMPLETED: [STATUS_AFTER_SALE], # 已完成可售后
STATUS_CANCELLED: [], # 终态
STATUS_AFTER_SALE: [] # 终态/流转到退款成功
}
3. 状态变更校验方法(通用核心)
python
def change_order_status(order, target_status):
"""
订单状态变更核心方法
:param order: 订单对象
:param target_status: 目标状态
"""
current_status = order.status
# 1. 判断是否允许跳转(状态机核心)
if target_status not in ORDER_STATE_MACHINE[current_status]:
raise Exception(f"状态不允许跳转:{current_status} → {target_status}")
# 2. 执行更新(数据库乐观锁更新,保证并发安全)
with db.transaction():
# 乐观锁:只有状态没变才更新
rows = Order.update(
status=target_status
).where(
Order.id == order.id,
Order.status == current_status # 关键:状态没变才允许更新
).execute()
if rows == 0:
raise Exception("订单状态已变更,请重试")
return True
4. 业务事件触发(支付、发货、收货、取消)
python
# 1. 支付成功
def order_pay_success(order):
return change_order_status(order, STATUS_PENDING_SHIP)
# 2. 发货
def order_ship(order):
return change_order_status(order, STATUS_SHIPPED)
# 3. 确认收货
def order_confirm_receive(order):
return change_order_status(order, STATUS_COMPLETED)
# 4. 取消订单
def order_cancel(order):
return change_order_status(order, STATUS_CANCELLED)
# 5. 申请售后
def order_apply_after_sale(order):
return change_order_status(order, STATUS_AFTER_SALE)
五、面试满分回答(直接背这段)
订单采用状态机模式 设计,标准状态分为:
待付款、待发货、待收货、已完成、已取消、售后中。
实现思路:
- 定义状态流转规则,只允许合法状态跳转,防止乱跳;
- 所有操作(支付、发货、收货、取消)都通过事件触发状态变更;
- 更新时使用数据库乐观锁,保证并发安全与幂等性;
- 结合超时自动取消任务,待付款订单超时自动变为已取消。
这套设计能保证订单状态流转严谨、业务安全、高并发稳定。
六、面试官必追问:订单超时未支付怎么实现?
标准回答:
使用 Redis 过期监听 / 延迟队列(RabbitMQ delayed queue)
创建订单时发送一条15分钟或30分钟后执行 的延迟消息,
消息消费时检查订单状态:
- 如果还是待付款 → 自动取消 + 库存回滚。
7、订单超时自动取消
一、需求是什么?
订单创建后 30分钟未支付,必须:
- 自动取消订单
- 自动回滚库存
- 释放优惠券/积分
二、实现方案(3种,面试必说)
方案1:定时任务轮询(最简单,新手项目)
- 每隔几分钟扫一遍订单表
where status=待付款 and create_time < now()-30min- 优点:简单
- 缺点:有延迟、扫库压力大
方案2:Redis 过期键监听(中小型项目常用)
- 创建订单时,往 Redis 存一个 key,30分钟过期
- 监听过期事件,触发取消订单
- 优点:无轮询、无DB压力
- 缺点:Redis可能丢消息,需要定时任务兜底
方案3:延迟队列(RabbitMQ/RocketMQ)企业级标准方案(最推荐!)
- 订单创建 → 发送一条 延迟30分钟 的消息
- 时间到 → 消费消息 → 取消订单
- 优点:精准、可靠、高并发、无压力
- 电商/生产环境 100%用这个
三、面试满分回答(直接背这段)
订单超时取消首选延迟队列 (RabbitMQ死信队列/RocketMQ延迟队列)。
流程:
- 创建待付款订单时,发送一条延迟30分钟的消息。
- 消息到期后,消费者检查订单状态:
- 仍待付款 → 执行取消订单 + 库存回补。
- 已支付 → 直接忽略。
- 配合定时任务兜底,保证极端情况下数据一致。
优点:精准、无数据库压力、高可用、可靠。
四、Redis 过期监听实现(Python代码,易懂)
1. 下单时存Redis
python
def create_order(user_id, product_id):
# 1. 创建待付款订单
order_id = create_order_db(user_id, product_id)
# 2. 存入Redis,30分钟过期
redis.setex(f"order:timeout:{order_id}", 60*30, "1")
return order_id
2. 启动过期监听
python
def redis_timeout_listener():
pubsub = redis.pubsub()
# 订阅过期事件
pubsub.psubscribe('__keyevent@0__:expired')
for msg in pubsub.listen():
key = msg['data']
if not key or not key.startswith('order:timeout:'):
continue
# 解析订单ID
order_id = key.split(':')[-1]
# 执行超时取消
auto_cancel_order(order_id)
# 后台启动线程运行
threading.Thread(target=redis_timeout_listener, daemon=True).start()
3. 超时取消逻辑(核心)
python
def auto_cancel_order(order_id):
# 1. 查询订单
order = Order.get_by_id(order_id)
if not order or order.status != UNPAID:
return # 已支付/已取消,直接跳过
# 2. 事务:取消订单 + 回补库存
with db.atomic():
# 取消订单
Order.update(status=CANCELLED).where(
Order.id==order_id, Order.status==UNPAID
).execute()
# 库存回补
Stock.incr(1).where(Product.id==order.product_id).execute()
五、一句话终极背诵版
订单超时取消用延迟队列 最可靠,
创建订单时发送延迟消息 ,
到期检查状态,
未支付则取消+回库 ,
并使用定时任务兜底保证安全。
六、面试官最爱追问(必看)
问:如果延迟队列消息丢失了怎么办?
答:
加一个兜底定时任务,每分钟扫描一次超时未支付订单,确保数据绝对一致。
问:为什么不用定时任务一直轮询?
答:
轮询会频繁扫库,大数据量下数据库压力大,且延迟高。
8、下单扣库存 如何保证数据一致性 + 代码实现
一、核心问题
下单时必须保证:
订单创建成功 ↔ 库存扣减成功
要么都成功,要么都失败,绝对不能出现:订单创建了,库存没扣;或者库存扣了,订单没创建。
这就是 分布式事务 / 数据最终一致性 问题。
二、面试标准答案(先说结论)
下单扣库存 保证一致性的方案:
企业级标准方案(最常用、最稳)
TCC 模式 / 最终一致性(可靠消息)
流程:
- 预扣库存(库存锁定,不真正扣减)
- 创建订单
- 确认扣减 / 取消回滚
高并发最佳实践(电商通用)
Redis 预扣库存 + 数据库最终一致性 + 定时任务对账
三、完整实现流程(背这个)
标准一致性流程
- 校验商品、价格、用户权限
- 库存预扣(Redis 原子操作 DECR)
- 创建订单(数据库事务)
- 正式扣减数据库库存
- 任意一步失败 → 回滚库存 + 取消订单
四、代码实现(可直接背)
1. 下单核心逻辑(Python伪代码)
python
def create_order(user_id, product_id, num):
# ==================== 1. 基础校验 ====================
product = get_product(product_id)
if not product:
return "商品不存在"
# ==================== 2. Redis 预扣库存(原子操作) ====================
stock_key = f"stock:{product_id}"
remain_stock = redis.decrby(stock_key, num) # 原子扣减
# 库存不足,回滚Redis
if remain_stock < 0:
redis.incrby(stock_key, num)
return "库存不足"
try:
# ==================== 3. 数据库事务:创建订单 + 扣DB库存 ====================
with db.transaction(): # 数据库本地事务,保证原子性
# ① 创建订单
order_id = create_order_db(user_id, product_id, num)
# ② 扣数据库库存(乐观锁保证安全)
rows = Product.update(
stock=stock - num
).where(
Product.id == product_id,
Product.stock >= num # 数据库层校验
).execute()
if rows == 0:
raise Exception("数据库库存扣减失败")
# 成功
return {"order_id": order_id, "msg": "下单成功"}
except Exception as e:
# ==================== 4. 异常:全部回滚 ====================
redis.incrby(stock_key, num) # 回滚Redis库存
return "下单失败,已回滚库存"
五、高并发场景 最终一致性方案(面试加分)
流程(电商大厂标准)
- Redis 预扣库存
- 发送可靠消息(MQ)
- 消费消息:创建订单 + 扣DB库存
- 失败则回补库存 + 订单取消
- 定时任务对账(兜底)
优点
- 高并发、无锁、高性能
- 最终一致性 100% 保证数据安全
六、面试满分回答(直接背这段)
下单扣库存保证数据一致性,核心是确保订单创建和库存扣减要么全部成功,要么全部失败。
实现方案:
- Redis 预扣库存(原子操作,保证高并发不超卖)
- 数据库本地事务 ,保证创建订单 + 扣减数据库库存原子性
- 任何环节异常,自动回滚 Redis 库存
- 高并发下使用 可靠消息队列 + 最终一致性 保证强一致
- 配合 定时任务对账 做兜底
这套方案既保证高并发性能 ,又保证数据绝对一致,是电商下单的标准实践。
9、电商大促高并发场景:如何保障系统不崩溃?
一、一句话核心思路(先背这句)
前端限流 + 网关层限流 + 服务异步化 + 缓存扛读 + 数据库分治 + 服务保护 + 监控兜底
一句话总结:把流量挡住、把请求异步、把压力分散、把核心保住!
二、完整高并发保障方案(7大层防御体系,面试必说)
1. 前端/客户端层(第一道防线)
- 按钮防重复点击(节流、点击后禁用)
- 接口防抖,防止重复提交
- 静态资源CDN(图片、JS、CSS全走CDN,不占服务器)
- 前端缓存(商品列表、详情页本地缓存)
作用:挡住 30% 无效流量!
2. API网关层(第二道防线,最重要)
- 接口限流:IP限流、用户限流、接口限流(令牌桶)
- 黑名单、防刷
- 熔断、降级:下游挂了直接切断
- 灰度发布:小流量验证,不一次性全量
- 路由拆分:秒杀、商品、订单分开入口
作用:挡住洪峰流量,不让请求冲进服务!
3. 缓存层(第三道防线,扛住90%读请求)
- 商品详情全量缓存(Redis)
- 热点数据提前预热
- 库存放Redis(高性能预扣)
- 本地缓存Caffeine(二级缓存,减轻Redis压力)
- 防止缓存穿透/击穿/雪崩(之前背过的方案)
作用:读请求 90% 走缓存,不查数据库!
4. 服务层(第四道防线:异步 + 扩容)
① 服务无状态 + 水平扩容
- 订单、商品、库存服务集群部署
- 大促前手动扩容 + 自动弹性扩缩容
② 同步转异步(核心!削峰填谷)
下单流程拆分成同步核心 + 异步非核心
- 同步:扣库存、创建订单
- 异步:通知、日志、统计、积分、优惠券发放
用 MQ(RabbitMQ/RocketMQ/Kafka)消峰
③ 服务熔断、降级
- 关闭推荐、营销、评论等非核心接口
- 只保:下单、支付、库存、商品核心链路
5. 消息队列 MQ(第五道防线:削峰神器)
- 下单请求 → MQ → 消费端慢慢处理
- 流量再大,MQ 顶着,服务不会被打崩
- 订单超时、状态同步全异步化
作用:把瞬间流量变成匀速流量!
6. 数据库层(第六道防线:最后堡垒)
- 读写分离:读从库,写主库
- 分库分表:订单表、用户表按 hash 拆分
- 热点行隔离:秒杀商品单独库
- 禁大事务、禁慢查询
- 索引优化,所有查询必须走索引
- 数据库连接池限流
7. 监控 + 兜底(第七道防线)
- 实时监控:CPU、内存、QPS、错误率
- 告警:异常第一时间通知
- 压测:大促前全链路压测
- 兜底方案 :
- 限流兜底页面
- 降级静态页
- 数据库熔断保护
三、大促高并发 标准执行流程(面试口述满分)
- 流量进不来:前端 + 网关限流拦截
- 请求不落地:90%读请求走Redis缓存
- 流量不暴增:MQ异步削峰
- 服务不卡死:服务扩容 + 熔断降级
- 数据库不崩:读写分离 + 分库分表 + 禁慢查询
- 出问题可回滚:监控告警 + 快速降级
四、面试官最爱听的 满分回答(直接背这段)
在电商大促高并发场景下,我会从七层架构保障系统稳定:
- 前端防重、防抖、CDN加速,减少无效请求;
- API网关统一限流、熔断、降级,控制流量入口;
- 多级缓存(本地缓存+Redis)承担90%读流量,防止穿透、击穿、雪崩;
- 核心服务水平扩容,无状态设计可快速弹性伸缩;
- 同步流程异步化,使用消息队列削峰填谷,避免流量压垮服务;
- 服务降级保护 ,关闭营销、推荐等非核心功能,保订单、保库存、保支付;
- 数据库读写分离、分库分表、索引优化,避免数据库被打崩;
- 全链路监控+告警+压测,提前发现问题,出现故障快速回滚。
整套方案从入口、缓存、服务、消息、数据库全方位保护,确保大促高并发下系统不崩溃、不宕机、可用率达标。
10、API网关如果挂了怎么处理
一、核心结论
API网关是流量唯一入口 ,单点故障影响全局,解决方案核心思路:杜绝单点、故障转移、降级兜底、快速恢复。
二、完整解决方案(分维度,面试按顺序作答)
1. 事前架构:从根源避免网关单点故障(最重要)
(1)集群化部署 + 负载均衡
- 网关多实例集群 ,不部署单节点;前端/客户端请求经过 SLB/nginx 负载均衡 分发到多个网关节点。
- 一台网关宕机,负载均衡自动剔除异常节点,流量切到正常实例,业务无感知。
- 实践:生产环境至少部署 2~3个网关节点,大促前继续扩容。
(2)多可用区部署(云环境标配)
不同网关节点部署在不同机房/可用区,规避单机房断电、网络故障,提升容灾能力。
(3)服务健康检查 & 自动摘除
- 负载均衡、服务注册中心(Nacos/Eureka/Consul)定时探测网关健康状态。
- 节点异常、端口不通、接口报错率过高,自动下线该节点,不再分配流量。
(4)网关本身无状态
网关不存储会话、业务数据,配置统一放配置中心,任意节点可随时上下线、扩容缩容。
2. 事中应急:网关整体不可用(集群全挂/大面积故障)
分两层兜底策略,按优先级执行:
方案1:静态页面兜底(用户侧体验兜底)
网关彻底瘫痪后,前端切静态降级页面,提示"系统繁忙,请稍后重试",拒绝新请求,保护后端服务。
方案2:备用入口 / 路由降级(核心业务抢救)
方式A:备用网关集群
提前搭建备用网关集群,主集群故障时,负载均衡一键切换流量至备用集群。
方式B:直连后端(极端应急,仅核心链路)
临时绕过网关,Nginx直接将下单、支付、库存等核心接口路由到后端微服务。
注意:该方式会丢失网关的鉴权、限流、日志等能力,仅应急使用,事后立刻恢复。
方案3:流量管控 + 主动限流
故障期间全局限流、关闭非核心入口,只保留支付、订单查询等刚需接口,减少压力。
3. 快速恢复:故障定位与重启
- 监控告警:网关CPU、内存、连接数、错误率、端口状态实时监控,故障秒级告警。
- 快速重启/重建 :基于容器(Docker/K8s)部署,异常节点支持容器自愈、自动重启;K8s可根据副本数自动拉起新Pod。
- 灰度恢复:恢复节点后先切小流量验证,再逐步全量切回,防止故障反复。
4. 流量与配置防护(避免重复宕机)
- 故障恢复初期降低限流阈值,缓慢放量,防止瞬间流量再次压垮网关。
- 临时关闭非核心插件(全量日志、链路追踪、复杂规则校验),简化网关逻辑,提升吞吐量。
三、常见故障根因 & 对应优化(面试加分项)
- 流量洪峰打垮网关
优化:前置限流、分接口配置不同限流规则、网关集群提前扩容。 - 插件逻辑耗时过高(如复杂鉴权、数据脱敏)
优化:异步化非核心插件、拆分复杂逻辑、优化插件执行顺序。 - 连接数打满、端口耗尽
优化:调整连接池参数、设置连接超时、限制单IP连接数。 - 依赖组件故障(Redis/配置中心)
优化:网关依赖组件也做集群,增加本地缓存兜底配置。
四、面试标准口述答案(直接背诵)
标准版(通用回答)
API网关作为流量入口,首先杜绝单点问题 :生产环境采用多实例集群+负载均衡部署,多可用区容灾,配合健康检查自动剔除异常节点,单节点故障不会影响整体。
如果整个网关集群宕机,执行多层兜底:
- 前端展示静态降级页面,拦截大部分新流量;
- 启用备用网关集群,或临时将核心接口绕过网关直连后端服务应急;
- 依托容器平台实现节点自动重启、快速重建;
- 恢复后逐步放量,同时排查根因,关闭非核心插件避免二次故障。
日常通过实时监控告警提前发现隐患,大促前完成集群扩容与全链路压测,从事前、事中、事后全流程保障网关高可用。
精简版(简短作答)
我们通过网关集群+负载均衡消除单点,单节点故障自动转移流量。若集群整体故障,先做静态页面降级,再切换备用集群或临时直连核心服务;依靠容器自愈快速恢复节点,恢复后控量逐步切回,同时结合监控提前规避风险。
11、布隆过滤器
一、一句话通俗解释
布隆过滤器 = 一个超级省空间的"存在性判断工具"
- 用来快速判断:一个数据一定不存在,还是可能存在
- 作用:彻底解决缓存穿透问题(查不存在的数据,直接拦截,不查数据库)
二、核心原理(超简单)
- 用一个二进制数组(只存 0/1,极省空间)
- 用多个哈希函数,把数据算出多个位置
- 把这些位置全部设为 1
- 判断时:
- 只要有一个位置是 0 → 一定不存在
- 全部是 1 → 可能存在
三、两大特点(必背)
- 有就一定有?不一定(有误判率)
- 没有就一定没有!绝对准确
优点 :速度极快、占用空间极小
缺点:不能删除数据、有极小误判率
四、面试标准答案(直接背)
布隆过滤器是一种空间高效的概率型数据结构 ,用于判断一个元素是否存在于集合中。
它的特点是:
- 空间占用极小、查询速度极快
- 不存在的数据能 100% 判断出来
- 存在的数据可能存在误判
主要用途 :
解决缓存穿透,拦截不存在的请求,保护数据库。
五、一句话终极背诵版
布隆过滤器:判断数据一定不存在,用来防缓存穿透,快、省空间、有小误判。
12、漏桶 & 令牌桶算法
二者都是流量限流算法,核心用来控制接口QPS、抵挡突发流量,网关/接口限流场景高频使用。
一、漏桶算法(Leaky Bucket)
原理
想象一个固定容量的水桶,请求像水一样不断流入 ,水桶以固定速率匀速漏水(处理请求)。
- 桶未满:请求正常进入、被匀速处理
- 桶已满:新请求直接丢弃/拒绝
特点
- 强制匀速处理流量,无论入流多猛,出流速度恒定
- 无法应对突发流量,瞬间高并发会直接被拦截
- 适用场景:接口必须平稳输出、不允许突刺(内部后台接口、数据同步接口)
一句话总结
进水不限速,出水匀速,削突发流量,强控处理频率。
二、令牌桶算法(Token Bucket,电商/网关主流)
原理
系统以固定速率 往桶里放入令牌,每个请求必须拿到1个令牌才能被处理;桶有最大容量,令牌满了就不再新增。
- 有令牌:请求正常放行
- 无令牌:请求限流/排队/拒绝
特点
- 允许短暂突发流量:桶内积攒的令牌可一次性消耗,应对秒杀、大促瞬时洪峰
- 整体平均速率可控,同时兼容突发请求
- 工业界首选:API网关、下单、商品列表等前端高并发接口基本都用它
一句话总结
按速率生成令牌,拿牌才放行,平均限流+支持突发流量。
三、核心对比(面试必背)
| 算法 | 流量特征 | 能否抗突发 | 典型使用场景 |
|---|---|---|---|
| 漏桶 | 输出匀速 | 不支持 | 后台任务、同步接口 |
| 令牌桶 | 平均限速,允许突发 | 支持 | API网关、秒杀、电商前端接口 |
四、Python 简易伪代码(理解即可)
1. 漏桶简易实现
python
import time
class LeakyBucket:
def __init__(self, capacity, leak_rate):
self.capacity = capacity # 桶最大容量
self.leak_rate = leak_rate # 每秒漏水数
self.water = 0 # 当前水量
self.last_time = time.time()
def allow(self):
# 先计算漏出的水量
now = time.time()
delta = now - self.last_time
self.water = max(0, self.water - delta * self.leak_rate)
self.last_time = now
if self.water < self.capacity:
self.water += 1
return True
return False
2. 令牌桶简易实现
python
import time
class TokenBucket:
def __init__(self, capacity, token_rate):
self.capacity = capacity # 令牌桶最大容量
self.token_rate = token_rate# 每秒生成令牌数
self.tokens = capacity # 当前令牌数
self.last_time = time.time()
def allow(self):
# 补充令牌
now = time.time()
delta = now - self.last_time
self.tokens = min(self.capacity, self.tokens + delta * self.token_rate)
self.last_time = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False
13、redis.incr(key) redis.expire(key, 1) redis.set(lock_key, "1", ex=5, nx=True) redis.decrby(stock_key, num)
1. redis.incr(key)
作用
原子自增 +1
- 不存在自动创建,值为 1
- 线程安全、原子操作
场景
接口限流、统计次数、计数器
python
count = redis.incr("user:1:click")
2. redis.expire(key, 1)
作用
给 key 设置过期时间(秒)
场景
配合 incr 做每秒限流:
python
redis.incr(key)
redis.expire(key, 1) # 1秒后自动过期
3. redis.set(lock_key, "1", ex=5, nx=True)
⭐ 最最重要!分布式锁!
作用
原子加锁(官方标准写法)
ex=5:5秒过期(防死锁)nx=True:只有不存在才设置成功- nx=True:只有 key 不存在才能设置成功(加锁、防重复)
- nx=False:不管 key 存不存在,都直接覆盖设置(普通赋值)
效果
同一时间只有一个请求能加锁成功
场景
秒杀、重复下单、重复退款、分布式锁
python
lock_success = redis.set("lock:product:1001", "1", ex=5, nx=True)
if not lock_success:
return "系统繁忙"
4. redis.decrby(stock_key, num)
作用
原子减指定数量
- 原子性!高并发安全
- 不会超卖
场景
秒杀扣库存、预扣库存
python
remaining_stock = redis.decrby("stock:1001", 1)
if remaining_stock < 0:
# 库存不足,回滚
redis.incrby("stock:1001", 1)
14、什么是 TCC 模式?
一、一句话通俗解释
TCC 是一种分布式事务解决方案,保证跨多个服务的操作:要么全部成功,要么全部失败。
全称:
Try → Confirm → Cancel
核心作用
解决:
- 订单创建了,库存没扣
- 库存扣了,订单没创建
这类分布式数据不一致问题
二、TCC 三个阶段(必须背)
1. Try(预留/冻结资源)
- 尝试执行业务
- 冻结/预占资源(不是真正扣减)
- 例:预扣库存、冻结优惠券
2. Confirm(确认执行)
- Try 全部成功 → 执行真正的扣减/提交
- 例:真正扣库存、真正创建订单
3. Cancel(取消/回滚)
- 任何一个 Try 失败 → 全部回滚
- 例:释放库存、释放优惠券
三、举个电商下单例子(秒懂)
下单流程:
- Try
- 库存服务:预扣库存(冻结)
- 订单服务:预创建订单
- 全部成功 → Confirm
- 库存:真正扣减
- 订单:真正提交
- 任意失败 → Cancel
- 库存:回滚冻结
- 订单:取消预创建
最终:要么都成功,要么都回滚!
四、TCC 特点(面试必背)
- 柔性事务(最终一致性)
- 业务侵入性强(每个服务要写 3 个接口)
- 性能极高(无锁、高并发、适合秒杀)
- 电商/金融/支付场景主流方案