vault backup: 2026-05-05 20:20:15
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
---
|
||||
tags: [microservice, api-gateway, kong, apisix, spring-cloud-gateway]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# API 网关
|
||||
|
||||
## 概述
|
||||
|
||||
API Gateway 是所有外部请求的统一入口,承担以下职责:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Client["客户端 App / Web"] --> GW["API Gateway"]
|
||||
GW --> Auth["鉴权 & 限流"]
|
||||
GW --> Route["路由转发"]
|
||||
GW --> Transform["协议转换"]
|
||||
GW --> Log["日志 & 监控"]
|
||||
GW -.-> CB[(配置中心)]
|
||||
```
|
||||
|
||||
常见实现:**Kong、APISIX、Spring Cloud Gateway、Nginx + Lua**。
|
||||
|
||||
## 网关应该做什么?
|
||||
|
||||
> [!summary] 网关职责清单
|
||||
|
||||
| ✅ 适合放 | ❌ 不应该放 |
|
||||
|---------|-----------|
|
||||
| 鉴权与认证 | 业务逻辑(如订单创建) |
|
||||
| 限流熔断 | 复杂的数据聚合查询 |
|
||||
| HTTPS 终结 | 大量 CPU 密集型计算 |
|
||||
| 请求/响应转换 | 涉及数据库写操作 |
|
||||
| 路由分发 | 跨服务事务管理 |
|
||||
| 日志 & 监控 | 邮件/短信发送等异步任务 |
|
||||
|
||||
> [!tip] 核心原则
|
||||
> **网关保持瘦**——它是 traffic cop(交通警察),不是 warehouse manager(仓库管理员)。重逻辑应下沉到业务服务。
|
||||
|
||||
### 分层鉴权模型
|
||||
|
||||
> [!question] 权衡题
|
||||
> 有人说:"鉴权放到网关统一做,避免每个服务重复写。"但如果某个内部服务不需要鉴权呢?或者不同团队要求不同的鉴权方式呢?
|
||||
|
||||
**分层鉴权架构**:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
External["外部用户"] --> GW["API Gateway<br/>JWT 校验 + OAuth2"]
|
||||
GW --> S1[公开接口<br/>无需额外鉴权]
|
||||
GW --> S2[内部接口<br/>Service Token]
|
||||
|
||||
S1 --> UserSvc[[User Service]]
|
||||
S2 --> OrderSvc[[Order Service]]
|
||||
S2 --> PaySvc[[Payment Service]]
|
||||
|
||||
OrderSvc -->|"mTLS + JWT"| DB[(DB)]
|
||||
PaySvc -->|"mTLS + JWT"| DB
|
||||
```
|
||||
|
||||
- **第一层(网关)**:校验外部用户的 JWT/OAuth Token,拦截非法请求
|
||||
- **第二层(服务间)**:通过 Service Token 或 mTLS 保证调用方身份可信
|
||||
- **第三层(数据层)**:RBAC / ABAC 细粒度权限控制
|
||||
|
||||
## 路由策略
|
||||
|
||||
### 基础路由规则
|
||||
|
||||
```yaml
|
||||
# APISIX 路由示例
|
||||
routes:
|
||||
- uri: /api/orders/*
|
||||
upstream:
|
||||
nodes:
|
||||
"order-service:8080": 1
|
||||
type: roundrobin
|
||||
|
||||
- uri: /api/payments/*
|
||||
upstream:
|
||||
nodes:
|
||||
"payment-service:8080": 1
|
||||
type: roundrobin
|
||||
```
|
||||
|
||||
### 高级路由策略
|
||||
|
||||
| 策略 | 场景 | 示例 |
|
||||
|------|------|------|
|
||||
| **路径匹配** | 按 URL 前缀路由 | `/api/v1/*` → v1 版本服务 |
|
||||
| **Header 匹配** | A/B 测试、灰度发布 | `x-canary: true` → 新版本 |
|
||||
| **权重路由** | 金丝雀发布 | 90% 流量 → v1, 10% → v2 |
|
||||
| **正则匹配** | 复杂 URL 模式 | `/api/user/(?P<id>\d+)/*` |
|
||||
|
||||
## 网关插件体系
|
||||
|
||||
网关的核心价值在于 **可插拔的中间件链**,类似 Express/Koa 的 middleware 概念。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Req["Request"] -->|Plugin 1| RateLimiter["限流"]
|
||||
RateLimiter -->|Plugin 2| Auth["鉴权"]
|
||||
Auth -->|Plugin 3| CBR["熔断"]
|
||||
CBR -->|Plugin 4| Transform["协议转换"]
|
||||
Transform -->|Plugin 5| Logger["日志"]
|
||||
Logger --> Backend["Backend Service"]
|
||||
```
|
||||
|
||||
### 常用插件列表
|
||||
|
||||
| 插件 | 作用 | 推荐算法 |
|
||||
|------|------|---------|
|
||||
| **Rate Limiting** | 防刷限流 | 令牌桶 / 漏桶 |
|
||||
| **CORS** | 跨域处理 | 预检缓存 |
|
||||
| **IP 黑白名单** | 访问控制 | Redis Bloom Filter |
|
||||
| **Response Rewrite** | 修改响应体 | JSON Patch |
|
||||
| **Request Transformation** | Header/Body 改写 | Map-based |
|
||||
| **Prometheus Exporter** | 指标采集 | 自动埋点 |
|
||||
| **Fault Injection** | 混沌测试注入延迟/错误 | 按比例注入 |
|
||||
|
||||
## 网关的高可用设计
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
DNS["DNS / CLB"] --> GW1["Gateway Node 1"]
|
||||
DNS --> GW2["Gateway Node 2"]
|
||||
|
||||
subgraph GW_Cluster["网关集群"]
|
||||
GW1
|
||||
GW2
|
||||
end
|
||||
|
||||
GW1 --> B1["backend-pool-v1"]
|
||||
GW2 --> B2["backend-pool-v1"]
|
||||
|
||||
B1 --> Svc1[[order-service]]
|
||||
B1 --> Svc2[[user-service]]
|
||||
B2 --> Svc1
|
||||
B2 --> Svc2
|
||||
|
||||
GW1 -.-> Config["配置中心 (同步)"]
|
||||
GW2 -.-> Config
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- 网关无状态设计,可横向扩展
|
||||
- 配置通过注册中心实时同步,无需重启
|
||||
- 多节点前接负载均衡器(CLB/Nginx)
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/服务发现/README]] — 网关需要订阅服务实例列表
|
||||
- [[02-服务治理/流量治理/README]] — 高级路由和灰度发布的延伸
|
||||
- [[hzh/MS/API 设计原则]] — API Gateway 的设计与 REST/gRPC 选型
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
tags: [microservice, service-governance]
|
||||
create time: 2026-04-29 12:02
|
||||
---
|
||||
|
||||
# 服务治理
|
||||
|
||||
## 概述
|
||||
|
||||
服务治理是微服务架构的"操作系统"——它不直接实现业务逻辑,但决定了系统能否在复杂、高并发、多团队协作的环境中稳定运转。
|
||||
|
||||
> [!question] 开篇思考
|
||||
> 假设你有 10 个微服务,每个服务有 3 个实例,总共 30 个服务实例。手动维护它们的地址列表会带来哪些问题?你能想到几种解决方案?
|
||||
|
||||
答案藏在下面每一个章节里——从服务发现到流量治理,每一层都在解决特定维度的复杂度。
|
||||
|
||||
## 知识体系
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A["服务发现"] --> B["API 网关"]
|
||||
B --> C["服务间通信"]
|
||||
C --> D["容错模式"]
|
||||
D --> E["配置管理"]
|
||||
E --> F["分布式追踪"]
|
||||
F --> G["流量治理"]
|
||||
G --> H["安全机制"]
|
||||
```
|
||||
|
||||
| # | 主题 | 核心问题 |
|
||||
|---|------|----------|
|
||||
| 1 | [[02-服务治理/服务发现/README]] | 服务如何找到彼此?注册中心的工作原理是什么? |
|
||||
| 2 | [[02-服务治理/API网关/README]] | 统一入口承担哪些职责?网关应该瘦还是胖? |
|
||||
| 3 | [[02-服务治理/服务间通信/README]] | RPC vs RESTful?同步 vs 异步怎么选? |
|
||||
| 4 | [[02-服务治理/容错模式/README]] | 网络不可靠,故障怎么隔离和恢复? |
|
||||
| 5 | [[02-服务治理/配置管理/README]] | 上百个服务的配置如何统一管理? |
|
||||
| 6 | [[02-服务治理/分布式追踪/README]] | 请求穿越多个服务后,如何追踪链路? |
|
||||
| 7 | [[02-服务治理/流量治理/README]] | 灰度发布如何做?高级路由策略有哪些? |
|
||||
| 8 | [[02-服务治理/安全机制/README]] | 服务间调用如何认证和授权?mTLS 是什么? |
|
||||
|
||||
### 学习建议
|
||||
|
||||
> [!tip] 学习路径
|
||||
> 按编号顺序阅读。前三个主题是理解服务治理的基础,后面的容错、配置、追踪是在此之上的稳定性保障。
|
||||
|
||||
> [!question] 带着问题读
|
||||
> 每篇文章都设计了启发式问题。先自己想一遍答案,再看文档,效果更好。
|
||||
|
||||
### 关联笔记
|
||||
|
||||
- [[01-基础概念]] — 微服务的整体架构认知
|
||||
- [[03-数据一致性]] — 服务调用链路上的数据一致性问题
|
||||
- [[04-可观测性]] — 日志、指标、链路追踪的完整体系
|
||||
- [[05-部署运维]] — K8s Service 天然提供负载均衡和服务发现
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
tags: [microservice, distributed-tracing, opentelemetry, jaeger, skywalking]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 分布式链路追踪
|
||||
|
||||
## 概述
|
||||
|
||||
单个服务的日志只能告诉你局部信息。分布式链路追踪将一次请求跨越多个服务的完整调用链串起来,形成全局视图。
|
||||
|
||||
> [!question] 定位问题的困难
|
||||
> 用户反映下单慢,你的系统由订单、支付、库存、会员 4 个服务串联而成。没有工具的情况下,你要怎么知道是哪个服务拖慢了整体响应时间?
|
||||
|
||||
## 核心概念
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Req["请求 trace_id=abc123"] --> Span1["Span #1<br/>API Gateway<br/>5ms"]
|
||||
Span1 --> Span2["Span #2<br/>Order Service<br/>70ms"]
|
||||
Span1 --> Span3["Span #3<br/>User Service<br/>15ms"]
|
||||
Span2 --> Span4["Span #4<br/>Inventory DB Query<br/>60ms"]
|
||||
|
||||
style Span2 fill:#ff9999
|
||||
style Span4 fill:#ffcc99
|
||||
```
|
||||
|
||||
| 概念 | 说明 |
|
||||
|------|------|
|
||||
| **Trace** | 一次完整请求的调用链,由一个唯一的 `trace_id` 标识 |
|
||||
| **Span** | 链路中的一个执行片段(如一次 HTTP 调用、一次 SQL 查询),有独立的 `span_id` |
|
||||
| **Parent-Child** | Span 之间通过 `parent_span_id` 建立父子关系,形成树状结构 |
|
||||
| **Context Propagation** | 通过 Header 传递 `trace_id`/`span_id`,贯穿整条链路 |
|
||||
| **Sampling** | 不是每条请求都采样,按比例或策略选择,降低存储开销 |
|
||||
|
||||
### Trace/Span 数据结构
|
||||
|
||||
```json
|
||||
{
|
||||
"traceId": "abc123def456...",
|
||||
"spans": [
|
||||
{
|
||||
"spanId": "span-001",
|
||||
"parentId": null,
|
||||
"operationName": "POST /orders",
|
||||
"startTime": "2026-05-05T10:00:00.000Z",
|
||||
"durationMs": 120,
|
||||
"tags": {
|
||||
"http.method": "POST",
|
||||
"http.url": "/api/orders",
|
||||
"http.status_code": 200
|
||||
},
|
||||
"logs": [
|
||||
{
|
||||
"timestamp": "2026-05-05T10:00:00.050Z",
|
||||
"fields": [{"key": "event", "value": "order.created"}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"spanId": "span-002",
|
||||
"parentId": "span-001",
|
||||
"operationName": "GetUserById (gRPC)",
|
||||
"startTime": "2026-05-05T10:00:00.010Z",
|
||||
"durationMs": 15,
|
||||
"tags": {
|
||||
"rpc.system": "grpc",
|
||||
"rpc.service": "UserService",
|
||||
"rpc.method": "GetUser"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 上下文传播 (Context Propagation)
|
||||
|
||||
`trace_id` 如何从上游服务传递到下游?
|
||||
|
||||
### HTTP 场景:W3C Trace Context 标准
|
||||
|
||||
```json
|
||||
// HTTP Header 中实际传递的字段
|
||||
{
|
||||
"traceparent": "00-abc123def456...-789ghi012jkl-01",
|
||||
"tracestate": "congo=t61rcWkgMzE"
|
||||
}
|
||||
```
|
||||
|
||||
格式:`version-trace_id-span_id-flags`
|
||||
|
||||
```go
|
||||
// OpenTelemetry SDK 自动处理 context 注入和提取
|
||||
func Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 从入站请求提取 trace context
|
||||
ctx := propagator.Extract(r.Context(), headerReader{r.Header})
|
||||
|
||||
// 创建新的 span
|
||||
ctx, span := tracer.Start(ctx, "handleOrder")
|
||||
defer span.End()
|
||||
|
||||
// 将 trace context 注入到出站请求
|
||||
r = r.WithContext(ctx)
|
||||
propagator.Inject(ctx, headerWriter{r.Header})
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### MQ 场景:Message Header 透传
|
||||
|
||||
```go
|
||||
// RocketMQ 生产者 - 自动注入 trace context
|
||||
msg := rocketmq.NewMessage("order-created", payload)
|
||||
msg.WithProperty("trace_id", currentTraceID) // 手动注入
|
||||
msg.WithProperty("span_id", currentSpanID)
|
||||
|
||||
// RocketMQ 消费者 - 恢复 trace context
|
||||
traceID := msg.GetProperty("trace_id")
|
||||
span, _ := tracer.Start(ctx, "processOrderCreated",
|
||||
trace.WithSpanKind(trace.SpanKindConsumer))
|
||||
```
|
||||
|
||||
## 主流方案对比
|
||||
|
||||
| 方案 | 协议 | 存储后端 | 侵入程度 | 特色能力 |
|
||||
|------|------|---------|---------|---------|
|
||||
| **OpenTelemetry** | OTLP | Prometheus/Jaeger/Zipkin | SDK + Auto-Instrumentation | CNCF 标准,厂商中立,未来趋势 |
|
||||
| **Jaeger** | Jaeger native | Cassandra/Elasticsearch | Agent / SDK | Uber 开源,UI 友好,支持业务 Tags |
|
||||
| **SkyWalking** | SkyWalking | MySQL/Elasticsearch/ES | 零侵入 Java Agent | 国产,中文文档完善,APM 一体 |
|
||||
|
||||
> [!tip] 选型建议
|
||||
> 新项目优先选 **OpenTelemetry**——它是行业标准,未来会被所有工具支持。如果团队需要开箱即用的 APM,**SkyWalking** 的 Java Agent 零侵入方案是快速上手的最佳选择。
|
||||
|
||||
## OpenTelemetry Go 实战
|
||||
|
||||
```go
|
||||
// 初始化 TracerProvider
|
||||
provider := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithBatcherExporter(exporter), // 异步批量上报,不阻塞
|
||||
)
|
||||
defer provider.Shutdown(context.Background())
|
||||
|
||||
tracer := provider.Tracer("order-service")
|
||||
|
||||
func handleOrder(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := tracer.Start(r.Context(), "handleOrder")
|
||||
defer span.End()
|
||||
|
||||
// 设置丰富的属性,方便查询和过滤
|
||||
span.SetAttributes(
|
||||
attribute.String("http.method", r.Method),
|
||||
attribute.Int("http.status_code", http.StatusOK),
|
||||
attribute.String("user.id", getUserID(r)),
|
||||
)
|
||||
|
||||
// 调用下游服务(trace context 自动传播)
|
||||
resp, err := callInventoryService(ctx)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
w.Write(resp.Body)
|
||||
}
|
||||
```
|
||||
|
||||
## 采样策略
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
AllReq["全部请求"] --> Sampler{"采样决策"}
|
||||
Sampler -->|"100%"| Core["核心链路全量采集"]
|
||||
Sampler -->|"5~10%"| Normal["普通路径随机采样"]
|
||||
Sampler -->|"0%"| Health["健康检查/内部心跳"]
|
||||
|
||||
Core --> Storage["Trace 存储"]
|
||||
Normal --> Storage
|
||||
Health --> Drop["丢弃"]
|
||||
```
|
||||
|
||||
| 环境 | 采样率 | 理由 |
|
||||
|------|--------|------|
|
||||
| **开发 / 测试** | 100% | 方便调试,无存储压力 |
|
||||
| **生产 - 核心链路** | 100% | 下单、支付等关键路径必须全量 |
|
||||
| **生产 - 普通路径** | 5~10% | 平衡成本和覆盖率 |
|
||||
| **生产 - 错误链路** | 100% | 出错时的请求优先保留 |
|
||||
|
||||
> [!note] 基于错误的智能采样
|
||||
>
|
||||
> 高级做法:**正常路径低采样,一旦检测到错误立即提升当前请求的采样率**。这样既省了存储,又能在出问题时有足够的数据回溯。
|
||||
|
||||
## 渐进式落地路线
|
||||
|
||||
> [!tip] 不要试图一开始就采集全部 Span
|
||||
>
|
||||
> 1. **第一步**:先接 Tracing,覆盖核心链路(下单、支付),rate=100%
|
||||
> 2. **第二步**:加入 Metrics 监控(Prometheus + Grafana)
|
||||
> 3. **第三步**:集中 Logging(Loki / ELK),与 trace_id 关联
|
||||
> 4. **第四步**:全量上 OpenTelemetry Collector,统一管理
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/API网关/README]] — API Gateway 可以在入口处注入 trace_id
|
||||
- [[04-可观测性/链路追踪/README]] — 更详细的链路追踪设计方法论
|
||||
- [[02-服务治理/配置管理/README]] — 配置中心的动态刷新可以联动调整采样率
|
||||
@@ -0,0 +1,181 @@
|
||||
---
|
||||
tags: [microservice, security, mTLS, JWT, OAuth2, zero-trust]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 安全机制
|
||||
|
||||
## 概述
|
||||
|
||||
微服务架构下,服务间通信的安全保障比单体应用复杂得多。每个服务的 API 都是潜在的攻击面,需要多层防御。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "防御层"
|
||||
L1["L1: 网络隔离<br/>VPC / 安全组"]
|
||||
L2["L2: 传输加密<br/>mTLS / TLS"]
|
||||
L3["L3: 身份认证<br/>JWT / Service Token"]
|
||||
L4["L4: 授权控制<br/>RBAC / ABAC"]
|
||||
L5["L5: 审计追踪<br/>操作日志"]
|
||||
end
|
||||
|
||||
L1 -.-> L2 -.-> L3 -.-> L4 -.-> L5
|
||||
```
|
||||
|
||||
> [!tip] Zero Trust 原则
|
||||
> **永不信任,始终验证**。每个服务调用都要经过认证和授权,无论请求来自内网还是外网。
|
||||
|
||||
## 服务间认证
|
||||
|
||||
### mTLS (双向 TLS)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as 调用方 Service
|
||||
participant CA as Certificate Authority
|
||||
participant Svc as 被调方 Service
|
||||
|
||||
Client->>CA: 申请证书 (SPIFFE ID)
|
||||
Svc->>CA: 申请证书 (SPIFFE ID)
|
||||
|
||||
Client->>Svc: TLS Handshake + ClientCert
|
||||
Svc->>Svc: 验证书 + SPIFFE ID
|
||||
Svc-->>Client: ✅ 认证成功
|
||||
|
||||
note over Client,Svc: 建立加密通道
|
||||
```
|
||||
|
||||
**mTLS 的核心优势**:
|
||||
- 双方都持有对方可验证的证书,防止中间人攻击
|
||||
- 证书自动轮换(配合 Istio/Linkerd 等服务网格)
|
||||
- 零代码侵入——Sidecar 代理处理握手
|
||||
|
||||
### JWT / Service Token
|
||||
|
||||
适用于不具备 mTLS 基础设施的场景:
|
||||
|
||||
```go
|
||||
// 生成 Service Token
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"sub": "order-service", // 服务标识
|
||||
"iss": "auth-server", // 签发者
|
||||
"aud": "payment-service", // 目标服务
|
||||
"exp": time.Now().Add(1*time.Hour).Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
})
|
||||
tokenString, _ := token.SignedString(secretKey)
|
||||
```
|
||||
|
||||
| 方案 | 安全性 | 复杂度 | 适用场景 |
|
||||
|------|--------|--------|---------|
|
||||
| **mTLS** | ⭐⭐⭐⭐⭐ | 中(需 PKI 基础设施) | 服务网格环境、K8s 内部通信 |
|
||||
| **JWT + Shared Secret** | ⭐⭐⭐⭐ | 低 | 中小规模,快速上手 |
|
||||
| **mTLS + JWT** | ⭐⭐⭐⭐⭐ | 中高 | 金融级安全要求 |
|
||||
|
||||
> [!tip] 最佳实践
|
||||
> 在生产环境中,推荐 **mTLS + JWT 双层防护**:mTLS 保证通道安全,JWT 传递调用方的身份信息(谁在调用)。
|
||||
|
||||
## API 鉴权模型
|
||||
|
||||
### RBAC (基于角色的访问控制)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User["用户"] -->|"拥有"| Role["角色"]
|
||||
Role -->|"拥有"| Permission["权限"]
|
||||
Permission -->|"访问"| Resource["资源"]
|
||||
|
||||
Admin["Admin"] --> ReadWrite
|
||||
Editor["Editor"] --> ReadWrite
|
||||
Viewer["Viewer"] --> ReadOnly
|
||||
|
||||
ReadWrite --> OrderCRUD
|
||||
ReadOnly --> OrderRead
|
||||
|
||||
OrderCRUD --> CRUD["Create/Read/Update/Delete"]
|
||||
OrderRead --> Read["Read Only"]
|
||||
```
|
||||
|
||||
### ABAC (基于属性的访问控制)
|
||||
|
||||
适合细粒度场景:
|
||||
|
||||
```go
|
||||
func canAccess(user User, resource Resource, action string) bool {
|
||||
// 属性比较规则
|
||||
rules := []Rule{
|
||||
{
|
||||
Condition: user.Department == resource.Department, // 同部门
|
||||
Action: "read",
|
||||
},
|
||||
{
|
||||
Condition: user.Role == "admin" || user.ID == resource.OwnerID,
|
||||
Action: "write",
|
||||
},
|
||||
}
|
||||
|
||||
for _, r := range rules {
|
||||
if r.Condition && r.Action == action {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
## 输入校验与防攻击
|
||||
|
||||
### SQL 注入防护
|
||||
|
||||
```go
|
||||
// ❌ 危险:字符串拼接
|
||||
query := fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", userInput)
|
||||
|
||||
// ✅ 安全:参数化查询
|
||||
rows, err := db.Query("SELECT * FROM users WHERE name = ?", userInput)
|
||||
```
|
||||
|
||||
### XSS 防护
|
||||
|
||||
```go
|
||||
// Go HTML template 自动转义
|
||||
tpl.ExecuteTemplate(w, "page.html", data) // {{.Name}} 自动 HTML 转义
|
||||
|
||||
// JSON API 天然免疫(Content-Type: application/json)
|
||||
```
|
||||
|
||||
### 常见攻击防护清单
|
||||
|
||||
| 威胁 | 防护手段 | 实现位置 |
|
||||
|------|---------|---------|
|
||||
| **SQL 注入** | 参数化查询 / ORM | 数据访问层 |
|
||||
| **XSS** | 输出转义 / CSP Header | Web 框架 / Gateway |
|
||||
| **CSRF** | SameSite Cookie / CSRF Token | 网关 / Session |
|
||||
| **DDoS** | 限流 + WAF | API Gateway |
|
||||
| **重放攻击** | Nonce + Timestamp | API 签名 |
|
||||
| **凭证泄露** | HTTPS + Secure Cookie | 传输层 |
|
||||
|
||||
## API 签名(防重放攻击)
|
||||
|
||||
对高安全要求的 API,客户端需要对请求签名:
|
||||
|
||||
```
|
||||
Signature = HMAC-SHA256(Secret, HTTP_Method + URL + Timestamp + Body)
|
||||
```
|
||||
|
||||
```
|
||||
GET /api/orders?userId=123×tamp=1714900000&nonce=abc123
|
||||
↓ 用 Secret 做 HMAC-SHA256 签名
|
||||
a1b2c3d4e5f6...
|
||||
```
|
||||
|
||||
服务端验证步骤:
|
||||
1. 检查 `timestamp` 是否在允许窗口内(如 ±5 分钟)
|
||||
2. 检查 `nonce` 是否已使用(Redis SetNX,TTL 5min)
|
||||
3. 用同样的算法计算签名,比对是否一致
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/API网关/README]] — 网关层的统一鉴权和限流
|
||||
- [[02-服务治理/服务发现/README]] — 服务注册时也需要安全认证
|
||||
- [[hzh/MS/API 设计原则]] — API 设计中的安全考量
|
||||
@@ -0,0 +1,288 @@
|
||||
---
|
||||
tags: [microservice, circuit-breaker, retry, rate-limiting, bulkhead, health-check]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 容错模式
|
||||
|
||||
## 概述
|
||||
|
||||
微服务最大的挑战是 **网络不可靠**。分布式系统的每个远程调用都可能超时、被拒绝、或部分成功。必须提前设计降级和恢复策略。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A["🛡️ 超时控制"] --> B["⏱ 重试机制"]
|
||||
B --> C["⚡ 熔断器"]
|
||||
C --> D["🔀 限流"]
|
||||
D --> E["🧱 舱壁隔离"]
|
||||
E --> F["💤 降级策略"]
|
||||
```
|
||||
|
||||
> [!warning] 核心认知
|
||||
> 不要假设任何网络调用会成功。每个远程调用的代码都应该考虑失败路径。
|
||||
|
||||
## 1. 超时控制
|
||||
|
||||
这是所有容错机制的**前提**——没有超时的系统迟早会被拖垮。
|
||||
|
||||
```go
|
||||
// Go context 超时时序图
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
resp, err := client.DoRequest(ctx, req)
|
||||
if err == context.DeadlineExceeded {
|
||||
// 上游超时 → 走降级逻辑或快速返回错误
|
||||
}
|
||||
```
|
||||
|
||||
| 层级 | 推荐超时值 | 说明 |
|
||||
|------|-----------|------|
|
||||
| HTTP 客户端 → 业务服务 | 3~5s | 留有余量给下游 |
|
||||
| gRPC → 内部服务 | 1~2s | 内网延迟低 |
|
||||
| DB 查询 | 500ms~1s | 长查询应在 SQL 层限制 |
|
||||
|
||||
> [!tip] 超时传递原则
|
||||
> 如果整体 SLA 要求 P99 < 200ms,子调用的超时时间必须逐层递减。例如:网关 200ms → 订单服务 150ms → 库存服务 80ms。
|
||||
|
||||
## 2. 重试机制
|
||||
|
||||
> [!warning] 关键原则
|
||||
> 只对 **幂等操作** 重试!POST 创建操作直接重试会导致重复数据。GET、PUT(同参数)适合重试。
|
||||
|
||||
### 指数退避 + Jitter
|
||||
|
||||
```
|
||||
第 1 次重试:等待 1s + random(0~100ms)
|
||||
第 2 次重试:等待 2s + random(0~100ms)
|
||||
第 3 次重试:等待 4s + random(0~100ms)
|
||||
...
|
||||
```
|
||||
|
||||
```go
|
||||
func retryWithBackoff(ctx context.Context, maxRetries int, fn func() error) error {
|
||||
for attempt := uint(0); attempt <= uint(maxRetries); attempt++ {
|
||||
if err := fn(); err != nil {
|
||||
if attempt == uint(maxRetries) {
|
||||
return err
|
||||
}
|
||||
// jitter: 随机偏移,避免所有客户端同时重试造成二次冲击
|
||||
jitter := time.Duration(rand.Int63n(int64(time.Millisecond * 100)))
|
||||
wait := time.Duration(math.Pow(2, float64(attempt)))*time.Second + jitter
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-time.After(wait):
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
**Jitter 为什么重要?**
|
||||
- 如果没有随机偏移,当某个下游服务挂掉时,所有客户端会在同一时刻同时重试
|
||||
- 这会造成 **retry storm(重试风暴)**,对恢复中的服务施加二次冲击
|
||||
- 加上 jitter 后,请求均匀分散到时间窗口内
|
||||
|
||||
### 可重试 vs 不可重试的错误类型
|
||||
|
||||
| 可以重试 | 不应重试 |
|
||||
|---------|---------|
|
||||
| 连接超时 | 4xx Client Error(除 429) |
|
||||
| 连接重置 | 404 Not Found |
|
||||
| 502/503/504 Gateway Error | 业务错误(如余额不足) |
|
||||
| 并发冲突(乐观锁失败) | 403 Forbidden |
|
||||
|
||||
## 3. 熔断器 (Circuit Breaker)
|
||||
|
||||
当下游服务频繁失败时,快速失败避免线程堆积雪崩。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
CB{{🔘 CIRCUIT BREAKER}}
|
||||
|
||||
subgraph CL ["CLOSED — 正常"]
|
||||
C["请求放行<br/>⏱ 实时统计成功率<br/>⚠️ 连续失败 → 熔断"]
|
||||
end
|
||||
|
||||
subgraph OP ["OPEN — 熔断"]
|
||||
O["🚫 请求短路<br/>💥 直接返回降级响应<br/>🛡 不调下游,防雪崩"]
|
||||
end
|
||||
|
||||
subgraph HO ["HALF-OPEN — 探测"]
|
||||
H["🔍 放行少量探测请求<br/>✅ 成功 → 恢复全量流量<br/>❌ 失败 → 重新熔断"]
|
||||
end
|
||||
|
||||
CB --> CL
|
||||
CL -.->|失败 > N| OP
|
||||
OP -.->|等待超时| HO
|
||||
HO -->|探测成功| CL
|
||||
HO -->|探测失败| OP
|
||||
|
||||
style CL fill:#e6f9e6,stroke:#4caf50,stroke-width:3px,color:#000
|
||||
style OP fill:#ffebee,stroke:#ef5350,stroke-width:3px,color:#000
|
||||
style HO fill:#fff8e1,stroke:#ffa726,stroke-width:3px,color:#000
|
||||
```
|
||||
|
||||
### 状态转换条件
|
||||
|
||||
| 状态 | 触发条件 | 行为 | 退出条件 |
|
||||
|------|---------|------|---------|
|
||||
| **Closed** | 初始状态 / 从 Half-Open 恢复 | 正常放行请求 | 连续失败数 > threshold → 打开 |
|
||||
| **Open** | 失败率超过阈值 | 立即短路返回错误 | 等待 recoveryTimeout → 进入半开 |
|
||||
| **Half-Open** | 探测期 | 放少量请求测试 | 探测成功 → Closed;探测失败 → Open |
|
||||
|
||||
### 实战示例
|
||||
|
||||
```go
|
||||
// gobreaker 示例
|
||||
cb := state.NewCB(state.Settings{
|
||||
Name: "UserService",
|
||||
MaxElems: 10, // 窗口大小
|
||||
WaitRetry: 5 * time.Second, // Open → Half-Open 等待时间
|
||||
ReadyToTrip: func(counts state.Counters) bool {
|
||||
return counts.Failures > 5 // 连续 5 次失败熔断
|
||||
},
|
||||
})
|
||||
|
||||
result := cb.Execute(doRequest)
|
||||
if result.Err != nil {
|
||||
// 熔断打开,立即短路返回错误,不调用下游
|
||||
return fallbackResponse()
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 限流 (Rate Limiting)
|
||||
|
||||
保护下游服务不被过量请求压垮。
|
||||
|
||||
### 常见算法
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph "令牌桶"
|
||||
T1["匀速添加令牌"]
|
||||
T2["请求消耗令牌"]
|
||||
T3["不够则拒绝"]
|
||||
end
|
||||
|
||||
subgraph "滑动窗口"
|
||||
S1["按时间片切分"]
|
||||
S2["统计每片请求数"]
|
||||
S3["超过阈值则拒绝"]
|
||||
end
|
||||
```
|
||||
|
||||
| 算法 | 特点 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| **固定窗口** | 简单实现,存在边界突发问题 | 低频场景 |
|
||||
| **滑动窗口** | 精确控制,内存占用高 | 需要精细限流的场景 |
|
||||
| **令牌桶** | 允许一定突发,平均速率受限 | API 网关通用方案 |
|
||||
| **漏桶** | 强制匀速输出,不允突发 | 防止下游被打满 |
|
||||
|
||||
### 限流层级
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Client["客户端"] --> GW["L1: 网关级限流<br/>防刷 / DDOS"]
|
||||
GW --> Biz["L2: 业务级限流<br/>按用户/接口配额"]
|
||||
Biz --> Downstream["L3: 下游服务限流<br/>保护实例不被打满"]
|
||||
|
||||
style GW fill:#ffebee
|
||||
style Biz fill:#fff3e0
|
||||
style Downstream fill:#e8f5e9
|
||||
```
|
||||
|
||||
## 5. 舱壁隔离 (Bulkhead)
|
||||
|
||||
为不同下游服务分配独立的线程池/连接池,防止一个服务的故障蔓延到其他服务。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Caller["调用方"]
|
||||
|
||||
subgraph Bulkhead["舱壁隔离"]
|
||||
Pool1[订单池<br/>maxActive=10]
|
||||
Pool2[用户池<br/>maxActive=5]
|
||||
Pool3[支付池<br/>maxActive=8]
|
||||
end
|
||||
|
||||
Caller --> Pool1
|
||||
Caller --> Pool2
|
||||
Caller --> Pool3
|
||||
|
||||
Pool1 --> OrderSvc[[Order Service]]
|
||||
Pool2 --> UserSvc[[User Service]]
|
||||
Pool3 --> PaySvc[[Payment Service]]
|
||||
|
||||
note[订单服务爆满不会影响用户服务的调用]
|
||||
Pool1 -.-> note
|
||||
```
|
||||
|
||||
```go
|
||||
// poolgroup 示例:为不同服务隔离连接池
|
||||
orderPool := pool.New(10, 100) // 活跃10个,上限100个
|
||||
userPool := pool.New(5, 50)
|
||||
payPool := pool.New(8, 80)
|
||||
// 订单服务占满连接不会影响用户服务的调用
|
||||
```
|
||||
|
||||
## 6. 降级策略
|
||||
|
||||
当系统部分不可用时,通过降级保证核心功能可用。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Req["用户请求"]
|
||||
|
||||
Req --> Normal{"正常链路是否可用?"}
|
||||
|
||||
Normal -- 是 --> Full["完整功能 ✅"]
|
||||
|
||||
Normal -- 否 --> Degrade{"降级级别?"}
|
||||
|
||||
Degrade -- "非核心模块" --> Skip["跳过该功能 ⚡"]
|
||||
Degrade -- "核心模块不可用" --> Cache["返回缓存兜底 📦"]
|
||||
|
||||
Cache -- "无缓存" --> Default["返回默认值/提示页"]
|
||||
|
||||
Skip --> Partial["部分可用 ✅"]
|
||||
Default --> Minimal["最低可用 ✅"]
|
||||
```
|
||||
|
||||
### 常见降级场景
|
||||
|
||||
| 场景 | 降级方案 | 影响 |
|
||||
|------|---------|------|
|
||||
| 推荐服务挂了 | 展示热门榜单 / 空 | 用户体验略降 |
|
||||
| 评论服务挂了 | 隐藏评论区 | 不影响购买流程 |
|
||||
| 搜索服务超时 | 返回最近浏览记录 | 降低用户感知 |
|
||||
| 库存服务不可用 | 显示"暂时无法确认库存" | 引导用户稍后再试 |
|
||||
|
||||
## 7. 健康检查
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant LB as 负载均衡器/K8s
|
||||
participant S1 as 服务实例 A
|
||||
participant S2 as 服务实例 B
|
||||
|
||||
LB->>S1: GET /healthz -> 200 OK
|
||||
LB->>S2: GET /healthz -> 503 ERROR
|
||||
Note over LB: 标记 S2 不健康,剔除出池
|
||||
LB->>S2: GET /healthz -> 200 OK
|
||||
Note over LB: 逐步恢复,重新加入池
|
||||
```
|
||||
|
||||
- **存活探针 (Liveness)**:判断"进程是否还活着",挂了则重启
|
||||
- **就绪探针 (Readiness)**:判断"是否能接收流量",未就绪则剔除负载均衡池
|
||||
- **Readiness 比 Liveness 更重要**——一个进程活着但数据库连接耗尽时,应该停止接收流量而不是重启
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/API网关/README]] — 网关层的限流和熔断插件
|
||||
- [[02-服务治理/服务发现/README]] — 健康检查是服务发现的基础
|
||||
- [[04-可观测性/Metrics监控/README]] — 熔断器的指标暴露和告警联动
|
||||
@@ -0,0 +1,205 @@
|
||||
---
|
||||
tags: [microservice, service-discovery, consul, nacos, etcd, kubernetes]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 服务发现
|
||||
|
||||
## 概述
|
||||
|
||||
服务实例的动态变化(扩容、缩容、故障重启)让硬编码地址成为不可能。服务要回答的核心问题是:**我怎么找到你?**
|
||||
|
||||
> [!question] 引出问题
|
||||
> 假设你的订单服务有 3 个实例,运行在 `10.0.1.1:8080`、`10.0.1.2:8080`、`10.0.1.3:8080`。当其中一个实例扩容下线时,调用方如何得知最新的地址列表?手动改配置滚动重启?还是……有更好的办法?
|
||||
|
||||
## 两种发现模式
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph Client["客户端发现模式"]
|
||||
A[Service A] -->|1.查询注册中心| R1[(Registry)]
|
||||
R1 -->|2.返回实例列表| A
|
||||
A -->|3.自选实例直连| B[Service B]
|
||||
noteA[客户端内置负载均衡逻辑]
|
||||
end
|
||||
|
||||
subgraph Server["服务端发现模式"]
|
||||
C[Service C] -->|请求| P[LoadBalancer Proxy]
|
||||
P -->|查询注册中心| R2[(Registry)]
|
||||
R2 -->|返回实例| P
|
||||
P -->|转发| D[Service D]
|
||||
noteC[客户端无感知,透明代理]
|
||||
end
|
||||
```
|
||||
|
||||
**对比**:
|
||||
|
||||
| 维度 | 客户端发现 | 服务端发现 |
|
||||
|------|-----------|-----------|
|
||||
| 典型实现 | Eureka、Consul、Nacos | Nginx、Envoy、K8s Service |
|
||||
| 耦合度 | 客户端嵌入注册逻辑 | 透明代理,客户端无感知 |
|
||||
| 性能 | 直连调用,延迟最低 | 多一跳代理开销 |
|
||||
| 运维复杂度 | 每门语言需独立 SDK | 统一部署代理,技术无关 |
|
||||
| 灵活性 | 客户端可自定义路由策略 | 受限于代理能力 |
|
||||
|
||||
### 客户端发现的优劣势分析
|
||||
|
||||
**优势**:
|
||||
- 直连调用,少了一跳网络开销
|
||||
- 客户端可以根据本地缓存做智能选择(如就近节点优先)
|
||||
- 框架成熟,Eureka/Consul 社区案例丰富
|
||||
|
||||
**劣势**:
|
||||
- 每个服务实现中都需要集成 SDK,跨语言迁移成本高
|
||||
- 客户端需要处理实例列表的缓存与刷新逻辑
|
||||
- 新增服务时需要修改调用方的代码或配置
|
||||
|
||||
### 服务端发现的优劣势分析
|
||||
|
||||
**优势**:
|
||||
- 完全解耦——调用方只需知道 Proxy 地址
|
||||
- 统一治理入口,可以在代理层加限流、熔断等逻辑
|
||||
- 适合多语言团队,无需各自维护 SDK
|
||||
|
||||
**劣势**:
|
||||
- 额外一跳增加延迟(通常 <1ms,高吞吐场景累积明显)
|
||||
- Proxy 本身成为单点瓶颈,必须做横向扩展
|
||||
- 调测复杂度上升——出了问题要看两层日志
|
||||
|
||||
## 主流注册中心选型
|
||||
|
||||
### Nacos(推荐国内团队首选)
|
||||
|
||||
阿里开源,支持 AP(临时实例)+ CP(持久实例)双模型,同时提供配置管理功能。
|
||||
|
||||
```go
|
||||
// Nacos 服务注册 & 拉取
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
)
|
||||
|
||||
// 创建注册客户端
|
||||
sc := constant.ServerConfig{
|
||||
IpAddr: "127.0.0.1",
|
||||
Port: 8848,
|
||||
}
|
||||
|
||||
// 注册服务实例
|
||||
client, _ := clients.NewNamingClient(
|
||||
value_map.NewValueMap(map[string]any{"serverConfig": sc}),
|
||||
)
|
||||
|
||||
client.RegisterInstance(naming_param.RegisterInstanceParam{
|
||||
Ip: "10.0.0.1",
|
||||
Port: 8080,
|
||||
ServiceName: "order-service",
|
||||
ClusterName: "DEFAULT",
|
||||
})
|
||||
|
||||
// 拉取某服务的可用实例列表
|
||||
instances, _ := client.SelectInstances(naming_param.SelectInstanceParam{
|
||||
ServiceName: "order-service",
|
||||
})
|
||||
```
|
||||
|
||||
### Consul
|
||||
|
||||
HashiCorp 出品,基于 Raft 共识协议(CP),天然支持健康检查和 DNS 接口。
|
||||
|
||||
**核心特点**:
|
||||
- 内建 KV 存储,可作为轻量配置中心
|
||||
- 支持 multi-datacenter 部署
|
||||
- DNS 接口:`order-service.service.consul` 可直接解析 IP
|
||||
|
||||
### etcd + K8s Service
|
||||
|
||||
纯容器环境下最自然的选择。etcd 存数据,K8s 提供完整的发现和负载均衡体系。
|
||||
|
||||
```yaml
|
||||
# K8s Service — 服务端发现模式的代表
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: order-service
|
||||
spec:
|
||||
selector:
|
||||
app: order
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
调用方只需 `http://order-service:80`,K8s 通过 iptables/IPVS 自动实现负载均衡。
|
||||
|
||||
### Eureka
|
||||
|
||||
Netflix 开源,AP 模型。**注意**:Eureka 2.x 已开源关闭,不建议新项目使用。已有系统在迁移到 Nacos 或 Consul 之前可以继续用。
|
||||
|
||||
## 关键机制
|
||||
|
||||
### 服务注册流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant S as 服务实例
|
||||
participant R as 注册中心
|
||||
participant H as 健康检查器
|
||||
|
||||
S->>R: 1. Register(instance)
|
||||
R-->>S: 2. ACK
|
||||
Note over S,R: 实例写入内存 / etcd
|
||||
|
||||
loop 定时心跳
|
||||
S->>R: 3. Heartbeat (每 5s)
|
||||
R-->>S: 4. ACK
|
||||
end
|
||||
|
||||
R->>H: 5. 超过心跳间隔未收到 → 标记不健康
|
||||
H->>R: 6. 摘除实例
|
||||
```
|
||||
|
||||
### 临时实例 vs 持久实例
|
||||
|
||||
| 类型 | 宕机检测方式 | 数据存储 | 适用场景 |
|
||||
|------|-------------|---------|---------|
|
||||
| **临时实例 (ephemeral)** | 心跳超时自动摘除 | 内存 | Web 服务、应用实例 |
|
||||
| **持久实例 (persistent)** | 主动注销才摘除 | etcd | 数据库连接、外部依赖 |
|
||||
|
||||
> [!warning] 常见陷阱
|
||||
> 把数据库当成临时实例注册 —— 数据库挂了不需要被 "检测到",它自己控制启停。应该用持久实例。
|
||||
|
||||
### 优雅上下线
|
||||
|
||||
服务下线时不能直接断网,否则正在处理的请求会失败。
|
||||
|
||||
**上线流程**:
|
||||
1. 进程启动 → 加载配置、初始化连接池
|
||||
2. `/ready` 探针返回 200 → 注册中心注册 + K8s 加入负载均衡池
|
||||
3. 开始接收流量
|
||||
|
||||
**下线流程**:
|
||||
1. 注册中心注销实例 → 停止接收新请求
|
||||
2. 等待正在处理的请求完成(最大等待 N 秒)
|
||||
3. 关闭连接池、保存状态
|
||||
4. 进程退出
|
||||
|
||||
> [!tip] K8s Pod 优雅终止
|
||||
> ```yaml
|
||||
> spec:
|
||||
> terminationGracePeriodSeconds: 30 # 最多等 30 秒再 SIGKILL
|
||||
> ```
|
||||
> 配合 `preStop` Hook 可以提前摘除流量:
|
||||
> ```yaml
|
||||
> lifecycle:
|
||||
> preStop:
|
||||
> exec:
|
||||
> command: ["sh", "-c", "sleep 15"] # 给负载均衡摘流的时间
|
||||
> ```
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/API网关/README]] — API Gateway 是服务发现的用户之一
|
||||
- [[02-服务治理/容错模式/README]] — 健康检查是容错体系的基础
|
||||
- [[05-部署运维/Kubernetes/README]] — K8s Service 的服务发现原理
|
||||
@@ -0,0 +1,201 @@
|
||||
---
|
||||
tags: [microservice, rpc, rest, grpc, message-queue, event-driven]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 服务间通信
|
||||
|
||||
## 概述
|
||||
|
||||
微服务之间如何通信,是架构设计的核心决策之一。选错了通信方式,后面会带来一系列问题:耦合度太高、性能瓶颈、或者运维复杂度爆炸。
|
||||
|
||||
## RPC vs RESTful API
|
||||
|
||||
### 对比分析
|
||||
|
||||
| 维度 | REST over HTTP/JSON | gRPC (HTTP/2) | GraphQL |
|
||||
|------|---------------------|---------------|---------|
|
||||
| **性能** | 序列化开销大 | Protocol Buffers,二进制高效 | 中等(JSON) |
|
||||
| **人类可读** | URL + JSON 直观 | 需要 Proto 定义辅助理解 | 查询语言自描述 |
|
||||
| **语言兼容性** | 广泛,任何能发 HTTP 的语言都能用 | 需要代码生成 | 需客户端 SDK |
|
||||
| **缓存** | 天然支持 HTTP 缓存 | 不支持(HTTP/2 多路复用替代) | 可设计缓存层 |
|
||||
| **版本管理** | URL 路径 (/v1/, /v2/) | Proto 文件向前兼容 | Schema 演进工具 |
|
||||
| **适用场景** | 对外 API、跨团队/跨组织调用 | 内部服务间高频强类型调用 | 前端聚合查询、移动端 |
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "何时选什么?"
|
||||
D{"你的场景是?"}
|
||||
|
||||
D -->|"对外暴露 API"| REST["REST over HTTP"]
|
||||
D -->|"内部服务高频调用"| GRPC["gRPC"]
|
||||
D -->|"前端/移动端复杂查询"| GraphQL["GraphQL"]
|
||||
D -->|"异步解耦通知"| MQ["消息队列"]
|
||||
end
|
||||
```
|
||||
|
||||
### 混合通信模式(推荐)
|
||||
|
||||
实际工程中很少单一选型。**最佳实践是混合使用**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as 客户端
|
||||
participant GW as API Gateway
|
||||
participant O as Order Service
|
||||
|
||||
note over C,O: 外部请求 — 用 REST/gRPC
|
||||
C->>GW: POST /orders (HTTP/JSON)
|
||||
GW->>O: CreateOrder (gRPC)
|
||||
|
||||
note over O,O: 内部处理 — 同步 + 异步组合
|
||||
O->>O: 创建订单记录 (本地事务)
|
||||
O-->>GW: {orderId: "ORD-001"}
|
||||
GW-->>C: 200 OK
|
||||
|
||||
O->>O: Publish OrderCreated Event (MQ)
|
||||
Note right of O: 通知类场景异步处理
|
||||
```
|
||||
|
||||
## 同步通信
|
||||
|
||||
### gRPC 协议详解
|
||||
|
||||
gRPC 基于 Protocol Buffers(Proto3),利用 HTTP/2 的多路复用特性,非常适合高性能的内部服务间调用。
|
||||
|
||||
```go
|
||||
// proto/order/v1/order.proto
|
||||
syntax = "proto3";
|
||||
package order.v1;
|
||||
|
||||
service OrderService {
|
||||
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
|
||||
rpc GetOrder(GetOrderRequest) returns (Order);
|
||||
rpc StreamOrders(StreamRequest) returns (stream Order); // 服务端流
|
||||
}
|
||||
|
||||
message CreateOrderRequest {
|
||||
string user_id = 1;
|
||||
repeated Item items = 2;
|
||||
float total = 3;
|
||||
}
|
||||
|
||||
message Item {
|
||||
string product_id = 1;
|
||||
int32 quantity = 2;
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
UNKNOWN = 0;
|
||||
PENDING = 1;
|
||||
PAID = 2;
|
||||
SHIPPED = 3;
|
||||
CANCELLED = 4;
|
||||
}
|
||||
```
|
||||
|
||||
**Proto3 注意事项**:
|
||||
- 字段编号(`= 1`, `= 2`)不能重编——破坏向后兼容
|
||||
- 新增字段标记为 `optional` 时 Proto3 才能区分"未设置"和"默认值"
|
||||
- `repeated` 字段空数组不会省略,需要特殊处理
|
||||
|
||||
### RESTful API 设计规范
|
||||
|
||||
```
|
||||
GET /api/v1/orders → 获取订单列表
|
||||
POST /api/v1/orders → 创建订单
|
||||
GET /api/v1/orders/{id} → 获取订单详情
|
||||
PUT /api/v1/orders/{id} → 更新订单(全量替换)
|
||||
PATCH /api/v1/orders/{id} → 部分更新
|
||||
DELETE /api/v1/orders/{id} → 删除订单
|
||||
```
|
||||
|
||||
**核心原则**:
|
||||
- **资源名词化**:URL 用名词复数,不用动词
|
||||
- **无状态**:每个请求携带完整上下文(通过 Header 传 Token)
|
||||
- **统一接口**:用标准 HTTP Method + Status Code 表达语义
|
||||
|
||||
## 异步通信
|
||||
|
||||
### 事件驱动架构
|
||||
|
||||
> [!question] 关键时刻的判断
|
||||
> 用户点击"提交订单"后,系统要做:① 创建订单记录 ② 扣减库存 ③ 扣款 ④ 发送短信通知。哪些步骤必须同步完成?哪些可以异步处理?为什么?
|
||||
|
||||
**答案**:①~③需要立即得到结果或保证一致性,走同步流程;④纯粹的通知类场景完全异步,用消息队列解耦。即使扣款失败,短信也没必要发出。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A["订单创建"] --> B{"是否需要同步响应?"}
|
||||
B -->|"是"| Sync["同步 RPC 链"]
|
||||
B -->|"否"| Async["异步 MQ 事件"]
|
||||
|
||||
Sync --> Stock["查库存 (RPC)"]
|
||||
Stock --> Pay["支付 (RPC)"]
|
||||
|
||||
Async --> SMS["发短信 (Event)")
|
||||
Async --> Points["加积分 (Event)"]
|
||||
Async --> Email["发确认邮件 (Event)"]
|
||||
```
|
||||
|
||||
### 消息队列选型
|
||||
|
||||
| 方案 | 吞吐量 | 延迟 | 可靠性 | 特色能力 |
|
||||
|------|--------|------|--------|---------|
|
||||
| **RocketMQ** | 极高 (百万级) | 毫秒级 | 事务消息支持 | 阿里出品,国内首选 |
|
||||
| **Kafka** | 最高 (千万级) | 秒级 | 持久化 | 大数据生态集成 |
|
||||
| **RabbitMQ** | 中等 (十万级) | 亚毫秒 | 高 | 灵活的路由模型 |
|
||||
| **Pulsar** | 高 | 毫秒级 | 高 | 存储计算分离 |
|
||||
|
||||
### 发布订阅 vs 点对点
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
Publisher[生产者] --> Broker[(MQ Broker)]
|
||||
|
||||
Broker --> Sub1["消费者组 A<br/>Topic: order-events"]
|
||||
Broker --> Sub2["消费者组 B<br/>Topic: order-events"]
|
||||
Broker --> Sub3["消费者组 C<br/>Topic: order-events"]
|
||||
|
||||
style Sub1 fill:#cfe2f3
|
||||
style Sub2 fill:#d9e2f3
|
||||
style Sub3 fill:#e2d9f3
|
||||
```
|
||||
|
||||
- **发布订阅 (Pub/Sub)**:一个消息被多个消费组分别消费,每个组内只有一个实例收到
|
||||
- **点对点 (Queue)**:一条消息只被一个消费者处理
|
||||
|
||||
## 同步与异步的组合拳
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Gateway
|
||||
participant Order
|
||||
participant MQ
|
||||
participant Notify
|
||||
participant Analytics
|
||||
|
||||
Client->>Gateway: 下单请求
|
||||
Gateway->>Order: 创建订单
|
||||
Order->>Order: 写库 + 出消息(事务)
|
||||
Order-->>Gateway: 返回 orderId
|
||||
Gateway-->>Client: 202 Accepted ⚡
|
||||
|
||||
Note over MQ: 异步后续处理
|
||||
MQ->>Notify: 发送通知
|
||||
MQ->>Analytics: 数据统计
|
||||
|
||||
Note right of Client: 用户体验好:<br/>主流程快速响应<br/>非关键任务后台处理
|
||||
```
|
||||
|
||||
> [!keypoint] 关键洞察
|
||||
> - 同步链路:**gRPC 直连**,延迟低,适合核心事务链
|
||||
> - 异步链路:**消息队列**,解耦非关键路径,即使失败也不影响主干
|
||||
> - 核心原则:**同步保性能,异步保解耦**
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/API网关/README]] — API Gateway 负责协议转换
|
||||
- [[03-数据一致性/分布式事务/README]] — 消息投递的一致性保障
|
||||
- [[05-部署运维/Kubernetes/README]] — Sidecar 代理透明拦截通信流量
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
tags: [microservice, canary-release, blue-green, traffic-routing, istio]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 流量治理
|
||||
|
||||
## 概述
|
||||
|
||||
灰度发布(也叫金丝雀发布)是降低变更风险的核心手段。它让你将新版本逐步推向一小部分用户,观察指标正常后再全量。
|
||||
|
||||
> [!question] 如何安全地上线?
|
||||
> 你修复了一个紧急 Bug,但这次改动涉及核心支付链路。直接全量发布一旦出问题损失巨大。有没有办法先小范围验证,确认没问题再放量?
|
||||
|
||||
## 灰度策略全景
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["🟢 v1 (稳定版)<br/>95% 流量"] --> B["🔵 v2 (测试版)<br/>5% 流量"]
|
||||
B --> C{"监控指标?"}
|
||||
|
||||
C -- "✅ 一切正常" --> D["逐步放量<br/>10% → 25% → 50%"]
|
||||
C -- "❌ 错误率飙升" --> E["自动回滚到 v1 🔄"]
|
||||
|
||||
D --> F{"全部放量至 100%"}
|
||||
F --> G["🟢 v2 成为新稳定版"]
|
||||
```
|
||||
|
||||
### 常见灰度策略对比
|
||||
|
||||
| 策略 | 描述 | 优点 | 缺点 | 适用场景 |
|
||||
|------|------|------|------|---------|
|
||||
| **按百分比** | 随机分配 N% 流量到新版本 | 简单粗暴,覆盖面广 | 可能只命中特定用户 | 通用场景 |
|
||||
| **按用户 ID** | 指定用户/内部账号走新版 | 可精准控制测试范围 | 样本不够代表性 | 内部验收阶段 |
|
||||
| **按 Header** | `x-canary: true` 路由到新版本 | 灵活性最高 | 需要客户端配合 | QA / AB 测试 |
|
||||
| **按地域** | 某个城市/机房的新版本 | 地域性问题的理想试验场 | 地域偏差大 | 全球化部署 |
|
||||
| **按设备类型** | iOS 新用户先用新版 | 覆盖目标人群 | 样本有限 | 移动端发版 |
|
||||
|
||||
## 蓝绿 vs 灰度
|
||||
|
||||
> [!summary] 两种发布策略对比
|
||||
>
|
||||
> | 维度 | 蓝绿部署 | 灰度发布 (金丝雀) |
|
||||
> |------|---------|-----------------|
|
||||
> | **切换方式** | 一次性全切 | 逐步放量 |
|
||||
> | **资源消耗** | 双倍(新旧并行) | 初期少量副本 |
|
||||
> | **回滚速度** | 秒级(切回 LB 即可) | 同样秒级 |
|
||||
> | **风险等级** | 中高(全量暴露问题) | 低(渐进式) |
|
||||
> | **适合场景** | 大型变更、重大版本 | 日常迭代、高风险链路 |
|
||||
|
||||
### 蓝绿部署流程
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Blue: 初始状态
|
||||
Blue --> DeployGreen: 部署 v2 到 Green 环境
|
||||
DeployGreen --> TestGreen: 验证 Green
|
||||
TestGreen --> Switch: 切换入口流量
|
||||
Switch --> Green: 全部流量到 Green/v2
|
||||
Green --> CleanupBlue: 删除 Blue/v1
|
||||
CleanupBlue --> [*]
|
||||
```
|
||||
|
||||
### 金丝雀发布流程
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
S1["v1 运行中<br/>100% 流量"]
|
||||
S2["部署 v2<br/>5% 流量"]
|
||||
S3["监控 15min"]
|
||||
S4{"P99 延迟 < SLA?"}
|
||||
|
||||
S4 -- 否 --> Rollback["回滚 v2 🔄"]
|
||||
S4 -- 是 --> S5["放量 25%"]
|
||||
S5 --> S6["监控 30min"]
|
||||
S6 --> S7{"错误率 < 0.1%?"}
|
||||
S7 -- 否 --> Rollback
|
||||
S7 -- 是 --> S8["放量 50%"]
|
||||
S8 --> S9["监控 1h"]
|
||||
S9 --> S10{"全项达标?"}
|
||||
S10 -- 是 --> S11["100% 全量 ✅"]
|
||||
S10 -- 否 --> Rollback
|
||||
|
||||
style Rollback fill:#ffebee
|
||||
style S11 fill:#e8f5e9
|
||||
```
|
||||
|
||||
## 高级路由规则
|
||||
|
||||
### Istio VirtualService
|
||||
|
||||
```yaml
|
||||
# 灰度规则:header 携带 canary=true 的用户走 v2
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: order-route
|
||||
spec:
|
||||
hosts: ["order-service"]
|
||||
http:
|
||||
# 灰度规则
|
||||
- match:
|
||||
- headers:
|
||||
x-canary:
|
||||
exact: "true"
|
||||
route:
|
||||
- destination:
|
||||
host: order-service
|
||||
subset: v2
|
||||
weight: 100
|
||||
# 默认:全部走 v1
|
||||
- route:
|
||||
- destination:
|
||||
host: order-service
|
||||
subset: v1
|
||||
weight: 100
|
||||
```
|
||||
|
||||
### 权重路由示例
|
||||
|
||||
```yaml
|
||||
# 按比例分流
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: order-service
|
||||
subset: v1
|
||||
weight: 90
|
||||
- destination:
|
||||
host: order-service
|
||||
subset: v2
|
||||
weight: 10
|
||||
```
|
||||
|
||||
## 流量治理的其他维度
|
||||
|
||||
除了发布策略,流量治理还包括:
|
||||
|
||||
| 能力 | 说明 |
|
||||
|------|------|
|
||||
| **熔断降级** | 下游不可用时自动降级,参见 [[02-服务治理/容错模式/README]] |
|
||||
| **限流** | 保护上游不因过量请求被打垮,参见 [[02-服务治理/容错模式/README]] |
|
||||
| **重试** | 对瞬态故障自动恢复,参见 [[02-服务治理/容错模式/README]] |
|
||||
| **黑白名单** | IP 级别访问控制 |
|
||||
| **A/B Testing** | 基于用户分组的长期实验 |
|
||||
|
||||
## 灰度发布的量化决策依据
|
||||
|
||||
> [!tip] 必须有可量化的观测指标作为决策依据
|
||||
>
|
||||
> 不要凭感觉放量,让数据说话:
|
||||
>
|
||||
> | 指标 | 阈值参考 | 告警级别 |
|
||||
> |------|---------|---------|
|
||||
> | **错误率** | < 0.1% (v1 baseline 对比) | > 1% 立即回滚 |
|
||||
> | **P99 延迟** | ≤ v1 × 1.1 | > v1 × 1.3 暂停放量 |
|
||||
> | **CPU/Memory** | 在 limits 的 70% 以内 | > 85% 扩容 |
|
||||
> | **下游依赖成功率** | > 99.5% | < 95% 熔断 |
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/API网关/README]] — API Gateway 的路由和权重分发
|
||||
- [[04-可观测性/Metrics监控/README]] — 灰度期间的监控面板设计
|
||||
- [[05-部署运维/SRE实践/README]] — 基于 SLO 的发布决策
|
||||
@@ -0,0 +1,173 @@
|
||||
---
|
||||
tags: [microservice, config-management, nacos, apollo, spring-cloud-config]
|
||||
create time: 2026-05-05
|
||||
---
|
||||
|
||||
# 配置管理
|
||||
|
||||
## 概述
|
||||
|
||||
当服务实例数以百计时,手动管理配置是不可想象的。配置中心提供 **集中化、动态化、版本化** 的配置管理能力。
|
||||
|
||||
> [!question] 引出配置中心的必要性
|
||||
> 假设你的 50 个服务实例都要连同一个数据库。现在需要把数据库密码从 `password1` 改为 `password2`,你会怎么改?登录每台机器改配置文件?滚动重启所有 Pod?还是……有更好的办法?
|
||||
|
||||
## 核心价值
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Dev["开发/运维"] --> CC[(配置中心)]
|
||||
CC -->|热更新推送| S1[Service A]
|
||||
CC -->|热更新推送| S2[Service B]
|
||||
CC -->|热更新推送| S3[Service C]
|
||||
|
||||
CC -.->|版本管理| V1[v1.0 历史配置]
|
||||
CC -.->|版本管理| V2[v1.1 当前配置]
|
||||
```
|
||||
|
||||
| 能力 | 说明 |
|
||||
|------|------|
|
||||
| **动态刷新** | 修改配置后立即生效,无需重启 |
|
||||
| **环境隔离** | dev / test / prod 配置分离 |
|
||||
| **版本管理与回滚** | 每次变更有迹可循,一键回滚 |
|
||||
| **权限控制** | 敏感配置(密钥、Token)按角色隔离 |
|
||||
| **配置审计** | 记录谁在什么时候改了什么 |
|
||||
|
||||
## 配置分层模型
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "配置优先级(低 → 高)"
|
||||
Base["Base 基线配置<br/>各项目共享的默认值"]
|
||||
App["应用级配置<br/>每个服务的专属配置"]
|
||||
Env["环境级配置<br/>dev/test/prod 差异"]
|
||||
Instance["实例级配置<br/>单节点调优参数"]
|
||||
end
|
||||
|
||||
style Base fill:#e3f2fd
|
||||
style App fill:#fff3e0
|
||||
style Env fill:#fce4ec
|
||||
style Instance fill:#e8f5e9
|
||||
```
|
||||
|
||||
**典型配置项分层**:
|
||||
|
||||
| 层级 | 示例 | 修改频率 |
|
||||
|------|------|---------|
|
||||
| 基线配置 | Redis 集群地址、公共超时时间 | 极低 |
|
||||
| 应用配置 | 线程池大小、日志级别 | 低 |
|
||||
| 环境配置 | DB 连接串、Feature Flag | 中 |
|
||||
| 实例配置 | 单机限流阈值、调试开关 | 高 |
|
||||
|
||||
## Nacos Config 示例
|
||||
|
||||
```go
|
||||
// 动态监听配置变更
|
||||
configClient, _ := clients.NewConfigClient(value_map.NewValueMap(map[string]any{
|
||||
"serverConfig": sc,
|
||||
}))
|
||||
|
||||
content, _ := configClient.GetConfig(config_param.GetConfigParam{
|
||||
DataId: "order-service.yaml",
|
||||
Group: "DEFAULT_GROUP",
|
||||
})
|
||||
|
||||
// 监听配置变化——Nacos 推送更新回调
|
||||
configClient.ListenChange(config_param.ListenChangeParam{
|
||||
DataId: "order-service.yaml",
|
||||
Group: "DEFAULT_GROUP",
|
||||
Callback: func(content string) {
|
||||
fmt.Println("配置更新了:", content)
|
||||
// 重新加载配置...
|
||||
ReloadConfig(content)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### 配置文件的命名规范
|
||||
|
||||
推荐格式:`{service-name}.{environment}.yaml`
|
||||
|
||||
| 服务名 | 环境 | Data ID |
|
||||
|--------|------|---------|
|
||||
| order-service | dev | `order-service.dev.yaml` |
|
||||
| order-service | prod | `order-service.prod.yaml` |
|
||||
| user-service | prod | `user-service.prod.yaml` |
|
||||
|
||||
## Apollo vs Nacos Config 对比
|
||||
|
||||
| 维度 | Apollo (携程) | Nacos Config (阿里) | Spring Cloud Config |
|
||||
|------|--------------|---------------------|--------------------|
|
||||
| **界面体验** | Web UI 完善,操作直观 | 较好 | 需自建 |
|
||||
| **发布流程** | 支持审核、灰度、回滚 | 基础发布+回滚 | 依赖 Git 工作流 |
|
||||
| **配置粒度** | 应用/Cluster/Namespace 多维 | Service/Group | File-based |
|
||||
| **性能** | AP 模型,延迟 < 1s | AP 模型,延迟 < 1s | 读取 Git,延迟稍高 |
|
||||
| **生态集成** | 适合 Java/Spring 体系 | Java + Go + Python 等 | 仅 Spring 生态 |
|
||||
| **适用场景** | 大型企业,多团队协同 | 中小团队快速落地 | 纯 Spring 项目 |
|
||||
|
||||
## K8s ConfigMap & Secret
|
||||
|
||||
纯 K8s 环境内的原生方案:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: order-service-config
|
||||
data:
|
||||
application.yaml: |
|
||||
server:
|
||||
port: 8080
|
||||
datasource:
|
||||
url: jdbc:mysql://db-host:3306/orders
|
||||
username: ${DB_USERNAME}
|
||||
password: ${DB_PASSWORD}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: order-service-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_USERNAME: "app_user"
|
||||
DB_PASSWORD: "s3cret_p@ss"
|
||||
```
|
||||
|
||||
注入到容器:
|
||||
|
||||
```yaml
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: order-service-config
|
||||
- secretRef:
|
||||
name: order-service-secrets
|
||||
```
|
||||
|
||||
> [!warning] K8s 原生方案的局限
|
||||
> - 修改 ConfigMap 后 Pod 不会自动重载配置(需配合 Sidecar 或手动触发 reload)
|
||||
> - 没有版本管理和灰度发布能力
|
||||
> - **建议**:简单项目用 K8s ConfigMap,复杂场景上 Apollo/Nacos
|
||||
|
||||
## 敏感信息处理
|
||||
|
||||
> [!danger] 安全红线
|
||||
> **永远不要**在代码仓库中硬编码密码、API Key、私钥等敏感信息。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Dev["开发者本地"] -->|"K8s Secret / Vault"| Store["加密存储"]
|
||||
Store -->|"运行时解密"| Runtime["运行时的环境变量"]
|
||||
Runtime --> App["应用程序"]
|
||||
|
||||
Audit["审计系统"] -.->|"只读访问"| Store
|
||||
```
|
||||
|
||||
**推荐方案**:
|
||||
- **K8s Secret** — 小型集群内使用(base64 编码,非加密,配合 EncryptionConfiguration 增强)
|
||||
- **HashiCorp Vault** — 企业级密钥管理,动态秘钥、自动轮换
|
||||
- **云厂商 KV 服务** — AWS Secrets Manager / 阿里云 KMS / 腾讯云 SecretManager
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[02-服务治理/服务发现/README]] — Nacos 同时提供服务发现和配置管理
|
||||
- [[05-部署运维/Kubernetes/README]] — ConfigMap/Secret 是 K8s 的配置注入方式
|
||||
Reference in New Issue
Block a user