专家(一):Claude Code 微服务实战——6 个服务从拆分到 K8s 部署,$0.45 全套 YAML 照抄

专家(一):Claude Code × 微服务------从单体拆分到 Kubernetes 部署

Windows 10/11 · Claude Code v2.1.32+ · DeepSeek V4 Pro / Anthropic API · 🟡 中度时效 · 最后更新 2026-05-13

一、这篇教程解决什么问题

一句话定位:读完本篇,你会用 Claude Code 把一个 FastAPI 单体电商系统拆分为 6 个微服务------从 DDD 限界上下文识别、gRPC 接口定义、逐个服务实现与测试、Docker 多阶段构建到 Kubernetes 生产级部署(Deployment + Service + Ingress + HPA + 分布式追踪),全程 AI 主导、你来审校。

这是专家系列的开篇------不再做 Todo App。场景是真实的:一个业务膨胀的电商单体,代码开始互相绊脚,部署越来越慢,团队在考虑"要不要拆"。

真实案例速览(这些不是理论------是真实的人用 Claude Code 完成的微服务项目):

案例 规模 传统估算 AI 辅助实际 加速比
Alex Chen: Django 单体拆分 12万行→5个微服务 12周 14天 ~6x
Liran Farage: CI/CD 迁移 35+ Serverless 微服务 数周 几天 ~5x
Nubank: ETL 拆分 600万行代码 --- 12x 工时节省 12x

阅读前提(硬条件):

DeepSeek 用户注意:全部可用。本文全程使用 DeepSeek V4-Pro 完成,每个阶段记录实际 Token 消耗。文末附完整成本对比。

读完能得到什么

  1. 一套DDD 限界上下文识别的 Claude Code 实操方法------不是画 PPT,是逐文件分析依赖
  2. 6 个微服务的完整 gRPC + FastAPI 实现------proto 定义、服务代码、数据库迁移
  3. 全套 Kubernetes 生产级 YAML(Deployment/Service/Ingress/HPA/ConfigMap/Secret)由 Claude Code 生成
  4. Jaeger + Prometheus + Grafana 分布式追踪和监控体系
  5. 真实数据------每个微服务的 Token 消耗、生成代码量、人工修改比例
  6. 5 个真实 Debug(gRPC 服务发现失败、K8s CrashLoopBackOff、消息队列幂等性、跨服务认证失败、分布式追踪断链)

二、项目全景:我们要拆什么

2.1 单体现状

一个名为 ShopFast 的电商系统,FastAPI 单体,运行了 18 个月:

复制代码
shopfast/
├── app/
│   ├── main.py              # 越来越大的 FastAPI 入口
│   ├── models/              # 47 个 SQLAlchemy 模型,全部耦合在一起
│   │   ├── user.py
│   │   ├── product.py
│   │   ├── order.py         # import user, product, payment, inventory...
│   │   └── payment.py
│   ├── routers/             # 23 个路由文件
│   ├── services/            # 部分 Service 直接查表绕过模型层
│   └── utils/               # 到处 import 的工具函数
├── alembic/                 # 一个共享数据库的迁移
└── tests/                   # 覆盖率 18%

典型症状

  • user.py 中的一个字段 → 11 个文件报类型错误
  • 部署:整个应用 1.2GB Docker 镜像 → 推到 registry 5 分钟 → 重启 3 分钟
  • 订单模块出 bug → 部署修复 → 同时部署了用户模块的未测试改动 → 用户登录挂了
  • 3 个循环依赖:order↔user↔notification、product↔inventory↔order、payment↔order↔user

2.2 目标架构

拆分为 6 个微服务 + 1 个 API 网关:

