项目面试指南
一、项目介绍
1.1 STAR 法则
要素 | 说明 | 示例 |
Situation | 项目背景 | 公司电商平台日活 100 万 |
Task | 你的任务 | 负责订单系统重构 |
Action | 采取的行动 | 引入分库分表、消息队列 |
Result | 取得的成果 | QPS 提升 10 倍,延迟降低 50% |
1.2 项目介绍模板
1. 项目背景(1-2句)
- 业务场景、用户规模
2. 技术架构(重点)
- 整体架构图
- 核心技术栈
3. 你的职责
- 负责的模块
- 解决的核心问题
4. 技术亮点
- 性能优化
- 架构设计
5. 项目成果
- 量化指标1.3 架构图讲解技巧
讲解顺序:
1. 整体概览:先介绍系统整体架构
2. 分层说明:从上到下或从左到右
3. 核心链路:重点讲解核心业务流程
4. 技术亮点:突出你负责的部分
示例讲解:
这是我们订单系统的整体架构:
1. 接入层:Nginx 做负载均衡,网关负责鉴权和限流
2. 服务层:采用微服务架构,订单、库存、支付独立部署
3. 中间件:Redis 做缓存,Kafka 做异步解耦
4. 数据层:MySQL 分库分表,ES 做订单搜索
我主要负责订单服务,核心解决了高并发下的库存超卖问题...1.4 项目亮点/创新点
常见亮点类型:
| 类型 | 示例 |
|——|——|
| 性能优化 | 接口延迟从 500ms 降到 50ms |
| 架构改进 | 单体拆分微服务,支持独立扩展 |
| 技术攻坚 | 解决分布式事务一致性问题 |
| 工具建设 | 开发自动化测试框架 |
| 成本优化 | 服务器成本降低 30% |
1.5 收获与反思
回答框架:
技术收获:
- 深入理解了 XXX 技术原理
- 掌握了 XXX 问题的解决方案
业务收获:
- 理解了 XXX 业务场景
- 学会了如何平衡技术和业务
反思改进:
- 如果重新做,会在 XXX 方面做得更好
- 发现了 XXX 问题,后续可以优化1.6 技术方案评审要点
评审维度:
| 维度 | 关注点 |
|——|——–|
| 功能性 | 是否满足业务需求 |
| 可靠性 | 异常处理、容错设计 |
| 性能 | 响应时间、吞吐量 |
| 可扩展性 | 未来业务增长支持 |
| 安全性 | 数据安全、接口安全 |
| 可维护性 | 代码质量、文档完善 |
| 成本 | 开发成本、运维成本 |
评审流程:
1. 方案背景和目标
2. 技术选型和对比
3. 详细设计(架构图、时序图、数据模型)
4. 风险评估和应对
5. 里程碑和排期1.7 技术选型理由
场景 | 选型 | 理由 |
缓存 | Redis | 高性能、丰富数据结构 |
消息队列 | Kafka | 高吞吐、持久化 |
搜索 | Elasticsearch | 全文检索、聚合分析 |
数据库 | MySQL + 分库分表 | 成熟稳定、团队熟悉 |
二、系统设计原则
2.1 高可用设计
核心思路:冗余 + 故障转移
层级 | 方案 |
应用层 | 多实例部署、负载均衡 |
缓存层 | Redis 集群、主从 |
数据库 | 主从复制、读写分离 |
服务层 | 熔断、降级、限流 |
可用性计算:
可用性 = MTBF / (MTBF + MTTR)
99.9% = 8.76 小时/年 停机
99.99% = 52.6 分钟/年 停机2.2 高并发设计
策略 | 说明 |
缓存 | 减少数据库压力 |
异步 | 消息队列削峰 |
分流 | CDN、负载均衡 |
分库分表 | 数据水平扩展 |
池化 | 连接池、线程池 |
2.3 容量评估
日活用户:100 万
日均请求:1000 万
峰值 QPS = 日均 QPS × 峰值系数
= (1000万 / 86400) × 10
≈ 1157 × 10 = 11570 QPS
单机 QPS:1000
需要机器:12 台(预留 buffer)2.4 可扩展性设计
策略 | 说明 |
水平扩展 | 增加机器数量 |
垂直扩展 | 升级单机配置 |
无状态设计 | 服务不保存状态,便于扩展 |
分库分表 | 数据水平拆分 |
微服务拆分 | 服务独立部署扩展 |
无状态设计原则:
- Session 存储在 Redis
- 文件存储在对象存储
- 配置存储在配置中心
2.5 一致性设计
一致性级别 | 说明 | 适用场景 |
强一致性 | 写入立即可见 | 金融交易 |
最终一致性 | 一段时间后一致 | 社交动态 |
因果一致性 | 因果相关操作有序 | 评论回复 |
实现方案:
- 强一致:同步复制、分布式事务
- 最终一致:异步复制、消息队列
三、微服务
3.1 服务拆分原则
原则 | 说明 |
单一职责 | 一个服务只做一件事 |
高内聚低耦合 | 减少服务间依赖 |
业务边界 | 按领域模型拆分 |
数据独立 | 每个服务独立数据库 |
3.2 服务注册与发现
服务启动 → 注册到注册中心(Nacos/Consul)
↓
调用方从注册中心获取服务列表
↓
负载均衡选择实例调用3.3 API 网关
功能:
- 路由转发
- 认证鉴权
- 限流熔断
- 日志监控
- 协议转换
常用组件:Kong、Nginx、Spring Cloud Gateway
3.4 配置中心设计
组件 | 特点 |
Nacos | 阿里开源,配置 + 注册中心 |
Apollo | 携程开源,功能丰富 |
Spring Cloud Config | Spring 生态 |
核心功能:
- 配置集中管理
- 动态更新(不重启)
- 版本管理与回滚
- 灰度发布
- 权限控制
3.5 服务间通信
方式 | 特点 | 适用场景 |
HTTP/REST | 简单、通用 | 跨语言、外部接口 |
RPC(gRPC) | 高性能、强类型 | 内部服务调用 |
消息队列 | 异步、解耦 | 异步处理、削峰 |
3.6 服务版本管理
版本策略:
- URL 版本:
/api/v1/users
- Header 版本:Accept: application/vnd.api.v1+json
- 参数版本:/api/users?version=1兼容性原则:
- 新增字段不破坏旧版本
- 废弃字段标记 deprecated
- 重大变更发布新版本
四、消息队列
4.1 使用场景
场景 | 说明 |
异步处理 | 注册后发邮件、短信 |
削峰填谷 | 秒杀订单入队 |
系统解耦 | 订单 → 库存、物流 |
日志收集 | 应用日志 → Kafka → ES |
4.2 消息可靠性
生产者:
1. 确认机制(acks=all)
2. 重试机制
3. 本地消息表Broker:
1. 持久化
2. 副本机制消费者:
1. 手动确认
2. 幂等处理4.3 消息顺序性
Kafka:
- 单 Partition 内有序
- 相同 Key 发送到同一 Partition
producer.send(new ProducerRecord<>(topic, orderId, message));4.4 消息积压处理
- 临时扩容消费者
- 跳过非关键消息
- 转存后离线处理
4.5 Kafka 高性能原理
技术 | 说明 |
顺序写 | 磁盘顺序写性能高 |
零拷贝 | sendfile 减少拷贝 |
批量发送 | 减少网络开销 |
分区并行 | 多 Partition 并行消费 |
页缓存 | 利用 OS 页缓存 |
4.6 消息幂等性
问题:消息可能重复消费
解决方案:
| 方案 | 说明 |
|——|——|
| 唯一 ID | 消息携带唯一 ID,消费前检查 |
| 数据库唯一索引 | 业务字段唯一约束 |
| Redis 去重 | SETNX 记录已处理消息 |
| 状态机 | 状态只能单向流转 |
def consume(message):
msg_id = message.id
# Redis 去重
if not redis.setnx(f"msg:{msg_id}", 1, ex=86400):
return # 已处理
# 处理业务逻辑
process(message)4.7 延迟消息实现
方案 | 说明 |
RocketMQ 延迟级别 | 内置 18 个延迟级别 |
RabbitMQ 死信队列 | TTL + 死信交换机 |
Redis ZSet | score 为执行时间 |
时间轮 | 高效定时任务 |
# Redis ZSet 实现
def delay_message(msg, delay_seconds):
execute_time = time.time() + delay_seconds
redis.zadd("delay_queue", {msg: execute_time})
# 消费者轮询
while True:
now = time.time()
messages = redis.zrangebyscore("delay_queue", 0, now)
for msg in messages:
process(msg)
redis.zrem("delay_queue", msg)4.8 Kafka vs RabbitMQ vs RocketMQ
特性 | Kafka | RabbitMQ | RocketMQ |
吞吐量 | 极高 | 中等 | 高 |
延迟 | 毫秒级 | 微秒级 | 毫秒级 |
消息顺序 | Partition 内有序 | 队列内有序 | 队列内有序 |
延迟消息 | 不支持 | 支持 | 支持 |
事务消息 | 支持 | 支持 | 支持 |
适用场景 | 日志、大数据 | 业务消息 | 电商、金融 |
五、分布式
5.1 CAP 理论
特性 | 说明 |
C(一致性) | 所有节点数据一致 |
A(可用性) | 请求都能得到响应 |
P(分区容错) | 网络分区时系统可用 |
三选二:分布式系统必须容忍 P,在 C 和 A 间权衡
系统 | 选择 |
ZooKeeper | CP |
Eureka | AP |
Redis Cluster | AP |
5.2 BASE 理论
特性 | 说明 |
BA(基本可用) | 允许部分功能降级 |
S(软状态) | 允许中间状态 |
E(最终一致) | 最终数据一致 |
5.3 分布式事务
方案 | 原理 | 适用场景 |
2PC | 协调者两阶段提交 | 强一致要求 |
TCC | Try-Confirm-Cancel | 高并发 |
Saga | 补偿事务 | 长事务 |
本地消息表 | 消息 + 定时任务 | 异步场景 |
TCC 示例:
Try:预留资源(冻结库存)
Confirm:确认执行(扣减库存)
Cancel:取消释放(解冻库存)5.4 分布式锁
Redis 实现:
-- 加锁
SET lock_key unique_value NX EX 30
-- 解锁(Lua 保证原子性)
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
endZooKeeper 实现:
创建临时顺序节点
判断是否最小节点
是 → 获得锁
否 → 监听前一个节点5.5 分布式 ID
方案 | 优点 | 缺点 |
UUID | 简单 | 无序、太长 |
数据库自增 | 简单 | 性能瓶颈 |
雪花算法 | 趋势递增、高性能 | 时钟回拨 |
Leaf | 高可用 | 依赖外部服务 |
5.6 一致性哈希
解决问题:节点增减时减少数据迁移
哈希环:0 ~ 2^32-1
节点映射到环上
数据顺时针找到第一个节点
虚拟节点:解决数据倾斜5.7 Raft 协议
核心:Leader 选举 + 日志复制
1. 选举:获得多数票成为 Leader
2. 日志复制:Leader 复制日志到 Follower
3. 提交:多数确认后提交5.8 Paxos 协议
角色:
- Proposer:提出提案
- Acceptor:接受提案
- Learner:学习已通过的提案
两阶段:
1. Prepare:Proposer 发送提案编号
2. Accept:Acceptor 接受最高编号的提案
与 Raft 对比:
| 特性 | Paxos | Raft |
|——|——-|——|
| 复杂度 | 高 | 低 |
| 理解难度 | 难 | 易 |
| Leader | 可选 | 必须 |
| 工程实现 | 复杂 | 简单 |
5.9 ZooKeeper 原理与应用
核心特性:
- 顺序一致性
- 原子性
- 单一视图
- 可靠性
- 实时性(最终一致)
应用场景:
| 场景 | 实现方式 |
|——|———-|
| 配置中心 | 持久节点 + Watch |
| 服务注册 | 临时节点 |
| 分布式锁 | 临时顺序节点 |
| Leader 选举 | 临时顺序节点 |
/services
/user-service
/instance-1 (临时节点)
/instance-2 (临时节点)六、缓存设计
6.1 缓存策略
策略 | 说明 |
Cache-Aside | 先查缓存,未命中查库并写缓存 |
Read-Through | 缓存层负责读取 |
Write-Through | 同步写缓存和数据库 |
Write-Behind | 异步批量写数据库 |
6.2 缓存一致性
推荐方案:先更新数据库,再删除缓存
def update(data):
db.update(data)
cache.delete(key)
# 延迟双删(可选)
time.sleep(0.5)
cache.delete(key)为什么删除而不是更新:
- 避免并发写导致数据不一致
- 懒加载,减少无效更新
6.3 多级缓存
请求 → 本地缓存(Caffeine) → Redis → 数据库6.4 热点数据处理
方案 | 说明 |
本地缓存 | 减少 Redis 压力 |
多副本 | 热点 Key 分散到多个 Key |
读写分离 | 从库分担读压力 |
6.5 缓存预热
场景:系统启动时缓存为空,大量请求打到数据库
方案:
1. 启动预热:启动时加载热点数据
2. 定时预热:定时任务刷新缓存
3. 手动预热:运维工具触发
def warm_up_cache():
# 加载热点商品
hot_products = db.query("SELECT * FROM products WHERE is_hot = 1")
for product in hot_products:
cache.set(f"product:{product.id}", product, ex=3600)
# 加载热门用户
hot_users = db.query("SELECT * FROM users ORDER BY followers DESC LIMIT 1000")
for user in hot_users:
cache.set(f"user:{user.id}", user, ex=3600)七、限流熔断
7.1 限流算法
算法 | 说明 | 特点 |
计数器 | 固定窗口计数 | 临界问题 |
滑动窗口 | 滑动时间窗口 | 平滑 |
漏桶 | 固定速率处理 | 平滑输出 |
令牌桶 | 固定速率放令牌 | 允许突发 |
令牌桶实现:
class TokenBucket:
def __init__(self, rate, capacity):
self.rate = rate # 令牌生成速率
self.capacity = capacity # 桶容量
self.tokens = capacity
self.last_time = time.time()
def acquire(self):
now = time.time()
# 添加令牌
self.tokens = min(self.capacity,
self.tokens + (now - self.last_time) * self.rate)
self.last_time = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False7.2 熔断器
状态转换:
Closed → Open → Half-Open → Closed
↓ ↓ ↓
正常 熔断 尝试恢复Hystrix/Sentinel:
- 失败率超阈值 → 熔断
- 超时时间后 → 半开
- 成功 → 关闭
7.3 降级策略
策略 | 说明 |
返回默认值 | 返回兜底数据 |
返回缓存 | 返回旧缓存数据 |
功能降级 | 关闭非核心功能 |
页面降级 | 返回静态页面 |
7.4 服务隔离
方式 | 说明 | 优缺点 |
线程池隔离 | 每个服务独立线程池 | 隔离性好,开销大 |
信号量隔离 | 限制并发数 | 开销小,无法超时 |
// Hystrix 线程池隔离
@HystrixCommand(
threadPoolKey = "userServicePool",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "10"),
@HystrixProperty(name = "maxQueueSize", value = "100")
}
)
public User getUser(Long id) {
return userService.getUser(id);
}八、性能优化
8.1 接口优化
方向 | 方法 |
减少 IO | 批量查询、缓存 |
异步处理 | 非核心逻辑异步化 |
并行处理 | 多线程并行查询 |
减少数据 | 按需返回字段 |
8.2 数据库优化
方向 | 方法 |
索引 | 合理建索引 |
SQL | 避免慢查询 |
连接池 | 复用连接 |
读写分离 | 分担读压力 |
分库分表 | 水平扩展 |
8.3 线上问题排查
CPU 100%:
1. top -c 找到进程
2. top -Hp <pid> 找到线程
3. printf '%x' <tid> 转 16 进制
4. jstack <pid> | grep <tid> 查看堆栈内存泄漏:
1. jmap -heap <pid> 查看堆使用
2. jmap -dump:format=b,file=heap.bin <pid>
3. MAT 分析 dump 文件GC 问题:
1. jstat -gc <pid> 1000 查看 GC 情况
2. 分析 GC 日志
3. 调整堆大小、GC 算法8.4 JVM 调优
常用参数:
# 堆内存
-Xms4g -Xmx4g # 初始和最大堆
-Xmn2g # 新生代大小
# GC 选择
-XX:+UseG1GC # G1 收集器
-XX:+UseZGC # ZGC(低延迟)
# GC 日志
-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=10M调优思路:
1. 确定性能目标(吞吐量/延迟)
2. 选择合适的 GC 算法
3. 调整堆大小和比例
4. 分析 GC 日志优化
8.5 压测与性能评估
压测工具:
| 工具 | 特点 |
|——|——|
| JMeter | 功能丰富,GUI |
| wrk | 高性能,命令行 |
| ab | 简单,Apache 自带 |
| Locust | Python,分布式 |
关键指标:
| 指标 | 说明 |
|——|——|
| QPS | 每秒请求数 |
| TPS | 每秒事务数 |
| RT | 响应时间 |
| P99 | 99% 请求的响应时间 |
| 错误率 | 失败请求占比 |
# wrk 示例
wrk -t12 -c400 -d30s http://localhost:8080/api/users八点五、监控告警
8.6 日志收集与分析(ELK)
架构:
应用日志 → Filebeat → Kafka → Logstash → Elasticsearch → Kibana组件职责:
| 组件 | 职责 |
|——|——|
| Filebeat | 日志采集,轻量级 |
| Logstash | 日志解析、转换 |
| Elasticsearch | 存储、检索 |
| Kibana | 可视化、分析 |
日志规范:
{
"timestamp": "2026-01-09T10:00:00Z",
"level": "ERROR",
"service": "order-service",
"traceId": "abc123",
"message": "订单创建失败",
"exception": "..."
}8.7 链路追踪(Jaeger/Zipkin)
核心概念:
| 概念 | 说明 |
|——|——|
| Trace | 一次完整请求链路 |
| Span | 链路中的一个操作 |
| TraceId | 链路唯一标识 |
| SpanId | 操作唯一标识 |
| ParentSpanId | 父操作标识 |
实现原理:
请求进入 → 生成 TraceId → 传递到下游服务 → 收集 Span → 聚合展示8.8 指标监控(Prometheus/Grafana)
Prometheus 架构:
应用暴露 /metrics → Prometheus 拉取 → 存储时序数据 → Grafana 展示
↓
Alertmanager 告警四种指标类型:
| 类型 | 说明 | 示例 |
|——|——|——|
| Counter | 只增不减 | 请求总数 |
| Gauge | 可增可减 | 当前连接数 |
| Histogram | 分布统计 | 响应时间分布 |
| Summary | 分位数统计 | P99 延迟 |
8.9 告警设计
告警分级:
| 级别 | 说明 | 响应时间 |
|——|——|———-|
| P0 | 核心业务不可用 | 5 分钟 |
| P1 | 重要功能受损 | 30 分钟 |
| P2 | 非核心功能异常 | 2 小时 |
| P3 | 预警类 | 下个工作日 |
告警规则示例:
# Prometheus 告警规则
groups:
-name: api-alerts
rules:
-alert: HighErrorRate
expr: rate(http_requests_total{status="500"}[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary:"高错误率告警"九、场景设计题
9.1 秒杀系统
核心挑战:高并发、超卖、重复下单
架构设计:
用户 → CDN → Nginx → 网关 → 秒杀服务 → Redis → MQ → 订单服务关键技术:
| 问题 | 方案 |
|——|——|
| 高并发 | 页面静态化、CDN、限流 |
| 超卖 | Redis 预扣库存 + Lua 原子操作 |
| 重复下单 | 用户 + 商品 唯一索引 |
| 数据库压力 | 异步下单(MQ) |
Redis 扣库存:
local stock = redis.call('get', KEYS[1])
if tonumber(stock) > 0 then
redis.call('decr', KEYS[1])
return 1
end
return 09.2 短链服务
核心功能:长链接 → 短链接 → 重定向
设计方案:
1. 生成短码:Base62(自增ID) 或 哈希
2. 存储:短码 → 长链接
3. 访问:302 重定向短码生成:
CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def encode(num):
result = []
while num:
result.append(CHARS[num % 62])
num //= 62
return ''.join(reversed(result))9.3 Feed 流系统
推模式:写扩散
发布动态 → 写入所有粉丝的 Feed 列表
优点:读取快
缺点:写放大(大 V 问题)拉模式:读扩散
读取 Feed → 聚合关注人的动态
优点:写入简单
缺点:读取慢推拉结合:
- 普通用户:推模式
- 大 V:拉模式
9.4 订单系统
核心问题:
| 问题 | 方案 |
|——|——|
| 订单超时取消 | 延迟队列(RocketMQ/Redis ZSet) |
| 库存扣减 | 预扣 → 确认/回滚 |
| 幂等性 | 订单号唯一索引 |
| 分库分表 | 按用户 ID 分片 |
9.5 支付系统
核心问题:
| 问题 | 方案 |
|——|——|
| 重复支付 | 支付单号幂等 |
| 掉单 | 对账 + 补单 |
| 一致性 | 本地事务 + 异步通知 |
| 安全 | 签名验签、HTTPS |
9.6 抢红包系统
设计要点:
1. 预分配:红包创建时预先分配金额
2. 原子扣减:Redis Lua 保证原子性
3. 异步入账:消息队列异步处理
-- 抢红包 Lua 脚本
local remaining = redis.call('hget', KEYS[1], 'remaining')
if tonumber(remaining) > 0 then
local amount = redis.call('lpop', KEYS[2])
if amount then
redis.call('hincrby', KEYS[1], 'remaining', -1)
return amount
end
end
return nil9.7 评论系统
数据模型:
-- 评论表
CREATE TABLE comments (
id BIGINT PRIMARY KEY,
content TEXT,
user_id BIGINT,
target_id BIGINT, -- 被评论对象
parent_id BIGINT, -- 父评论(楼中楼)
root_id BIGINT, -- 根评论
created_at TIMESTAMP
);分页方案:
- 游标分页(推荐):
WHERE id < last_id ORDER BY id DESC LIMIT 20
- 偏移分页:LIMIT 20 OFFSET 100(大偏移性能差)9.8 排行榜系统
Redis ZSet 实现:
# 更新分数
redis.zadd("leaderboard", {user_id: score})
# 获取排名(从 0 开始)
rank = redis.zrevrank("leaderboard", user_id)
# 获取 Top N
top_users = redis.zrevrange("leaderboard", 0, 9, withscores=True)
# 获取用户附近排名
start = max(0, rank - 5)
nearby = redis.zrevrange("leaderboard", start, rank + 5, withscores=True)9.9 搜索系统
架构:
数据源 → 数据同步 → Elasticsearch → 搜索服务 → 用户核心功能:
| 功能 | 实现 |
|——|——|
| 全文检索 | ES 倒排索引 |
| 分词 | IK 分词器 |
| 高亮 | highlight |
| 聚合 | aggregations |
| 排序 | 相关性 + 业务权重 |
9.10 定时任务系统
方案 | 适用场景 |
Cron | 单机定时 |
Quartz | 分布式定时 |
XXL-JOB | 可视化调度 |
时间轮 | 高性能延迟任务 |
分布式定时任务要点:
- 任务只执行一次(分布式锁)
- 任务失败重试
- 任务监控告警
9.11 消息推送系统
架构:
业务系统 → 推送服务 → 长连接网关 → 客户端
↘ 第三方推送(APNs/FCM)长连接方案:
| 方案 | 特点 |
|——|——|
| WebSocket | 双向通信,浏览器支持 |
| MQTT | 轻量级,IoT 常用 |
| 自定义协议 | 灵活,开发成本高 |
9.12 文件存储系统
架构:
客户端 → 上传服务 → 对象存储(OSS/S3)
↓
元数据服务 → 数据库大文件上传:
1. 分片上传:大文件切分为小块
2. 断点续传:记录已上传分片
3. 秒传:MD5 校验,相同文件直接返回
十、通用问题
10.1 接口幂等性
方案 | 说明 |
唯一索引 | 数据库唯一约束 |
Token 机制 | 先获取 Token,使用后删除 |
状态机 | 状态只能单向流转 |
乐观锁 | version 版本号 |
Token 实现:
# 获取 Token
token = uuid.uuid4()
redis.set(f"token:{token}", 1, ex=300)
return token
# 使用 Token
if redis.delete(f"token:{token}"):
# 执行业务
else:
# 重复请求10.2 接口安全
方案 | 说明 |
HTTPS | 传输加密 |
签名 | 防篡改 |
时间戳 | 防重放 |
Token | 身份认证 |
限流 | 防刷 |
10.3 灰度发布
方案 | 说明 |
用户灰度 | 按用户 ID 百分比 |
流量灰度 | 按请求百分比 |
机器灰度 | 部分机器部署新版本 |
10.4 AB 测试
实现方式:
1. 流量分桶:用户 ID 哈希分配到不同桶
2. 实验配置:配置中心管理实验参数
3. 数据收集:埋点收集用户行为
4. 效果分析:统计分析确定最优方案
def get_experiment_group(user_id, experiment_name):
bucket = hash(f"{user_id}:{experiment_name}") % 100
if bucket < 10:
return "control" # 对照组 10%
elif bucket < 20:
return "treatment_a" # 实验组A 10%
else:
return "treatment_b" # 实验组B 80%10.5 项目亮点回答模板
1. 背景:为什么要做这个优化/设计
2. 方案:采用了什么技术方案
3. 实现:关键的技术细节
4. 效果:量化的改进数据
5. 思考:方案的优缺点、改进空间示例:
背景:订单查询接口 P99 延迟达到 500ms,影响用户体验
方案:引入多级缓存(本地缓存 + Redis)
实现:
- 本地缓存使用 Caffeine,TTL 10s
- Redis 缓存 TTL 5min
- 缓存更新采用 Cache-Aside 模式
效果:P99 延迟降低到 50ms,数据库 QPS 下降 80%
思考:需要注意缓存一致性问题,采用延迟双删保证10.6 如何设计高可用系统
核心策略:
| 层面 | 方案 |
|——|——|
| 冗余 | 多实例、多机房、多活 |
| 隔离 | 服务隔离、资源隔离 |
| 限流 | 保护系统不被压垮 |
| 熔断 | 快速失败,避免级联故障 |
| 降级 | 有损服务优于无服务 |
| 监控 | 快速发现和定位问题 |
可用性公式:
可用性 = MTBF / (MTBF + MTTR)
MTBF: 平均故障间隔时间
MTTR: 平均故障恢复时间
提高可用性:
1. 增加 MTBF:减少故障发生
2. 减少 MTTR:快速恢复10.4 项目难点回答模板
1. 背景:遇到什么问题
2. 分析:问题原因是什么
3. 方案:尝试了哪些方案
4. 选择:为什么选择这个方案
5. 结果:最终效果如何
6. 反思:有什么收获十一、高频面试题与答案
Q1: 如何介绍项目?
答案(STAR 法则):
1. Situation(背景):项目是什么,解决什么问题
2. Task(任务):你负责哪部分,目标是什么
3. Action(行动):你做了什么,用了什么技术
4. Result(结果):取得了什么成果,数据量化示例:
> 我负责订单系统的性能优化。当时系统 QPS 只有 500,大促期间频繁超时。
> 我通过引入 Redis 缓存热点数据、优化慢 SQL、增加读写分离,
> 最终将 QPS 提升到 5000,接口 P99 从 800ms 降到 50ms。
Q2: 如何设计高并发系统?
答案:
1. 缓存:Redis 缓存热点数据,减少数据库压力
2. 异步:消息队列削峰填谷,异步处理非核心逻辑
3. 分流:
- CDN 静态资源加速
- 负载均衡分散请求
- 分库分表分散数据
4. 限流:保护系统不被压垮
5. 池化:连接池、线程池复用资源
6. 无状态:服务无状态,支持水平扩展Q3: 如何保证高可用?
答案:
策略 | 说明 |
冗余部署 | 多实例、多机房、主从复制 |
负载均衡 | 请求分发、故障节点摘除 |
熔断降级 | 服务不可用时快速失败 |
限流 | 保护系统不被压垮 |
超时重试 | 合理超时、有限重试 |
监控告警 | 及时发现问题 |
灰度发布 | 降低发布风险 |
Q4: 消息队列如何保证不丢失?
答案:
生产端:
- 开启发送确认(confirm 模式)
- 失败重试 + 本地消息表
Broker 端:
- 消息持久化到磁盘
- 多副本同步(Kafka ISR)
消费端:
- 手动 ACK,处理完再确认
- 消费失败进入死信队列Q5: 分布式事务怎么做?
答案:
方案 | 原理 | 适用场景 |
2PC | 协调者两阶段提交 | 强一致性,性能差 |
TCC | Try-Confirm-Cancel | 高性能,实现复杂 |
Saga | 事务补偿 | 长事务,最终一致 |
本地消息表 | 消息 + 定时任务 | 简单可靠 |
事务消息 | RocketMQ 半消息 | 解耦,最终一致 |
推荐:优先考虑最终一致性方案(Saga、消息队列)
Q6: 分布式锁怎么实现?
答案:
Redis 实现:
# 加锁
SET lock_key unique_id NX PX 30000
# 解锁(Lua 脚本)
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
endZooKeeper 实现:
- 创建临时顺序节点
- 监听前一个节点
- 最小序号获得锁
对比 | Redis | ZooKeeper |
性能 | 高 | 较低 |
可靠性 | 主从切换可能丢锁 | 高(CP) |
实现 | 简单 | 复杂 |
Q7: 缓存一致性怎么保证?
答案:
推荐方案:Cache Aside Pattern
读:先读缓存,没有则读数据库,写入缓存
写:先更新数据库,再删除缓存为什么删除而不是更新?
- 避免并发写导致数据不一致
- 懒加载,减少无效更新
延迟双删:
1. 删除缓存
2. 更新数据库
3. 延迟 500ms 再删除缓存(防止并发读写不一致)Q8: 接口幂等怎么做?
答案:
方案 | 实现 | 适用场景 |
Token 机制 | 请求前获取 token,使用后失效 | 表单提交 |
唯一索引 | 数据库唯一约束 | 创建类操作 |
状态机 | 状态只能单向流转 | 订单状态变更 |
去重表 | 记录已处理请求 | 通用 |
乐观锁 | version 字段控制 | 更新操作 |
Q9: 限流算法有哪些?
答案:
算法 | 原理 | 特点 |
固定窗口 | 固定时间窗口计数 | 简单,有临界问题 |
滑动窗口 | 滑动时间窗口 | 平滑,实现复杂 |
漏桶 | 固定速率流出 | 平滑流量,无法应对突发 |
令牌桶 | 固定速率放入令牌 | 允许一定突发 |
推荐:令牌桶(Guava RateLimiter)或滑动窗口
Q10: 设计秒杀系统?
答案:
1. 前端:
- 静态资源 CDN
- 按钮防重复点击
- 答题/验证码削峰
2. 网关层:
- 限流(令牌桶)
- 黑名单过滤
3. 服务层:
- Redis 预扣库存
- 库存不足直接返回
- 下单请求入消息队列
4. 数据层:
- 异步消费创建订单
- 数据库乐观锁扣减库存关键点:尽量将请求拦截在上游,减少数据库压力
Q11: 设计短链服务?
答案:
生成短链:
1. 发号器生成唯一 ID
2. Base62 编码(0-9, a-z, A-Z)
3. 存储映射关系:短链 → 长链访问流程:
1. 用户访问短链
2. 服务查询映射关系
3. 302 重定向到长链优化:
- 布隆过滤器判断短链是否存在
- Redis 缓存热点短链
- 分库分表支持海量数据
Q12: 线上问题怎么排查?
答案:
CPU 高:
1. top -Hp <pid> 查看高 CPU 线程
2. printf "%x\n" <tid> 转换为十六进制
3. jstack <pid> | grep <tid> 查看线程堆栈内存问题:
1. jmap -heap <pid> 查看堆内存
2. jmap -dump:format=b,file=heap.hprof <pid>
3. MAT 分析堆转储GC 问题:
1. jstat -gc <pid> 1000 查看 GC 情况
2. 分析 GC 日志
3. 调整堆大小、GC 算法最后更新:2026-01-09






Loading Comments...