一、微服务架构概述

1.1 单体架构 vs 微服务架构

单体架构                         微服务架构
┌─────────────────────┐         ┌─────────────────────────────┐
│  应用                 │         │  ┌──────┐  ┌──────┐  ┌──────┐ │
│  ┌─────────────────┐ │         │  │用户  │  │订单  │  │支付  │ │
│  │  UI              │ │         │  │服务  │  │服务  │  │服务  │ │
│  ├─────────────────┤ │         │  └──┬───┘  └──┬───┘  └──┬───┘ │
│  │  业务逻辑        │ │         │     │         │         │     │
│  ├─────────────────┤ │         │     └─────────┼─────────┘     │
│  │  数据访问        │ │         │               │               │
│  ├─────────────────┤ │         │         ┌─────▼─────┐         │
│  │  数据库          │ │         │         │  API 网关  │         │
│  └─────────────────┘ │         │         └───────────┘         │
└─────────────────────┘         └─────────────────────────────┘

单体架构优缺点:
✅ 开发简单,部署方便
✅ 测试容易,调试直观
❌ 耦合严重,难以扩展
❌ 技术栈锁定,牵一发而动全身

微服务架构优缺点:
✅ 独立部署,独立扩展
✅ 技术栈灵活,容错性好
❌ 运维复杂,网络开销大
❌ 分布式事务困难,调试困难

1.2 微服务核心原则

微服务设计的 12 条原则
┌─────────────────────────────────────────────────────────────┐
│  1. 单一职责:每个服务只做一件事                            │
│  2. 自治性:每个服务独立开发、部署、扩展                    │
│  3. 去中心化:数据存储、治理、技术栈去中心化                │
│  4. 弹性设计:熔断、降级、重试、限流                        │
│  5. 观察性:日志、指标、链路追踪                            │
│  6. 自动化:CI/CD、自动化测试、自动化部署                   │
│  7. 接口契约:API First 设计                                │
│  8. 数据隔离:每个服务拥有自己的数据库                      │
│  9. 异步通信:优先使用消息队列                              │
│  10. 容错设计:假设网络不可靠                               │
│  11. 无状态:便于水平扩展                                   │
│  12. 渐进式:逐步演进,不要一次性重构                       │
└─────────────────────────────────────────────────────────────┘

二、服务拆分策略

2.1 拆分方法论

服务拆分策略
┌─────────────────────────────────────────────────────────────┐
│  1. 按业务能力拆分                                          │
│     用户服务、订单服务、支付服务、库存服务                  │
│                                                             │
│  2. 按子域拆分 (DDD)                                        │
│     限界上下文 → 微服务                                     │
│     例如:电商领域的商品域、订单域、支付域                  │
│                                                             │
│  3. 按数据边界拆分                                          │
│     每个服务拥有独立的数据库                                │
│     服务间通过 API 访问数据                                 │
│                                                             │
│  4. 按变更频率拆分                                          │
│     高频变更的服务独立出来                                  │
│     低频变更的服务可以合并                                  │
│                                                             │
│  拆分原则:                                                │
│  - 高内聚低耦合                                            │
│  - 团队结构对齐 (康威定律)                                  │
│  - 先拆分边界清晰的模块                                    │
│  - 逐步演进,不要一刀切                                    │
└─────────────────────────────────────────────────────────────┘

2.2 电商系统拆分示例

// microservice/split_example.go
package main

// 用户服务 (User Service)
type UserService struct {
    repo UserRepository
}

func (s *UserService) Register(email, password string) (*User, error) { return nil, nil }
func (s *UserService) Login(email, password string) (string, error) { return "", nil }
func (s *UserService) GetProfile(userID int64) (*User, error) { return nil, nil }

// 商品服务 (Product Service)
type ProductService struct {
    repo ProductRepository
}

func (s *ProductService) ListProducts(category string, page, size int) ([]*Product, error) { return nil, nil }
func (s *ProductService) GetProductDetail(productID int64) (*Product, error) { return nil, nil }
func (s *ProductService) UpdateStock(productID int64, delta int) error { return nil }