复制代码
                          ┌────────────────────────────────┐
                          │        Nginx Ingress (K8s)      │
                          └───────────────┬────────────────┘
                                          │
                       ┌──────────────────┴──────────────────┐
                       │       API Gateway (FastAPI)          │
                       │   统一认证 · 路由转发 · 限流·熔断     │
                       └──────────────────┬──────────────────┘
                                          │
              ┌────────────┬──────────────┼──────────────┬────────────┐
              │ gRPC       │ gRPC         │ gRPC         │ gRPC       │ gRPC
              ▼            ▼              ▼              ▼            ▼
       ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
       │  User    │ │ Product  │ │  Order   │ │ Payment  │ │Notify    │
       │ Service  │ │ Service  │ │ Service  │ │ Service  │ │Service   │
       │          │ │          │ │          │ │          │ │(仅消费)   │
       │ Postgres │ │ Postgres │ │ Postgres │ │ Postgres │ │  Redis    │
       └──────────┘ └──────────┘ └────┬─────┘ └──────────┘ └──────────┘
                                      │
                                      │ Publish Events
                                      ▼
                             ┌────────────────┐
                             │  Apache Kafka   │
                             └────────┬───────┘
                                      │
                    ┌─────────────────┴─────────────────┐
                    ▼                                   ▼
           ┌──────────────┐                    ┌──────────────┐
           │ Notification │                    │  Analytics   │
           │   Service    │                    │   Service    │
           └──────────────┘                    └──────────────┘

2.3 各服务职责

服务 职责 数据库 对外接口 内部通信
API Gateway 统一入口、JWT 认证、路由转发、熔断 无状态 REST (8000) gRPC Client
User Service 注册/登录/用户信息 PostgreSQL REST (8001) + gRPC (50051) gRPC Server
Product Service 商品 CRUD/分类/库存查询 PostgreSQL REST (8002) + gRPC (50051) gRPC Server
Order Service 订单创建/状态管理/编排 PostgreSQL REST (8003) + gRPC (50051) gRPC Client + Kafka Producer
Payment Service 支付发起/回调处理/退款 PostgreSQL REST (8004) + gRPC (50051) gRPC Server
Notification Service 邮件/短信/推送 无(纯消费者) 无 HTTP Kafka Consumer

三、阶段一:拆分规划------让 Claude Code 读代码、画边界

3.1 核心策略

拆分最怕"盲拆"------按照目录结构或直觉切,拆完才发现 A 服务和 B 服务有 15 个隐式依赖。Claude Code 在这个阶段的价值不是写代码,而是:逐文件分析依赖、识别循环引用、给出基于数据的拆分优先级

在项目根目录启动 Claude Code 交互模式:

bash 复制代码
cd shopfast && claude

3.2 第一步:全局依赖分析

第一条 prompt(Plan 模式,不修改文件):

复制代码
分析整个 shopfast 代码库的依赖关系。不要修改任何文件。

任务:
1. 列出 app/ 目录下每个 Python 文件及其 import 的所有内部模块
2. 识别所有循环依赖(A→B→C→A)
3. 识别所有跨模块的数据库表直接访问(一个 Service 直接查另一个模块的表)
4. 将分析结果写入 docs/DEPENDENCY_GRAPH.md

只用 Read 和 Grep 工具。

Claude Code 读取了 47 个模型文件、23 个路由文件、18 个 Service 文件后,产出了一份依赖分析报告。关键发现:

  • 3 个循环依赖:order↔user↔notification、product↔inventory↔order、payment↔order↔user
  • 7 处跨模块直接查表 :OrderService 直接 SELECT * FROM products、PaymentService 直接 SELECT * FROM users
  • 11 个模块之间共享同一个 utils/ 目录,没有任何边界

3.3 第二步:限界上下文识别

基于依赖分析报告,第二条 prompt:

复制代码
基于 docs/DEPENDENCY_GRAPH.md,用 DDD 方法识别限界上下文。

对每个识别的上下文,列出:
1. 上下文名称(用业务语言,不是技术语言)
2. 属于该上下文的文件列表
3. 该上下文对外暴露的公共接口
4. 该上下文独占的数据库表
5. 与其他上下文的依赖关系(谁是上游、谁是下游)

按照"耦合度从低到高"排序,推荐前 3 个最安全优先提取的上下文。
输出写入 docs/BOUNDED_CONTEXTS.md。

Claude Code 给出的分析结果:

上下文 耦合度 独占表 依赖方向 建议
Notification 最低 notifications, notification_preferences 仅被其他模块调用,不主动依赖 第一优先
Product products, categories, inventories 被 Order 依赖,自身依赖少 第二优先
User users, user_profiles, roles 被几乎所有模块依赖 第三
Payment payments, refunds, payment_methods 依赖 User + Order 第四
Order 最高 orders, order_items, shipments 依赖 User + Product + Payment 最后

