1.1 RESTful 核心:资源 + HTTP 动词 + 状态码
REST (Representational State Transfer) 是一种架构风格,核心思想:
- 资源 (Resource):一切皆资源,用 URL 标识(名词)
- 动作 (Verb):用 HTTP 方法表达操作(GET/POST/PUT/DELETE)
- 表现层 (Representation):JSON/XML 是资源的表现形式
- 无状态 (Stateless):每次请求包含所有必要信息
| CRUD 操作 | HTTP 方法 | 路径示例 | 是否幂等 | 是否安全 | 语义 |
|---|---|---|---|---|---|
| Create | POST | POST /machines |
否 | 否 | 创建新资源 |
| Read | GET | GET /machines/42 |
是 | 是 | 获取资源 |
| Update (全量) | PUT | PUT /machines/42 |
是 | 否 | 替换整个资源 |
| Update (部分) | PATCH | PATCH /machines/42 |
否 | 否 | 修改部分字段 |
| Delete | DELETE | DELETE /machines/42 |
是 | 否 | 删除资源 |
幂等性:同一请求执行一次和多次效果相同 | 安全性:请求不会修改服务器资源
1.2 URL 设计规则
| 规则 | 好 | 坏 |
|---|---|---|
| 用名词不用动词 | GET /orders | GET /getOrders |
| 用复数名词 | /users | /user |
| 嵌套表示关系 | /users/1/orders | /getUserOrders?uid=1 |
| 用 query 过滤 | /orders?status=active | /activeOrders |
| 用 query 分页 | /orders?page=2&size=20 | /orders/page/2 |
| 用 query 排序 | /orders?sort=-created_at | /ordersByDateDesc |
/workshops/3/machines 就像「3号车间的设备清单」——先定位车间,再看设备。
过滤 ?status=running 就是「只看正在运行的设备」。
排序 ?sort=-temperature 就是「按温度从高到低排」。
分页 ?page=1&size=50 就是「每次只看50台」。
1.3 版本控制
| 方式 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| URL 路径 | /api/v1/users | 直观,易调试 | URL 变长 |
| 请求头 | Accept: application/vnd.api.v2+json | URL 干净 | 不易调试 |
| 查询参数 | /api/users?version=2 | 简单 | 不够 RESTful |
推荐:URL 路径方式,团队最容易理解和实施。
场景:某项目后端 API 混用 RESTful 和 RPC 风格:
// 不一致的设计 — 前端工程师崩溃
POST /api/getUserInfo // 用了动词
POST /api/user/create // RESTful 但路径不对
GET /api/user_list // 下划线风格
GET /api/order-detail/123 // 连字符风格
POST /api/orders/delete/456 // 用 POST 删除?
问题:前端每次都要查文档才能确定用哪个方法、哪个路径、返回什么格式。
修复:统一 RESTful 规范 + 自动生成 API 文档(Swagger/OpenAPI)。
// 统一后的设计
GET /api/v1/users // 列表
POST /api/v1/users // 创建
GET /api/v1/users/:id // 详情
PUT /api/v1/users/:id // 全量更新
DELETE /api/v1/users/:id // 删除
GET /api/v1/users/:id/orders // 子资源
1.4 实战案例:制造 OEE 仪表盘 API 设计
OEE (Overall Equipment Effectiveness) = 可用率 × 性能率 × 质量率。以下是一个完整的生产级 API 设计:
基础路径: /api/v1
// ===== 工厂 & 产线 =====
GET /factories // 工厂列表
GET /factories/{fid}/lines // 产线列表
GET /factories/{fid}/lines/{lid} // 产线详情
// ===== 设备 =====
GET /lines/{lid}/machines // 设备列表
GET /machines/{mid} // 设备详情
PATCH /machines/{mid}/status // 更新设备状态
// ===== OEE 数据 =====
GET /oee/overview?factory=1&date=2026-06-10
// 工厂级 OEE 总览
GET /oee/lines/{lid}?period=daily&date=2026-06-10
// 产线 OEE(可用率/性能率/质量率)
GET /oee/machines/{mid}?period=hourly&start=2026-06-10T00:00&end=2026-06-10T23:59
// 设备级 OEE 趋势
GET /oee/leaderboard?sort=-oee&limit=10
// OEE 排行榜
// ===== 告警 =====
GET /alerts?severity=critical&status=open&page=1&size=20
PATCH /alerts/{aid} // 处理告警
// ===== 报表导出 =====
POST /reports/generate // 生成报表任务
GET /reports/{rid}/download // 下载报表
设计要点:资源嵌套不超过2层,复杂查询用 query 参数,导出等异步操作返回任务 ID。
2xx = 「加工完成,请取货」 | 3xx = 「此工序已搬到3号车间」 | 4xx = 「图纸画错了,请修改」 | 5xx = 「机器故障了,我们在修」
2.2 常用状态码详解
| 码 | 含义 | 使用场景 | 工厂类比 |
|---|---|---|---|
200 | OK | GET 成功、PUT/PATCH 更新成功 | 质检合格,准予出厂 |
201 | Created | POST 创建资源成功,返回新资源 | 新设备入库登记完成 |
204 | No Content | DELETE 成功,无需返回 body | 报废设备已移除 |
301 | Moved Permanently | 资源永久迁移到新 URL | 产线永久搬到新厂房 |
400 | Bad Request | 请求格式错误、参数校验失败 | 工单填写不完整 |
401 | Unauthorized | 未认证(token 缺失/过期) | 没刷工牌,门禁不放行 |
403 | Forbidden | 已认证但无权限 | 普通工人进不了总经理办公室 |
404 | Not Found | 资源不存在 | 设备编号不存在 |
409 | Conflict | 资源冲突(重复创建) | 设备编号已存在 |
422 | Unprocessable Entity | 格式正确但语义错误 | 温度值填了负数 |
429 | Too Many Requests | 请求频率超限 | 同一产线1分钟报工100次 |
500 | Internal Server Error | 服务器内部错误 | 控制系统崩溃 |
502 | Bad Gateway | 网关收到无效上游响应 | 中控系统收到车间乱码 |
503 | Service Unavailable | 服务暂时不可用(过载/维护) | 车间正在检修,暂停接单 |
- 永远不要所有接口都返回 200,然后用 body 里的 code 区分 — 这违背了 HTTP 语义
- 4xx vs 5xx:客户端能修复的错误用 4xx,服务端自己的问题用 5xx
- 401 vs 403:不知道你是谁 → 401;知道你是谁但没权限 → 403
- 400 vs 422:格式语法错误 → 400;格式对但业务逻辑不通 → 422
3.1 认证方式概览
API Key = 厂牌(一张卡进出所有门,简单但不灵活)
JWT = 电子通行证(含照片+权限+有效期,自助验证不需查系统)
OAuth 2.0 = 临时授权书(你授权快递员只能进收发室,不能进车间)
API Key — 最简单的方式
// 请求时带上 Key
GET /api/v1/machines
Header: X-API-Key: sk_live_abc123def456
// 或 query 参数(不推荐,会出现在日志里)
GET /api/v1/machines?api_key=sk_live_abc123def456
优点:实现极简 | 缺点:无细粒度权限、无法过期、泄露风险高
适用:服务间调用、开放 API(如天气接口)
3.2 JWT (JSON Web Token) 详解
{ "alg": "HS256", "typ": "JWT" }
{ "sub": "user_42", "role": "admin", "exp": 1718000000 }
HMAC(header.payload, secret)
用什么加密
谁、什么角色、何时过期
确保内容没被改过
Header(卡片材质)+ Payload(你的照片+部门+有效期)+ Signature(防伪标记,HR盖章)。
任何人都能读取内容(Base64),但只有持有密钥的人能验证真伪。
POST /auth/login
查数据库
含用户信息+过期时间
localStorage / Cookie
Authorization: Bearer xxx
无状态,不查 DB
3.3 OAuth 2.0 授权码流程
authorization_code
你(用户)授权快递员(第三方应用)进入小区(资源服务器)放快递, 物业(授权服务器)给快递员一张临时通行证(access_token), 有效期1小时,到期可以续签(refresh_token)。
3.4 Session vs Token 对比
| 维度 | Session (有状态) | JWT Token (无状态) |
|---|---|---|
| 存储位置 | 服务端内存/Redis | 客户端(localStorage/Cookie) |
| 扩展性 | 需共享 Session(粘性会话/Redis) | 天然支持分布式 |
| 性能 | 每次查存储 | 验签即可,无 I/O |
| 安全撤销 | 直接删除 Session | 需黑名单机制(又变成有状态) |
| payload 大小 | 只需 Session ID | Token 自带数据,体积较大 |
| 适用场景 | 传统 Web 应用 | API、移动端、微服务 |
3.5 Refresh Token Rotation
15 分钟过期
换新 Access Token
+ 新 Refresh Token
Rotation:每次刷新时同时颁发新 Refresh Token,旧的一次性作废。 若旧 Refresh Token 被重复使用,说明可能被盗,立即撤销整个 Token 家族。
问题:JWT 无状态,签发后无法主动撤销。如果 Token 泄露,攻击者在过期前可一直使用。
解决方案(多层防御):
- 短有效期:Access Token 15 分钟,即使泄露窗口也小
- Refresh Token Rotation:刷新时轮换,检测重放攻击
- Token 黑名单:登出/改密码时将 Token 的 jti 加入 Redis 黑名单
- IP 绑定:签发时记录 IP,使用时校验(可选)
- HTTPS:传输层加密,防止中间人窃取
// 黑名单检查中间件 (伪代码)
async function jwtGuard(req, res, next) {
const token = extractToken(req);
const payload = jwt.verify(token, SECRET);
const isBlacklisted = await redis.get(`blacklist:${payload.jti}`);
if (isBlacklisted) return res.status(401).json({ error: 'Token revoked' });
req.user = payload;
next();
}
4.1 限流 (Rate Limiting)
Redis INCR + EXPIRE
Redis Sorted Set + 时间戳
Google Guava RateLimiter
- 限流维度:按 IP、按用户 ID、按 API Key、按接口
- 返回信息:
429 Too Many Requests+X-RateLimit-Remaining+Retry-After - 分布式:用 Redis 存计数,确保多实例一致
- 推荐算法:令牌桶(允许突发)+ 滑动窗口(精确统计)
4.2 输入校验
// 常见输入校验清单
const validationRules = {
// 1. 类型校验
age: { type: 'integer', min: 0, max: 150 },
// 2. 格式校验
email: { type: 'string', format: 'email' },
// 3. 长度限制
name: { type: 'string', minLength: 1, maxLength: 100 },
// 4. 枚举值
status: { type: 'string', enum: ['active', 'inactive', 'maintenance'] },
// 5. SQL 注入防护 — 永远用参数化查询
// BAD: `SELECT * FROM users WHERE id = ${req.params.id}`
// GOOD: `SELECT * FROM users WHERE id = $1`, [req.params.id]
// 6. XSS 防护 — 输出时转义
// BAD: res.send(`${user.name}`)
// GOOD: 使用模板引擎自动转义
};
4.3 CORS 配置
// Express CORS 配置示例
app.use(cors({
origin: ['https://app.example.com'], // 不要用 *
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // 允许携带 Cookie
maxAge: 86400 // 预检缓存 24 小时
}));
// 生产环境注意:
// - origin 不要用 '*',要精确指定域名
// - credentials: true 时 origin 不能是 '*'
// - 预检请求 (OPTIONS) 会消耗资源,设置 maxAge
4.4 HTTPS 强制
- 所有生产环境 API 必须 HTTPS
- 使用 HSTS 头:
Strict-Transport-Security: max-age=31536000; includeSubDomains - HTTP 请求自动 301 重定向到 HTTPS
场景:某开放 API 被爬虫/攻击者高频率调用,导致后端数据库连接池耗尽,正常用户无法使用。
应急处理:
- 紧急止损:WAF 层面按 IP 黑名单封禁攻击源
- 启用限流:按 IP 限 100 次/分钟,按用户限 1000 次/分钟
- 分析日志:定位异常调用模式(User-Agent、路径、时间分布)
- 长期方案:API Gateway 统一限流 + 验证码 + API Key 白名单
// Nginx 限流配置
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;
limit_req zone=api burst=50 nodelay;
// IP 黑名单
deny 203.0.113.0/24;
deny 198.51.100.0/24;
query {
user(id: 1) {
name
orders { id total }
address { city }
}
}
5.1 什么时候用 GraphQL
| 场景 | 适合 GraphQL | 适合 REST |
|---|---|---|
| 多端(Web/iOS/Android)不同数据需求 | ✓ 每端按需查询 | |
| 复杂嵌套数据(用户→订单→商品→评价) | ✓ 一次查询搞定 | 多次请求或 over-fetch |
| 简单 CRUD 后台管理 | ✓ REST 更直观 | |
| 缓存至关重要 | 缓存较复杂 | ✓ HTTP 缓存天然支持 |
| 团队 REST 经验丰富,GraphQL 经验少 | 学习成本高 | ✓ 快速上手 |
5.2 GraphQL 三种操作
# Query — 查询数据(类比 GET)
query GetMachineStatus($id: ID!) {
machine(id: $id) {
name
status
oee { availability performance quality }
}
}
# Mutation — 修改数据(类比 POST/PUT/DELETE)
mutation UpdateMachineStatus($id: ID!, $status: MachineStatus!) {
updateMachine(id: $id, status: $status) {
id
status
updatedAt
}
}
# Subscription — 实时订阅(WebSocket)
subscription OnAlertAdded($lineId: ID!) {
alertAdded(lineId: $lineId) {
id
severity
message
createdAt
}
}
6.1 单体 vs 微服务
一个模块挂了全部挂
User DB
Order DB
Pay DB
Inv DB
Msg Queue
ClickHouse
但引入分布式复杂性
单体 = 大工厂全在一个厂房:冲压、焊接、喷漆、总装全在一起。一台设备坏了可能影响整条线。
微服务 = 多个专业车间:冲压车间、焊接车间各自独立运作,通过传送带(消息队列)或物流车(REST/gRPC)协作。
6.2 服务拆分原则
- 按业务领域拆(DDD 限界上下文):用户域、订单域、支付域
- 高内聚低耦合:经常一起变化的放一起,很少一起变化的分开
- 独立数据存储:每个服务有自己的数据库,不共享
- 一个服务一个团队:康威定律 — 系统架构反映组织沟通结构
- 避免过细拆分:20 个服务可能太多了,从 5-8 个开始
6.3 服务通信方式
| 方式 | 协议 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| REST | HTTP/JSON | 外部 API、简单调用 | 通用、易调试 | 开销大、无强类型 |
| gRPC | HTTP/2 + Protobuf | 服务间高频调用 | 高性能、强类型 | 调试不便、浏览器不支持 |
| 消息队列 | AMQP/Kafka | 异步解耦、事件驱动 | 削峰填谷、松耦合 | 复杂度增加、最终一致性 |
6.4 服务发现 & API 网关
| 组件 | 工具 | 作用 |
|---|---|---|
| 服务发现 | Consul / Eureka / Nacos | 服务注册与发现,动态感知上下线 |
| API 网关 | Nginx / Kong / Spring Cloud Gateway | 统一入口:路由、限流、认证、日志 |
| 配置中心 | Apollo / Nacos / Consul | 集中管理各服务配置,动态刷新 |
| 链路追踪 | Jaeger / Zipkin / SkyWalking | 追踪请求在服务间的完整调用链 |
认证 · 限流 · 路由 · 日志
场景:某团队将系统拆成 20+ 微服务,一个用户请求涉及 6 个服务调用。出 Bug 时完全无法定位是哪个服务的问题。
根因:没有分布式追踪、没有统一日志、没有服务间调用可视化。
解决方案:
- 引入分布式追踪:每个请求生成 Trace ID,在各服务间传递
- 统一日志:ELK (Elasticsearch + Logstash + Kibana) 集中收集
- 服务网格:Istio/Linkerd 自动注入追踪信息
- 复盘:20 个服务是否合理?考虑合并一些过于碎片化的服务
// 在请求头中传递 Trace ID
app.use((req, res, next) => {
const traceId = req.headers['x-trace-id'] || uuid();
req.traceId = traceId;
res.setHeader('X-Trace-Id', traceId);
// 所有日志带上 traceId
logger.defaultMeta = { traceId };
next();
});
7.1 CAP 定理
| 选择 | 策略 | 典型系统 | 场景 |
|---|---|---|---|
| CP | 分区时宁可不可用也不返回旧数据 | Zookeeper, etcd, HBase | 金融交易、配置管理 |
| AP | 分区时保证可用但可能返回旧数据 | Cassandra, DynamoDB, Eureka | 社交、购物车、缓存 |
7.2 分布式事务
| 方案 | 原理 | 优点 | 缺点 | 适用 |
|---|---|---|---|---|
| 2PC 两阶段提交 |
协调者问所有参与者能不能提交 → 全部能 → 提交 | 强一致 | 同步阻塞、单点故障 | 数据库层面跨库事务 |
| TCC Try-Confirm-Cancel |
业务层面:预留资源(Try) → 确认(Confirm) 或 回滚(Cancel) | 柔性事务、高性能 | 每个操作要写3个方法、侵入性强 | 支付、金融核心 |
| Saga | 长事务拆成多个本地事务,每步失败执行补偿操作 | 无锁、可扩展 | 最终一致、补偿复杂 | 电商下单(库存+支付+物流) |
订单处理 = 下单 → 扣库存 → 支付 → 发物流 → 通知用户。
每步都是独立的本地事务。如果「支付」失败,就补偿:释放库存 → 取消订单。
不需要所有工序同时锁住(2PC),而是「做一步看一步,失败了往回退」。
7.3 熔断器模式 (Circuit Breaker)
监控失败率
返回降级响应
成功→关闭 失败→打开
7.4 服务降级策略
| 策略 | 做法 | 示例 |
|---|---|---|
| 返回默认值 | 用兜底数据响应 | 推荐系统挂了 → 返回热门商品 |
| 返回缓存 | 用上次成功的结果 | 价格服务挂了 → 返回缓存价格 |
| 功能关闭 | 关闭非核心功能 | 评价系统挂了 → 隐藏评价区域 |
| 排队等待 | 异步处理,稍后通知 | 高峰期下单 → 排队,短信通知结果 |
场景:电商系统的第三方支付网关宕机,所有支付请求超时,线程池耗尽导致整个系统雪崩。
解决方案:熔断 + 降级
// Resilience4j 熔断配置
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 失败率 50% 触发熔断
.waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断 30 秒
.slidingWindowSize(10) // 滑动窗口 10 次请求
.permittedNumberOfCallsInHalfOpenState(3) // 半开时放 3 个试探
.build();
// 降级逻辑
@CircuitBreaker(name = "payment", fallbackMethod = "payFallback")
public PaymentResult pay(Order order) {
return paymentClient.charge(order);
}
public PaymentResult payFallback(Order order, Exception e) {
// 降级方案 1:记录到数据库,稍后重试
pendingPaymentRepository.save(order);
// 降级方案 2:通知用户
notificationService.notify(order.getUserId(),
"支付系统繁忙,我们稍后自动重试");
return PaymentResult.queued(order.getId());
}
① 资源导向:URL 表示资源(名词),HTTP 方法表示操作(动词)
② 无状态:每次请求包含所有必要信息,服务端不保存客户端状态
③ 统一接口:GET/POST/PUT/DELETE 语义明确
④ 标准状态码:用 HTTP 状态码表达结果
⑤ HATEOAS(可选):响应中包含相关链接,实现自发现
PATCH:部分更新。只修改提供的字段,未提供的字段保持不变。
示例:更新用户
{ name: "Alice", age: 25, email: "a@b.com" }PUT
{ name: "Bob" } → 结果 { name: "Bob" }(age 和 email 丢失)PATCH
{ name: "Bob" } → 结果 { name: "Bob", age: 25, email: "a@b.com" }
/api/v1/users):最直观,但 URL 变长② 请求头(
Accept: application/vnd.api.v2+json):URL 干净,但调试不方便③ 查询参数(
?version=2):最简单,但不 RESTful推荐:大多数团队用 URL 路径,简单且被广泛理解。
GET /api/v1/orders?
status=active // 过滤:只看活跃订单
&created_after=2026-01-01 // 范围过滤
&sort=-created_at,priority // 排序:- 表示降序
&page=2&size=20 // 分页:第2页,每页20条
响应体包含分页元信息:
{
"data": [...],
"pagination": {
"page": 2, "size": 20,
"total": 158, "total_pages": 8
}
}
403 Forbidden:已认证但无权限 — 「我知道你是谁,但你没权限。」
类比:401 = 没刷工牌进不去大楼;403 = 刷了工牌但你进不了机房(需要更高权限)。
. 连接。优点:无状态(不查 DB)、天然支持分布式、移动端友好
缺点:无法主动撤销(需黑名单)、Payload 明文可读(不要放敏感信息)、Token 体积比 Session ID 大
JWT:客户端存储,无状态,利于扩展,但难以主动撤销。
选择:传统 Web(服务端渲染)→ Session;API/移动端/微服务 → JWT。
为什么更安全:access_token 只在后端和服务端之间传递,不经过浏览器,JavaScript 无法获取。隐式模式直接在浏览器返回 token,容易被 XSS 窃取。
① 限流 (Rate Limiting):按 IP/用户/接口维度限制频率(令牌桶/滑动窗口)
② IP 黑名单:WAF/网关层封禁恶意 IP
③ 认证 + 授权:接口必须认证,避免匿名滥用
④ 验证码:高频操作前加入人机验证
⑤ 监控告警:异常流量模式检测,自动触发防护
⑥ API Key 白名单:只允许已注册的客户端调用
解决方式:服务端在响应头中添加
Access-Control-Allow-Origin 等头信息。复杂请求(PUT/DELETE/自定义头)会先发 OPTIONS 预检请求。生产环境:精确指定 origin,不要用
*。
GraphQL:查询导向,单一端点,客户端按需获取字段。适合多端差异化需求、复杂嵌套数据。
选择:后台管理/简单 API → REST;BFF (Backend for Frontend)/多端复杂需求 → GraphQL。
微服务:独立部署、独立扩展、技术栈灵活。但引入分布式复杂性(网络延迟、数据一致性、调试困难)。
关键:不要为了微服务而微服务。小项目/团队小 → 单体更合适;大团队/大项目 → 微服务值得投入。
② gRPC (HTTP/2 + Protobuf):高性能二进制协议,强类型,适合服务间高频调用
③ 消息队列 (Kafka/RabbitMQ):异步解耦,削峰填谷,适合事件驱动场景,但增加复杂度
实践:同步调用用 gRPC,异步通信用消息队列,对外暴露用 REST。
解决的问题:
① 统一认证:在网关层做认证,各服务不用重复实现
② 路由转发:根据路径/头部将请求路由到对应服务
③ 限流熔断:在入口层统一保护后端服务
④ 协议转换:外部 REST → 内部 gRPC
⑤ 日志监控:统一记录请求日志和指标
常见方案:Nginx、Kong、Spring Cloud Gateway、Traefik。
网络分区(P)是不可避免的,所以实际是在 CP 和 AP 之间选择:
- CP(如 Zookeeper、etcd):分区时宁可不可用也要保证数据一致。适合配置管理、分布式锁。
- AP(如 Cassandra、Eureka):分区时保证可用但可能返回旧数据。适合社交、购物车。
BASE 理论:大多数互联网系统选择 AP + 最终一致性。
② TCC(Try-Confirm-Cancel):业务层面实现 Try(预留)/Confirm(确认)/Cancel(回滚)。高性能但侵入性强。
③ Saga:将长事务拆成多个本地短事务,每步有补偿操作。最终一致,适合电商、物流等业务流程。
④ 本地消息表:将消息持久化到本地 DB,定时扫描发送。简单可靠。
实践:尽量用最终一致性,避免强一致分布式事务。
三态:
① CLOSED(关闭):正常放行请求,同时统计失败率
② OPEN(打开):失败率超阈值,直接拒绝请求(快速失败),返回降级响应
③ HALF-OPEN(半开):超时后放少量请求试探,成功则关闭,失败则继续打开
实现框架:Resilience4j(推荐)、Sentinel、Hystrix(已停更)。
② 返回缓存:价格服务挂了 → 返回上次缓存的价格
③ 功能关闭:评价服务挂了 → 隐藏评价区域
④ 写队列:下单高峰 → 写入消息队列异步处理
⑤ 限流降级:超量请求直接返回「系统繁忙」
服务发现:服务启动时注册自己的地址到注册中心,调用方从注册中心查询目标服务地址。
- Consul:支持健康检查 + KV 存储,Go 生态
- Eureka:Netflix 开源,Spring Cloud 生态
- Nacos:阿里开源,支持 AP/CP 切换,国内主流
调用流程:Service A → 查注册中心 → 获取 Service B 地址 → 发起调用
实现:
① 入口网关生成 Trace ID,放入请求头
X-Trace-Id② 每个服务从请求头取出 Trace ID,记录日志并传递给下游
③ 所有服务日志集中收集(ELK/ClickHouse),按 Trace ID 检索完整链路
工具:Jaeger、Zipkin、SkyWalking。云原生环境可用 Istio 自动注入。
GET、PUT、DELETE 天然幂等。POST 不是幂等的(重复提交会创建多条记录)。
如何保证 POST 幂等:
① 客户端生成幂等 Key(
Idempotency-Key 请求头),服务端记录已处理的 Key② 数据库唯一约束,重复插入会报错
③ Token 机制:先获取 token,提交时消费 token
① 避免分布式事务:合理拆分服务边界,让事务在单个服务内完成
② 事件驱动 + 最终一致性:服务 A 完成操作后发布事件,服务 B 监听并处理
③ Saga 模式:编排多个本地事务,每步有补偿操作
④ 本地消息表:将事件持久化到本地 DB,确保消息不丢失
黄金法则:能不用分布式事务就不用。最终一致性 > 强一致性。
② 滑动窗口:按时间滑动统计,解决临界问题
③ 漏桶:请求以恒定速率处理(匀速出水),削峰填谷,但无法应对合理突发
④ 令牌桶:以恒定速率生成令牌,请求消耗令牌。允许突发(桶里有累积的令牌),是生产环境首选
区别:漏桶 = 请求匀速处理;令牌桶 = 允许一定突发后匀速恢复。
防止策略:
① 熔断器:下游异常率过高时快速失败,不阻塞线程
② 超时设置:设置合理的连接超时和读超时
③ 限流:限制并发请求数,保护线程池
④ 舱壁模式:不同服务使用隔离的线程池/连接池,故障不蔓延
⑤ 降级:故障时返回兜底响应,保证核心功能可用
- DNS 轮询 / CDN 加速
- 负载均衡(Nginx / 云 LB)多实例部署
- API Gateway 统一认证、限流、路由
应用层:
- 无状态设计(JWT),支持水平扩展
- 熔断 + 降级 + 超时(Resilience4j)
- 健康检查 + 自动重启
数据层:
- 主从复制 / 读写分离
- Redis 缓存 + 热点数据本地缓存
- 消息队列削峰填谷
运维层:
- 全链路监控 + 告警(Prometheus + Grafana)
- 日志集中收集(ELK)
- 自动扩缩容(K8s HPA)
共 8 个章节 · 10+ CSS 图表 · 25 道面试题 · 6 个生产案例