// 订单服务 (Order Service)
type OrderService struct {
    productClient ProductServiceClient  // 调用商品服务
    paymentClient PaymentServiceClient  // 调用支付服务
}

func (s *OrderService) CreateOrder(userID int64, items []*OrderItem) (*Order, error) { return nil, nil }
func (s *OrderService) CancelOrder(orderID int64) error { return nil }
func (s *OrderService) GetOrderHistory(userID int64) ([]*Order, error) { return nil, nil }

// 支付服务 (Payment Service)
type PaymentService struct {
    orderClient OrderServiceClient
}

func (s *PaymentService) Pay(orderID int64, amount float64) (*PaymentResult, error) { return nil, nil }
func (s *PaymentService) Refund(orderID int64) error { return nil }

// 库存服务 (Inventory Service)
type InventoryService struct {
    repo InventoryRepository
}

func (s *InventoryService) Reserve(productID int64, quantity int) error { return nil }
func (s *InventoryService) Release(productID int64, quantity int) error { return nil }
func (s *InventoryService) CheckAvailability(productID int64) (int, error) { return 0, nil }

三、服务间通信

3.1 RESTful API 通信

// communication/rest_server.go
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "strconv"
    "github.com/gorilla/mux"
)

// 用户服务 REST API
type UserAPI struct {
    service *UserService
}

func NewUserAPI(service *UserService) *UserAPI {
    return &UserAPI{service: service}
}

func (api *UserAPI) RegisterRoutes(r *mux.Router) {
    r.HandleFunc("/api/v1/users", api.CreateUser).Methods("POST")
    r.HandleFunc("/api/v1/users/{id}", api.GetUser).Methods("GET")
    r.HandleFunc("/api/v1/users/{id}", api.UpdateUser).Methods("PUT")
    r.HandleFunc("/api/v1/users/{id}", api.DeleteUser).Methods("DELETE")
}

func (api *UserAPI) CreateUser(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    user, err := api.service.Register(req.Email, req.Password)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

func (api *UserAPI) GetUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id, _ := strconv.ParseInt(vars["id"], 10, 64)

    user, err := api.service.GetProfile(id)
    if err != nil {
        http.Error(w, "User not found", http.StatusNotFound)
        return
    }

    json.NewEncoder(w).Encode(user)
}

// REST 客户端
type UserServiceClient struct {
    baseURL string
    client  *http.Client
}

func NewUserServiceClient(baseURL string) *UserServiceClient {
    return &UserServiceClient{
        baseURL: baseURL,
        client:  &http.Client{Timeout: 5 * time.Second},
    }
}

func (c *UserServiceClient) GetUser(id int64) (*User, error) {
    url := fmt.Sprintf("%s/api/v1/users/%d", c.baseURL, id)
    
    resp, err := c.client.Get(url)
    if err != nil {
        return nil, fmt.Errorf("request failed: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
    }

    var user User
    if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
        return nil, fmt.Errorf("decode failed: %w", err)
    }

    return &user, nil
}

3.2 gRPC 通信

// communication/grpc_communication.go
package main

import (
    "context"
    "log"
    "net"
    "time"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    pb "path/to/proto/userpb"
)

// gRPC 服务器
type UserGRPCServer struct {
    pb.UnimplementedUserServiceServer
    service *UserService
}

func (s *UserGRPCServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.UserResponse, error) {
    user, err := s.service.GetProfile(req.UserId)
    if err != nil {
        return nil, err
    }

    return &pb.UserResponse{
        Id:    user.ID,
        Name:  user.Name,
        Email: user.Email,
    }, nil
}

// gRPC 客户端
type UserGRPCClient struct {
    client pb.UserServiceClient
    conn   *grpc.ClientConn
}

func NewUserGRPCClient(address string) (*UserGRPCClient, error) {
    conn, err := grpc.Dial(
        address,
        grpc.WithTransportCredentials(insecure.NewCredentials()),
        grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(10 * 1024 * 1024)),
    )
    if err != nil {
        return nil, err
    }

    return &UserGRPCClient{
        client: pb.NewUserServiceClient(conn),
        conn:   conn,
    }, nil
}