3.4 第三步:确认拆分方案

docs/BOUNDED_CONTEXTS.md 作为人类和 AI 之间的"合同"。确认后保存:

bash 复制代码
claude -p "将 docs/BOUNDED_CONTEXTS.md 整理为正式的拆分方案 MIGRATION_PLAN.md,
包含:最终服务列表、每个服务的数据库、对外 API、迁移顺序(从耦合最低到最高)、
每一步的验收标准" --allowedTools "Read,Write"

3.5 阶段一数据

指标 数值
Token 消耗 ~28K
DeepSeek V4-Pro 费用 $0.05
耗时 45 min
Claude 读取的文件数 88 个
输出文档 DEPENDENCY_GRAPH.md + BOUNDED_CONTEXTS.md + MIGRATION_PLAN.md

关键经验 :这个阶段一分钱都不应该省。多花 0.05 在分析上,避免 5.00 花在"拆完后发现边界错了推倒重来"上。Claude Code 在这个阶段是"架构顾问"------用交互模式做推演,不要用 -p


四、阶段二:逐个微服务实现

4.1 开发策略:小步增量 + 绞杀者模式

不搞"大爆炸重写"------按照 MIGRATION_PLAN.md 的顺序,逐个提取服务:

复制代码
通知服务(最简单) → 商品服务 → 用户服务 → 支付服务 → 订单服务(最复杂)
                                                  → API 网关(并行)

每个服务遵循相同的 6 步循环:

复制代码
proto 定义 → 代码生成 → 服务实现 → 单体中创建 Client → 切换流量 → 删除旧代码

第一个服务最重要------它验证整个流程(proto→代码→Docker→K8s→监控→回滚)的可行性。

4.2 Step 1:Proto 定义

为每个服务定义 gRPC 契约。以订单服务为例:

bash 复制代码
mkdir -p proto/order/v1
claude
复制代码
在 proto/order/v1/order.proto 中定义 Order 服务的 gRPC 契约:

需要:
- CreateOrder RPC:接收 user_id + items[] + shipping_address,返回 order_id + status
- GetOrder RPC:接收 order_id,返回完整订单信息
- ListOrders RPC:接收 user_id + page_token,server-side streaming 返回订单列表

消息中包含 common/v1/common.proto 的 Money 和 Address 类型。
先创建 common.proto,再创建 order.proto。
只写 proto 文件,不要生成代码。

Claude Code 生成的 proto/order/v1/order.proto

protobuf 复制代码
syntax = "proto3";
package order.v1;
import "common/v1/common.proto";

message OrderItem {
    string product_id = 1;
    string product_name = 2;
    int32 quantity = 3;
    common.v1.Money unit_price = 4;
}

message CreateOrderRequest {
    string user_id = 1;
    repeated OrderItem items = 2;
    common.v1.Address shipping_address = 3;
}

message CreateOrderResponse {
    string order_id = 1;
    string status = 2;
    common.v1.Money total_amount = 3;
}

message GetOrderRequest { string order_id = 1; }
message GetOrderResponse {
    string order_id = 1;
    string user_id = 2;
    repeated OrderItem items = 3;
    string status = 4;
    string created_at = 5;
}

service OrderService {
    rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
    rpc GetOrder(GetOrderRequest) returns (GetOrderResponse);
}

Claude Code 自动做对的事 :写 order.proto 时先读了 common.proto,确认 MoneyAddress 的字段名一致后才引用------避免了后续编译时的类型不匹配错误。

4.3 Step 2:服务实现(以订单服务为例)

生成 proto 代码后,实现服务:

复制代码
基于 proto/order/v1/order.proto,实现 Order Service。

项目结构:
services/order-service/
├── Dockerfile
├── requirements.txt
├── app/
│   ├── main.py              # FastAPI + gRPC Server 同进程
│   ├── core/config.py       # Pydantic Settings
│   ├── core/database.py     # async SQLAlchemy engine
│   ├── models/order.py      # Order 模型
│   ├── routers/orders.py    # REST 端点
│   ├── services/order_service.py  # 业务逻辑
│   └── grpc/order_servicer.py     # gRPC 实现
└── alembic/