func (c *UserGRPCClient) GetUser(ctx context.Context, userID int64) (*pb.UserResponse, error) {
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    return c.client.GetUser(ctx, &pb.GetUserRequest{UserId: userID})
}

func (c *UserGRPCClient) Close() {
    c.conn.Close()
}

3.3 消息队列通信

// communication/message_queue.go
package main

import (
    "context"
    "encoding/json"
    "log"
    "github.com/segmentio/kafka-go"
)

// 消息生产者
type OrderEventProducer struct {
    writer *kafka.Writer
}

func NewOrderEventProducer(brokers []string) *OrderEventProducer {
    return &OrderEventProducer{
        writer: &kafka.Writer{
            Addr:     kafka.TCP(brokers...),
            Topic:    "order-events",
            Balancer: &kafka.LeastBytes{},
        },
    }
}

func (p *OrderEventProducer) PublishOrderCreated(order *Order) error {
    event := OrderEvent{
        Type:    "order.created",
        OrderID: order.ID,
        UserID:  order.UserID,
        Amount:  order.TotalAmount,
        Time:    time.Now(),
    }

    data, err := json.Marshal(event)
    if err != nil {
        return err
    }

    return p.writer.WriteMessages(context.Background(),
        kafka.Message{
            Key:   []byte(strconv.FormatInt(order.ID, 10)),
            Value: data,
            Headers: []kafka.Header{
                {Key: "event-type", Value: []byte("order.created")},
            },
        },
    )
}

// 消息消费者
type OrderEventConsumer struct {
    reader *kafka.Reader
}

func NewOrderEventConsumer(brokers []string, groupID string) *OrderEventConsumer {
    return &OrderEventConsumer{
        reader: kafka.NewReader(kafka.ReaderConfig{
            Brokers:   brokers,
            Topic:     "order-events",
            GroupID:   groupID,
            MinBytes:  10e3,
            MaxBytes:  10e6,
            MaxWait:   1 * time.Second,
        }),
    }
}

func (c *OrderEventConsumer) Consume(ctx context.Context) {
    for {
        msg, err := c.reader.ReadMessage(ctx)
        if err != nil {
            log.Printf("read message error: %v", err)
            continue
        }

        var event OrderEvent
        if err := json.Unmarshal(msg.Value, &event); err != nil {
            log.Printf("unmarshal error: %v", err)
            continue
        }

        // 处理事件
        switch event.Type {
        case "order.created":
            c.handleOrderCreated(event)
        case "order.paid":
            c.handleOrderPaid(event)
        case "order.cancelled":
            c.handleOrderCancelled(event)
        }

        // 提交偏移量
        if err := c.reader.CommitMessages(ctx, msg); err != nil {
            log.Printf("commit error: %v", err)
        }
    }
}

func (c *OrderEventConsumer) handleOrderCreated(event OrderEvent) {
    log.Printf("Processing order created: %d", event.OrderID)
    // 更新库存、发送通知等
}

func (c *OrderEventConsumer) handleOrderPaid(event OrderEvent) {
    log.Printf("Processing order paid: %d", event.OrderID)
    // 发货、更新订单状态等
}

func (c *OrderEventConsumer) handleOrderCancelled(event OrderEvent) {
    log.Printf("Processing order cancelled: %d", event.OrderID)
    // 退款、释放库存等
}

四、服务发现与负载均衡

4.1 基于 Consul 的服务发现

// discovery/consul_discovery.go
package main

import (
    "fmt"
    "log"
    "math/rand"
    "sync"
    "time"
    "github.com/hashicorp/consul/api"
)

// 服务注册
type ServiceRegistry struct {
    client *api.Client
    mu     sync.RWMutex
    services map[string][]*api.ServiceEntry
}

func NewServiceRegistry(address string) (*ServiceRegistry, error) {
    config := api.DefaultConfig()
    config.Address = address
    
    client, err := api.NewClient(config)
    if err != nil {
        return nil, err
    }

    return &ServiceRegistry{
        client:   client,
        services: make(map[string][]*api.ServiceEntry),
    }, nil
}

func (r *ServiceRegistry) Register(serviceName, instanceID string, port int) error {
    registration := &api.AgentServiceRegistration{
        ID:      instanceID,
        Name:    serviceName,
        Port:    port,
        Check: &api.AgentServiceCheck{
            HTTP:     fmt.Sprintf("http://localhost:%d/health", port),
            Interval: "10s",
            Timeout:  "5s",
        },
    }

    return r.client.Agent().ServiceRegister(registration)
}

func (r *ServiceRegistry) Deregister(instanceID string) error {
    return r.client.Agent().ServiceDeregister(instanceID)
}

func (r *ServiceRegistry) Discover(serviceName string) ([]*api.ServiceEntry, error) {
    entries, _, err := r.client.Health().Service(serviceName, "", true, nil)
    if err != nil {
        return nil, err
    }

    r.mu.Lock()
    r.services[serviceName] = entries
    r.mu.Unlock()

    return entries, nil
}

// 负载均衡客户端
type LoadBalancer struct {
    registry *ServiceRegistry
    mu       sync.RWMutex
    cache    map[string][]string // serviceName → addresses
}

func NewLoadBalancer(registry *ServiceRegistry) *LoadBalancer {
    lb := &LoadBalancer{
        registry: registry,
        cache:    make(map[string][]string),
    }

    // 定期刷新服务列表
    go lb.refreshLoop()
    return lb
}

func (lb *LoadBalancer) refreshLoop() {
    ticker := time.NewTicker(30 * time.Second)
    for range ticker.C {
        lb.mu.Lock()
        for serviceName := range lb.cache {
            entries, err := lb.registry.Discover(serviceName)
            if err != nil {
                log.Printf("refresh service %s error: %v", serviceName, err)
                continue
            }

            addresses := make([]string, 0, len(entries))
            for _, entry := range entries {
                addr := fmt.Sprintf("%s:%d", entry.Service.Address, entry.Service.Port)
                addresses = append(addresses, addr)
            }
            lb.cache[serviceName] = addresses
        }
        lb.mu.Unlock()
    }
}

// 轮询负载均衡
func (lb *LoadBalancer) RoundRobin(serviceName string) (string, error) {
    lb.mu.RLock()
    addresses, ok := lb.cache[serviceName]
    lb.mu.RUnlock()

    if !ok || len(addresses) == 0 {
        // 从注册中心获取
        entries, err := lb.registry.Discover(serviceName)
        if err != nil {
            return "", err
        }

        addresses = make([]string, 0, len(entries))
        for _, entry := range entries {
            addr := fmt.Sprintf("%s:%d", entry.Service.Address, entry.Service.Port)
            addresses = append(addresses, addr)
        }

        lb.mu.Lock()
        lb.cache[serviceName] = addresses
        lb.mu.Unlock()
    }

    if len(addresses) == 0 {
        return "", fmt.Errorf("no available instances for %s", serviceName)
    }

    // 随机选择一个
    return addresses[rand.Intn(len(addresses))], nil
}

4.2 健康检查

// discovery/health_check.go
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "sync"
    "time"
)

type HealthStatus string

const (
    StatusHealthy   HealthStatus = "healthy"
    StatusDegraded  HealthStatus = "degraded"
    StatusUnhealthy HealthStatus = "unhealthy"
)

type HealthChecker struct {
    mu       sync.RWMutex
    checks   map[string]HealthCheck
    status   HealthStatus
    details  map[string]interface{}
}

type HealthCheck struct {
    Name     string
    Interval time.Duration
    Timeout  time.Duration
    Check    func() error
    lastCheck time.Time
    lastError error
}

func NewHealthChecker() *HealthChecker {
    hc := &HealthChecker{
        checks:  make(map[string]HealthCheck),
        status:  StatusHealthy,
        details: make(map[string]interface{}),
    }
    go hc.runChecks()
    return hc
}