要求:
1. FastAPI 和 gRPC 在同一个 lifespan 中启动
2. gRPC Server 监听 50051,HTTP 监听 8003
3. CreateOrder 实现:先调 User Service 验证用户 → 调 Product Service 验证商品
   → 本地写订单 → 调 Payment Service 发起支付 → Kafka 发布 OrderCreated 事件
4. 所有 gRPC 调用设置 3 秒超时
5. 数据库用 async SQLAlchemy + asyncpg,expire_on_commit=False

Claude Code 生成的核心结构(main.py):

python 复制代码
import grpc
from concurrent import futures
from contextlib import asynccontextmanager
from fastapi import FastAPI

grpc_server = grpc.aio.server(futures.ThreadPoolExecutor(max_workers=10))

@asynccontextmanager
async def lifespan(app: FastAPI):
    order_pb2_grpc.add_OrderServiceServicer_to_server(OrderServicer(), grpc_server)
    grpc_server.add_insecure_port("[::]:50051")
    await grpc_server.start()
    yield
    await grpc_server.stop(grace=5)

app = FastAPI(title="Order Service", lifespan=lifespan)
app.include_router(orders.router, prefix="/api/v1/orders")

4.4 Step 3:单体内创建 Client + Feature Flag 切换

复制代码
在单体中创建 gRPC Client(shopfast/app/clients/order_client.py):
1. 使用 grpc.aio.insecure_channel
2. 封装重试(tenacity,最多 3 次,指数退避)
3. 封装断路器(连续 5 次失败 → 断路 30 秒 → 半开试探)
4. 在单体路由中加 Feature Flag(环境变量 USE_NEW_ORDER_SERVICE=true/false)

4.5 逐个服务实现数据

服务 Token 费用 耗时 生成代码 人工修改比例
Notification Service ~8K $0.014 20min ~180 行 5%
Product Service ~15K $0.027 35min ~350 行 8%
User Service ~12K $0.021 30min ~280 行 10%
Payment Service ~18K $0.032 40min ~400 行 12%
Order Service(最复杂) ~25K $0.044 55min ~520 行 15%
API Gateway ~12K $0.021 25min ~250 行 7%
阶段二合计 ~90K $0.16 ~3.5h ~1980 行 ~10%

10% 人工修改比例意味着 Claude Code 生成的代码 90% 直接可用。需要人工修改的主要是:具体业务规则的边界条件(如优惠券叠加逻辑)、跨服务调用时的错误处理策略选择、以及数据库迁移脚本的外键处理。


五、阶段三:基础设施即代码------Docker + Kubernetes

5.1 Docker 多阶段构建

Claude Code 为每个微服务生成生产级 Dockerfile:

复制代码
为 services/order-service/ 写生产级 Dockerfile:
1. 多阶段构建(builder + runtime)
2. builder 用 uv 安装依赖到 /install
3. runtime 用 python:3.12-slim,非 root 用户
4. HEALTHCHECK 指令
5. 最终镜像 < 200MB

Claude Code 生成的 Dockerfile 关键部分:

dockerfile 复制代码
# Stage 1: Build
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
COPY requirements.txt .
RUN uv pip install --system --prefix=/install --no-cache-dir -r requirements.txt

# Stage 2: Runtime
FROM python:3.12-slim AS runtime
COPY --from=builder /install /usr/local
COPY app/ ./app/
COPY generated/ ./generated/

RUN groupadd --gid 1000 app && useradd --uid 1000 --gid app --shell /bin/bash --create-home app
USER app

ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
EXPOSE 8003 50051

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8003/health')" || exit 1

CMD ["gunicorn", "app.main:app", "-k", "uvicorn.workers.UvicornWorker", "-w", "4", "-b", "0.0.0.0:8003"]

Claude Code 做对的关键细节 :HEALTHCHECK 用 Python 内置 urllib 而非 curl,避免在 runtime 镜像中安装额外系统包。非 root 用户 + PYTHONUNBUFFERED=1 自动设置。

5.2 Kubernetes YAML 生成

这是 Claude Code 在基础设施领域最亮眼的表现。一个单服务 Deployment 手写通常 2-3 小时(查文档 → 确认 API 版本 → 验证字段名),Claude Code 不到 15 分钟完成。

复制代码
为 Order Service 生成完整的 Kubernetes 部署清单:

1. Namespace: ecommerce
2. ConfigMap(非敏感配置)+ Secret(数据库密码、JWT密钥)
3. Deployment:
   - 3 副本,RollingUpdate(maxUnavailable: 0)
   - CPU 250m/500m,Memory 256Mi/512Mi
   - livenessProbe: GET /health,initialDelaySeconds=30
   - readinessProbe: GET /health/ready,initialDelaySeconds=5
   - startupProbe: GET /health,failureThreshold=30(给慢启动留 300 秒)
   - 非 root 用户,terminationGracePeriodSeconds=30
4. Service:暴露 HTTP 8003 + gRPC 50051 双端口
5. Ingress:REST 流量 + gRPC 流量分开配置
6. HPA:CPU 70% 触发扩缩,min 2 / max 10,缩容稳定窗口 300 秒

全部 YAML 写入 k8s/order-service/ 目录。

Claude Code 生成的 Deployment 核心片段:

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: ecommerce
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
  selector:
    matchLabels: { app: order-service }
  template:
    metadata:
      labels: { app: order-service, version: v1 }
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8003"
    spec:
      terminationGracePeriodSeconds: 30
      securityContext: { runAsNonRoot: true, runAsUser: 1000 }
      containers:
        - name: order-service
          image: registry.example.com/ecommerce/order-service:v1.0.0
          ports:
            - { name: http, containerPort: 8003 }
            - { name: grpc, containerPort: 50051 }
          envFrom:
            - configMapRef: { name: order-service-config }
          env:
            - name: DB_PASSWORD
              valueFrom: { secretKeyRef: { name: order-service-secret, key: DB_PASSWORD } }
          resources:
            requests: { cpu: "250m", memory: "256Mi" }
            limits: { cpu: "500m", memory: "512Mi" }
          startupProbe:
            httpGet: { path: /health, port: http }
            failureThreshold: 30
            periodSeconds: 10
          livenessProbe:
            httpGet: { path: /health, port: http }
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet: { path: /health/ready, port: http }
            initialDelaySeconds: 5
            periodSeconds: 5

三个 Claude Code 自动做对的安全细节

  1. maxUnavailable: 0------滚动更新时零停机
  2. startupProbe + failureThreshold: 30------给慢启动应用 300 秒初始化时间,这是 AI 生成 K8s YAML 最容易漏的配置
  3. 分离 livenessProbereadinessProbe------前者不检查外部依赖,后者检查数据库连接

5.3 阶段三数据

子阶段 Token 费用 传统手写 AI 辅助 效率提升
6 个 Dockerfile ~15K $0.027 3-4h 20min ~12x
6 套 K8s YAML ~35K $0.062 12-18h 50min ~15x
docker-compose 本地 ~8K $0.014 1-2h 10min ~9x
CI/CD (GitHub Actions) ~10K $0.018 2-3h 15min ~10x
阶段三合计 ~68K $0.12 18-27h ~1.5h ~15x

基础设施即代码是 Claude Code 效率提升最大的领域 ------传统 18-27 小时压缩到 1.5 小时,约 15 倍加速。


六、阶段四:可观测性------分布式追踪 + 指标 + 日志

6.1 Claude Code 生成 OpenTelemetry 集成

分布式系统最大的挑战不是"怎么拆",而是"拆完后怎么知道哪个服务出了问题"。Claude Code 可以为每个服务自动添加 OpenTelemetry 插桩:

复制代码
在 services/order-service/app/core/telemetry.py 中创建 OpenTelemetry 初始化模块。

要求:
1. 自动插桩:FastAPI + gRPC Server + SQLAlchemy + httpx + aiokafka
2. Traces 发送到 Jaeger (jaeger-collector:4317)
3. 业务指标:订单创建计数器、订单金额 Histogram
4. 排除 /health 和 /metrics 端点的追踪
5. 所有 Span 自动注入 service.name 和 deployment.environment

Claude Code 生成的核心代码:

python 复制代码
# services/order-service/app/core/telemetry.py
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.grpc import GrpcAioInstrumentorServer
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor

def setup_telemetry(app, service_name: str = "order-service"):
    resource = Resource.create({
        "service.name": service_name,
        "deployment.environment": os.getenv("ENVIRONMENT", "production"),
    })
    tracer_provider = TracerProvider(resource=resource)
    tracer_provider.add_span_processor(BatchSpanProcessor(
        OTLPSpanExporter(endpoint=os.getenv("JAEGER_ENDPOINT", "http://jaeger:4317"), insecure=True)
    ))
    trace.set_tracer_provider(tracer_provider)

    FastAPIInstrumentor.instrument_app(app, excluded_urls="/health,/metrics")
    GrpcAioInstrumentorServer().instrument()
    SQLAlchemyInstrumentor().instrument()

# 业务指标
meter = metrics.get_meter(__name__)
order_counter = meter.create_counter("orders_created_total", "Total orders")
order_amount = meter.create_histogram("order_amount", "Order amount", unit="CNY")

6.2 阶段四数据

子阶段 Token 费用 耗时
6 个服务的 OTel 集成 ~18K $0.032 25min
Jaeger + Prometheus + Grafana K8s YAML ~10K $0.018 15min
Grafana Dashboard JSON ~8K $0.014 10min
阶段四合计 ~36K $0.064 ~50min

七、成本全记录

7.1 各阶段汇总

阶段 Token DeepSeek V4-Pro 耗时 传统估算 效率
拆分规划 ~28K $0.05 45min 2-3 天 ---
6 个微服务实现 ~90K $0.16 3.5h 12-16h ~4x
Docker + K8s + CI/CD ~68K $0.12 1.5h 18-27h ~15x
可观测性集成 ~36K $0.064 50min 6-8h ~8x
Debug + 迭代 ~30K $0.053 1h --- ---
全流程合计 ~252K $0.45 ~7.5h ~38-54h ~5-7x

7.2 成本对比:DeepSeek V4-Pro vs Claude Opus 4.7

阶段 DeepSeek V4-Pro Claude Opus 4.7(估算) 价差
拆分规划 $0.05 $0.23 ~4.5x
服务实现 $0.16 $0.72 ~4.5x
IaC $0.12 $0.54 ~4.5x
可观测性 $0.064 $0.29 ~4.5x
合计 $0.45 $2.03 ~4.5x

Claude Opus 4.7 估算基于 Anthropic 官方定价(输入 5/M,输出 25/M token,2026-05)。IaC 阶段的差距最大------生成大量 YAML(高输出 token 占比),Opus 输出 25/M vs DeepSeek 3.48/M,差 ~7x。


八、复盘:Claude Code 在微服务拆分中的优劣

8.1 超预期的环节

环节 表现 原因
依赖分析 一次分析 88 个文件、3 个循环依赖、7 处跨模块查表 Glob + Grep + Read 组合快速构建代码地图
Proto 生成 自动检查 common.proto 的类型一致性 Claude Code 生成前会读取已存在的相关文件
K8s YAML 自动加 startupProbe、非 root、零停机滚动更新 训练数据中大量生产级模板
Docker 多阶段 HEALTHCHECK + 非 root + uv 加速安装 Docker 最佳实践在训练数据中密度极高
跨服务一致性 6 个服务的 YAML 结构、端口约定、标签命名完全一致 Claude Code 记住了之前生成的模板

8.2 需要人工介入的环节

环节 问题 解决方式
数据库外键拆分 Claude 建议直接删外键,没考虑过渡期双写 人工要求加 CDC 中间步骤
分布式事务 初版代码假设跨服务调用是原子的 人工引入 Saga + Outbox 模式
gRPC 超时 默认不设超时,可能导致级联挂起 人工要求所有 gRPC 调用设 3s 超时
Kafka 分区 按随机分区,同用户订单可能乱序 人工改为按 user_id 分区
Grafana Dashboard 生成的 JSON 缺少 P99 延迟面板 人工补充关键指标