func (hc *HealthChecker) RegisterCheck(name string, interval, timeout time.Duration, check func() error) {
    hc.mu.Lock()
    hc.checks[name] = HealthCheck{
        Name:     name,
        Interval: interval,
        Timeout:  timeout,
        Check:    check,
    }
    hc.mu.Unlock()
}

func (hc *HealthChecker) runChecks() {
    ticker := time.NewTicker(5 * time.Second)
    for range ticker.C {
        hc.mu.Lock()
        for name, check := range hc.checks {
            if time.Since(check.lastCheck) < check.Interval {
                continue
            }

            err := check.Check()
            check.lastCheck = time.Now()
            check.lastError = err
            hc.checks[name] = check

            if err != nil {
                hc.details[name] = err.Error()
            } else {
                hc.details[name] = "ok"
            }
        }
        hc.updateOverallStatus()
        hc.mu.Unlock()
    }
}

func (hc *HealthChecker) updateOverallStatus() {
    hasErrors := false
    for _, check := range hc.checks {
        if check.lastError != nil {
            hasErrors = true
            break
        }
    }

    if hasErrors {
        hc.status = StatusDegraded
    } else {
        hc.status = StatusHealthy
    }
}

func (hc *HealthChecker) HealthEndpoint(w http.ResponseWriter, r *http.Request) {
    hc.mu.RLock()
    defer hc.mu.RUnlock()

    status := HealthResponse{
        Status:  hc.status,
        Details: hc.details,
        Time:    time.Now(),
    }

    w.Header().Set("Content-Type", "application/json")
    if hc.status != StatusHealthy {
        w.WriteHeader(http.StatusServiceUnavailable)
    }
    json.NewEncoder(w).Encode(status)
}

type HealthResponse struct {
    Status  HealthStatus          `json:"status"`
    Details map[string]interface{} `json:"details"`
    Time    time.Time             `json:"time"`
}

五、分布式事务

5.1 Saga 模式

// transaction/saga.go
package main

import (
    "context"
    "log"
    "time"
)

// Saga 编排器
type SagaOrchestrator struct {
    steps []SagaStep
}

type SagaStep struct {
    Name     string
    Execute  func(ctx context.Context) error
    Compensate func(ctx context.Context) error
}

func NewSagaOrchestrator() *SagaOrchestrator {
    return &SagaOrchestrator{}
}

func (s *SagaOrchestrator) AddStep(name string, execute, compensate func(ctx context.Context) error) {
    s.steps = append(s.steps, SagaStep{
        Name:       name,
        Execute:    execute,
        Compensate: compensate,
    })
}

func (s *SagaOrchestrator) Execute(ctx context.Context) error {
    var executed []SagaStep

    for _, step := range s.steps {
        log.Printf("Executing step: %s", step.Name)
        
        if err := step.Execute(ctx); err != nil {
            log.Printf("Step %s failed: %v, starting compensation", step.Name, err)
            
            // 回滚已执行的步骤
            for i := len(executed) - 1; i >= 0; i-- {
                compStep := executed[i]
                log.Printf("Compensating step: %s", compStep.Name)
                if compErr := compStep.Compensate(ctx); compErr != nil {
                    log.Printf("Compensation failed for step %s: %v", compStep.Name, compErr)
                }
            }
            
            return err
        }
        
        executed = append(executed, step)
    }
    
    log.Printf("Saga completed successfully")
    return nil
}

// 订单创建 Saga 示例
func orderCreationSaga() *SagaOrchestrator {
    saga := NewSagaOrchestrator()

    // Step 1: 创建订单
    saga.AddStep("create-order",
        func(ctx context.Context) error {
            // 创建订单
            return nil
        },
        func(ctx context.Context) error {
            // 取消订单
            return nil
        },
    )

    // Step 2: 预留库存
    saga.AddStep("reserve-inventory",
        func(ctx context.Context) error {
            // 调用库存服务预留库存
            return nil
        },
        func(ctx context.Context) error {
            // 释放库存
            return nil
        },
    )

    // Step 3: 扣减余额
    saga.AddStep("deduct-balance",
        func(ctx context.Context) error {
            // 调用账户服务扣款
            return nil
        },
        func(ctx context.Context) error {
            // 退款
            return nil
        },
    )

    return saga
}