8.3 核心经验

  1. CLAUDE.md 分层架构对多服务项目至关重要。每个服务子目录放 30-50 行 CLAUDE.md(只描述该服务特有规则),根目录 CLAUDE.md(~100 行)只放跨服务共享规则。

  2. Proto 文件是"单一真实来源"。先定义 proto → 生成代码 → 实现服务。Claude Code 在不同会话间不会记住你的 API 契约------但 proto 文件会。

  3. 小步增量 + Feature Flag。每个服务提取后,用环境变量切换新旧实现。出问题一个环境变量回滚------比 git revert + 重新部署快 100 倍。

  4. 第一个提取的服务是"楔子"------选最独立、最低风险的。本项目中是通知服务,它验证了整个流程(proto→实现→Docker→K8s→监控→回滚)的可行性。

  5. "模块化单体"是合理的终态。不是所有服务都必须提取。如果某个模块不符合独立扩缩容、独立部署、独立团队的条件------留在单体中是对的。


九、Debug ×5(全项目实际踩坑)

Debug #1 --- gRPC UNIMPLEMENTED: unknown service

报错

复制代码
rpc error: code = Unimplemented desc = unknown service order.v1.OrderService

根因 :Client 端 proto 的 package 名是 order.v1,但 Server 端注册时写的是 pb.OrderService------不同 proto 文件的 package 声明不一致。

场景 Proto package 全限定服务名 结果
Client package order.v1; order.v1.OrderService 期望
Server A package order.v1; order.v1.OrderService 匹配
Server B package pb; pb.OrderService Unimplemented

修复 :统一所有 proto 文件的 package 声明格式为 {service}.v1

验证grpcurl -plaintext localhost:50051 list 确认所有服务名一致。


Debug #2 --- CrashLoopBackOff:Liveness Probe 过早

报错

复制代码
Warning  Unhealthy  Liveness probe failed: Get "http://10.244.1.5:8003/health": context deadline exceeded
Warning  BackOff    Back-off restarting failed container

根因 :Order Service 启动需 ~45 秒(加载 gRPC + 连接 DB + 初始化 Kafka),但 livenessProbe.initialDelaySeconds 只有 10 秒------应用还没起来就被判定为"死了"。

配置 行为
initialDelaySeconds: 10,无 startupProbe 10 秒后 liveness 开始检查 → kill
startupProbe + failureThreshold: 30 最长 300 秒初始化,liveness 在 startup 成功后接管

修复 :加 startupProbefailureThreshold: 30(30 × 10s = 300s)。

验证kubectl describe pod 确认不再出现 Liveness probe failed。


Debug #3 --- 数据库外键拆分:关联查询全部报错

症状 :将 Order 表迁移到独立 DB 后,SELECT * FROM orders JOIN users ON orders.user_id = users.id 全部报 relation "users" does not exist

根因:Claude Code 直接删除了跨库外键,但没处理依赖 JOIN 查询的 12 个 Service 方法。

外键处理策略 本场景适用性
直接删除外键 ❌(有 12 处 JOIN)
数据冗余(Denormalization) ✅ 用户名/邮箱冗余到 Order 表
CDC 事件同步 ✅ 用户信息变更通过 Kafka 同步

修复 :两步------① Order 表冗余 user_name + user_email,通过事件填充;② 订阅 user.updated Kafka 事件同步更新。

验证user.updated 事件后冗余字段 2 秒内同步。


Debug #4 --- 分布式事务:支付成功但订单状态未更新

症状 :支付回调成功,Payment 表已更新,但调用 OrderService.UpdateOrderStatus(PAID) 时网络超时------支付成功但订单卡在 PENDING。

根因:Claude Code 的初版代码假设网络调用总是成功------Payment 状态更新和通知下游不在同一事务中。

修复 :引入 Transactional Outbox 模式------同一 DB 事务中更新 Payment 状态 + 写入 outbox 事件。后台 worker 从 outbox 投递到 Kafka,Order Service 消费后更新订单状态。保证 at-least-once。

python 复制代码
async def handle_payment_callback(payment_id: str, status: str):
    async with db.begin():
        payment = await db.get(Payment, payment_id)
        payment.status = status
        db.add(OutboxEvent(aggregate_id=payment.order_id,
            event_type="PaymentCompleted",
            payload={"order_id": payment.order_id, "status": status}))

验证:模拟网络超时------Payment 状态正确、30 秒后 Kafka 重试成功、Order 最终一致。


Debug #5 --- Jaeger 中 gRPC 调用链断裂

症状:Jaeger 能看到 Order Service 的 Span,但看不到它调用的 User Service Span------调用链在 gRPC 边界断开。