5.2 TCC 模式

// transaction/tcc.go
package main

import (
    "context"
    "log"
    "sync"
)

// TCC 事务接口
type TCCResource interface {
    Try(ctx context.Context) error
    Confirm(ctx context.Context) error
    Cancel(ctx context.Context) error
}

// 库存资源 TCC 实现
type InventoryResource struct {
    mu        sync.Mutex
    reserved  map[int64]int // productID → quantity
}

func NewInventoryResource() *InventoryResource {
    return &InventoryResource{
        reserved: make(map[int64]int),
    }
}

func (r *InventoryResource) Try(ctx context.Context, productID int64, quantity int) error {
    r.mu.Lock()
    defer r.mu.Unlock()

    // 检查库存并预留
    currentStock := getCurrentStock(productID)
    if currentStock < quantity {
        return fmt.Errorf("insufficient stock for product %d", productID)
    }

    r.reserved[productID] = quantity
    log.Printf("Try: Reserved %d units of product %d", quantity, productID)
    return nil
}

func (r *InventoryResource) Confirm(ctx context.Context, productID int64) error {
    r.mu.Lock()
    defer r.mu.Unlock()

    quantity, ok := r.reserved[productID]
    if !ok {
        return fmt.Errorf("no reservation found for product %d", productID)
    }

    // 确认扣减库存
    deductStock(productID, quantity)
    delete(r.reserved, productID)
    log.Printf("Confirm: Deducted %d units of product %d", quantity, productID)
    return nil
}

func (r *InventoryResource) Cancel(ctx context.Context, productID int64) error {
    r.mu.Lock()
    defer r.mu.Unlock()

    quantity, ok := r.reserved[productID]
    if !ok {
        return nil // 没有预留,无需取消
    }

    // 释放预留的库存
    delete(r.reserved, productID)
    log.Printf("Cancel: Released %d units of product %d", quantity, productID)
    return nil
}

// TCC 事务管理器
type TCCTransactionManager struct {
    resources []TCCResource
}

func NewTCCTransactionManager() *TCCTransactionManager {
    return &TCCTransactionManager{}
}

func (tm *TCCTransactionManager) AddResource(resource TCCResource) {
    tm.resources = append(tm.resources, resource)
}

func (tm *TCCTransactionManager) Execute(ctx context.Context) error {
    // Phase 1: Try
    for _, resource := range tm.resources {
        if err := resource.Try(ctx); err != nil {
            log.Printf("Try phase failed: %v, starting cancel", err)
            // Cancel all previous resources
            tm.cancelAll(ctx)
            return err
        }
    }

    // Phase 2: Confirm
    for _, resource := range tm.resources {
        if err := resource.Confirm(ctx); err != nil {
            log.Printf("Confirm phase failed: %v", err)
            // 记录异常,需要人工介入或定时补偿
            return err
        }
    }

    return nil
}

func (tm *TCCTransactionManager) cancelAll(ctx context.Context) {
    for _, resource := range tm.resources {
        if err := resource.Cancel(ctx); err != nil {
            log.Printf("Cancel failed: %v", err)
        }
    }
}

六、链路追踪

6.1 OpenTelemetry 集成

// tracing/opentelemetry.go
package main

import (
    "context"
    "log"
    "net/http"
    "time"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/exporters/jaeger"
    "go.opentelemetry.io/otel/sdk/resource"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
    "go.opentelemetry.io/otel/trace"
)

// 初始化 tracer provider
func initTracer() (*sdktrace.TracerProvider, error) {
    exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(
        jaeger.WithEndpoint("http://localhost:14268/api/traces"),
    ))
    if err != nil {
        return nil, err
    }

    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("order-service"),
            attribute.String("environment", "production"),
        )),
    )

    otel.SetTracerProvider(tp)
    return tp, nil
}

// HTTP 中间件:自动创建 span
func TracingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        tracer := otel.Tracer("http-server")
        ctx, span := tracer.Start(r.Context(), r.URL.Path,
            trace.WithAttributes(
                semconv.HTTPMethodKey.String(r.Method),
                semconv.HTTPURLKey.String(r.URL.String()),
                semconv.HTTPTargetKey.String(r.URL.Path),
            ),
        )
        defer span.End()

        // 将 context 传递给下游
        r = r.WithContext(ctx)
        next.ServeHTTP(w, r)
    })
}

// 业务代码中手动创建 span
func processOrder(ctx context.Context, orderID int64) error {
    tracer := otel.Tracer("order-service")
    ctx, span := tracer.Start(ctx, "process-order",
        trace.WithAttributes(
            attribute.Int64("order.id", orderID),
        ),
    )
    defer span.End()

    // 调用库存服务
    if err := reserveInventory(ctx, orderID); err != nil {
        span.RecordError(err)
        span.SetStatus(sdktrace.StatusError, err.Error())
        return err
    }

    // 调用支付服务
    if err := processPayment(ctx, orderID); err != nil {
        span.RecordError(err)
        span.SetStatus(sdktrace.StatusError, err.Error())
        return err
    }

    span.SetStatus(sdktrace.StatusOk, "")
    return nil
}

func reserveInventory(ctx context.Context, orderID int64) error {
    tracer := otel.Tracer("order-service")
    _, span := tracer.Start(ctx, "reserve-inventory",
        trace.WithAttributes(
            attribute.Int64("order.id", orderID),
        ),
    )
    defer span.End()

    // 模拟调用库存服务
    time.Sleep(100 * time.Millisecond)
    return nil
}

func processPayment(ctx context.Context, orderID int64) error {
    tracer := otel.Tracer("order-service")
    _, span := tracer.Start(ctx, "process-payment",
        trace.WithAttributes(
            attribute.Int64("order.id", orderID),
        ),
    )
    defer span.End()

    // 模拟调用支付服务
    time.Sleep(200 * time.Millisecond)
    return nil
}

七、配置管理

7.1 集中配置中心

// config/config_center.go
package main

import (
    "context"
    "encoding/json"
    "log"
    "sync"
    "time"
    "github.com/fsnotify/fsnotify"
    "github.com/spf13/viper"
)

// 配置管理器
type ConfigManager struct {
    mu       sync.RWMutex
    config   *AppConfig
    watchers []ConfigWatcher
}

type AppConfig struct {
    Server   ServerConfig   `mapstructure:"server"`
    Database DatabaseConfig `mapstructure:"database"`
    Redis    RedisConfig    `mapstructure:"redis"`
    Kafka    KafkaConfig    `mapstructure:"kafka"`
}

type ServerConfig struct {
    Port    int           `mapstructure:"port"`
    Timeout time.Duration `mapstructure:"timeout"`
}

type DatabaseConfig struct {
    Host     string `mapstructure:"host"`
    Port     int    `mapstructure:"port"`
    User     string `mapstructure:"user"`
    Password string `mapstructure:"password"`
    DBName   string `mapstructure:"dbname"`
}

type RedisConfig struct {
    Address  string `mapstructure:"address"`
    Password string `mapstructure:"password"`
    DB       int    `mapstructure:"db"`
}

type KafkaConfig struct {
    Brokers []string `mapstructure:"brokers"`
    Topic   string   `mapstructure:"topic"`
}

type ConfigWatcher func(oldConfig, newConfig *AppConfig)

func NewConfigManager() *ConfigManager {
    return &ConfigManager{}
}

func (cm *ConfigManager) Load(path string) error {
    viper.SetConfigFile(path)
    viper.AutomaticEnv() // 支持环境变量覆盖

    if err := viper.ReadInConfig(); err != nil {
        return err
    }

    var config AppConfig
    if err := viper.Unmarshal(&config); err != nil {
        return err
    }

    cm.mu.Lock()
    cm.config = &config
    cm.mu.Unlock()

    // 监听配置文件变化
    viper.WatchConfig()
    viper.OnConfigChange(func(e fsnotify.Event) {
        log.Printf("Config file changed: %s", e.Name)
        
        var newConfig AppConfig
        if err := viper.Unmarshal(&newConfig); err != nil {
            log.Printf("Failed to parse new config: %v", err)
            return
        }

        cm.mu.Lock()
        oldConfig := cm.config
        cm.config = &newConfig
        cm.mu.Unlock()

        // 通知所有 watcher
        for _, watcher := range cm.watchers {
            watcher(oldConfig, &newConfig)
        }
    })

    return nil
}