根因 :gRPC 客户端未插桩 GrpcAioInstrumentorClient,trace context 不通过 gRPC metadata 传播。

场景 结果
FastAPI → gRPC Client(未插桩) Span 在 gRPC 边界断开
FastAPI → gRPC Client(已插桩) Span 通过 gRPC metadata 传播
gRPC Server(未插桩) 接收到的 trace context 被忽略
gRPC Server(已插桩) 正确创建子 Span

修复 :在 Order Service 添加 GrpcAioInstrumentorClient().instrument(),在各服务端确认 GrpcAioInstrumentorServer().instrument()

验证:Jaeger 中完整调用链:API Gateway → Order Service → User Service → PostgreSQL。


十、速查卡

Claude Code 拆分 Prompt 模板

阶段 模板
依赖分析 "分析代码库依赖关系。识别循环引用和跨模块查表。输出 DEPENDENCY_GRAPH.md。只用 Read/Grep。"
边界识别 "基于依赖图,用 DDD 识别限界上下文。按耦合度排序,推荐最安全优先提取的 3 个。"
服务提取 "将 {context} 提取为独立微服务。proto → 实现 → Client → Feature Flag。单体在测试通过后才能提交。"
K8s 生成 "为 {service} 生成完整 K8s 清单。含 startupProbe、非 root、零停机滚动更新、HPA。"

成本控制参数

场景 max_turns max_budget_usd 推荐模型
依赖分析(只读) 10 0.10 V4-Pro
服务实现(写代码) 15 0.50 V4-Pro
K8s 生成(大量输出) 8 0.20 V4-Pro
调试修复 8 0.15 V4-Pro

报错速查

报错 根因 解决
UNIMPLEMENTED unknown service Proto package 名不一致 统一 package {service}.v1;
CrashLoopBackOff Liveness probe 过早 startupProbe + failureThreshold: 30
relation does not exist 跨库外键直接删除 数据冗余 + CDC 事件同步
支付成功订单卡 PENDING 网络超时导致不一致 Outbox Pattern + Kafka 重试
Jaeger 调用链断裂 gRPC 未传播 trace context 添加 GrpcAioInstrumentorClient 插桩

扩展阅读

本系列相关文章:


参考文献

  1. AWS Prescriptive Guidance: Strangler Fig Pattern --- AWS 官方单体迁移指南
  2. How I use Claude Code to refactor a monolith into microservices --- Claude Code 拆分单体完整工作流
  3. Django 单体到微服务迁移案例 --- 12 万行 14 天拆分实录
  4. Claude Code Multi-File Refactor Protocol --- 大规模代码重组安全协议
  5. FastAPI + gRPC + K8s 生产级指南 --- FastAPI 微服务生产模式
  6. OpenTelemetry Python 官方文档 --- OTel 自动插桩指南
  7. Kubernetes CrashLoopBackOff 调试指南 --- K8s 官方 Pod 调试文档
  8. Microservices.io: Decompose by Subdomain --- DDD 子域分解模式
相关推荐
沪漂阿龙1 小时前
面试题:Transformer 模型详解——核心创新、编码器解码器结构、位置编码、因果掩码与大模型基础全解析
人工智能·深度学习·transformer
Zhu7581 小时前
[配置管理]k8s集群中airflow的端口转发
云原生·容器·kubernetes
JunLa1 小时前
Agent Basic 上篇
大数据·人工智能·agent
Raink老师1 小时前
【AI面试临阵磨枪-57】如何防止 Prompt 注入、越狱、敏感信息泄露
人工智能·面试·prompt·ai 面试
是吗乔治1 小时前
Claude Code Desktop 配置DeepSee API教程
deepseek·claude code·cc switch
沪漂阿龙2 小时前
面试题:预训练模型详解——GPT、BERT、T5 结构与训练目标、预训练微调范式、Transformers 加载 BERT 实战全解析
人工智能·深度学习
TE-茶叶蛋2 小时前
Java 8 引入的Stream API-stream()
java·windows·python
数智工坊2 小时前
【CLIP论文阅读】:基于自然语言监督的通用视觉预训练范式
论文阅读·人工智能
wanhengidc2 小时前
显卡服务器都有哪些功能
运维·服务器·人工智能·科技·智能手机·云计算