func (cm *ConfigManager) GetConfig() *AppConfig {
    cm.mu.RLock()
    defer cm.mu.RUnlock()
    return cm.config
}

func (cm *ConfigManager) Watch(watcher ConfigWatcher) {
    cm.mu.Lock()
    cm.watchers = append(cm.watchers, watcher)
    cm.mu.Unlock()
}

// 使用示例
func main() {
    cm := NewConfigManager()
    if err := cm.Load("config.yaml"); err != nil {
        log.Fatal(err)
    }

    // 注册配置变更监听
    cm.Watch(func(oldConfig, newConfig *AppConfig) {
        if oldConfig.Server.Port != newConfig.Server.Port {
            log.Printf("Server port changed from %d to %d", 
                oldConfig.Server.Port, newConfig.Server.Port)
            // 重启 HTTP 服务器
        }
    })

    // 获取配置
    config := cm.GetConfig()
    log.Printf("Server port: %d", config.Server.Port)
}

八、总结

8.1 核心要点

概念

要点

面试高频

服务拆分​

业务能力/子域/数据边界

⭐⭐⭐⭐⭐

服务通信​

REST/gRPC/消息队列

⭐⭐⭐⭐⭐

服务发现​

Consul/Etcd/ZooKeeper

⭐⭐⭐⭐

负载均衡​

轮询/随机/一致性哈希

⭐⭐⭐⭐

分布式事务​

Saga/TCC/最终一致性

⭐⭐⭐⭐⭐

链路追踪​

OpenTelemetry/Jaeger

⭐⭐⭐⭐

配置管理​

Viper/配置中心

⭐⭐⭐

健康检查​

存活/就绪探针

⭐⭐⭐⭐

8.2 选择指南

通信方式选择:
┌─────────────────────────────────────────────────────────────┐
│  同步调用:REST/gRPC                                       │
│  - 实时性强,需要立即返回结果                              │
│  - 适用于查询类操作                                        │
│                                                             │
│  异步调用:消息队列                                        │
│  - 解耦服务,削峰填谷                                      │
│  - 适用于不需要立即返回的操作                              │
│  - 提高系统的可用性和伸缩性                                │
│                                                             │
│  分布式事务选择:                                          │
│  - 强一致性:TCC 模式                                      │
│  - 最终一致性:Saga 模式                                   │
│  - 简单场景:本地消息表                                    │
└─────────────────────────────────────────────────────────────┘

8.3 记忆口诀

微服务拆分看业务,高内聚低耦合是关键
服务通信三件套,REST gRPC 消息队列
服务发现 Consul,健康检查不能少
负载均衡轮询好,一致性哈希也不错
分布式事务难,Saga TCC 来帮忙
链路追踪 OpenTelemetry,问题定位快准狠
配置管理要集中,热更新少不了

8.4 下讲预告

第11讲:Go 云原生实战 —— Docker + Kubernetes 部署与编排

我们将深入学习:

  • Docker 镜像构建与优化

  • Kubernetes 核心概念

  • Pod/Service/Deployment 配置

  • 配置管理与 Secrets

  • 监控与日志收集

  • CI/CD 流水线搭建

准备好了吗?让我们在第11讲再见!


🧰 开发之余的小工具推荐​

处理 Base64、JWT 解析、JSON 格式化、Crontab 计算、PDF 合并压缩这些碎片需求,我常用一个纯前端本地工具箱:zz365.top。所有计算在浏览器完成,文件不上服务器,关页即清。免费、无登录、无广告,适合开发者当常驻标签页。

更多推荐