【Go语言学习系列56】第四阶段项目实战:高性能API网关

📚 原创系列: “Go语言学习系列”

🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。

🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Go技术文章。

📑 Go语言学习系列导航

本文是【Go语言学习系列】的第56篇,当前位于第四阶段(专业篇)

🚀 第四阶段:专业篇
  1. 性能优化(一):编写高性能Go代码
  2. 性能优化(二):profiling深入
  3. 性能优化(三):并发调优
  4. 代码质量与最佳实践
  5. 设计模式在Go中的应用(一)
  6. 设计模式在Go中的应用(二)
  7. 云原生Go应用开发
  8. 分布式系统基础
  9. 高可用系统设计
  10. 安全编程实践
  11. Go汇编基础
  12. 第四阶段项目实战:高性能API网关 👈 当前位置

📚 查看完整Go语言学习系列导航

📖 文章导读

在本文中,您将了解:

  • API网关的基本概念和架构设计
  • 使用Go语言构建高性能API网关的核心组件
  • 路由、负载均衡、限流、熔断等关键功能的实现
  • 性能优化策略和监控方案
  • 项目部署和扩展性考虑

API网关架构

第四阶段项目实战:高性能API网关

在前面的文章中,我们已经学习了Go语言的各个方面,从基础语法到高级特性,从并发编程到性能优化。现在,让我们将这些知识应用到实际项目中,构建一个高性能的API网关。

API网关是现代微服务架构中的关键组件,它作为所有客户端请求的入口点,负责路由、负载均衡、认证授权、限流熔断等功能。通过构建一个高性能的API网关,我们可以将前面学到的Go语言知识进行综合应用,并解决实际项目中的挑战。

1. 项目概述

1.1 项目目标

我们的目标是构建一个高性能、可扩展的API网关,具有以下特点:

  • 高性能:能够处理大量并发请求,响应时间低
  • 可扩展:支持水平扩展,能够处理不断增长的流量
  • 可靠性:具有故障恢复能力,支持熔断和降级
  • 可观测性:提供详细的监控和日志,便于问题排查
  • 安全性:支持认证、授权和流量控制

1.2 技术栈选择

为了实现上述目标,我们将使用以下技术栈:

  • Go语言:作为主要开发语言,利用其高性能和并发特性
  • Gin框架:作为HTTP路由和中间件框架
  • gRPC:用于与后端微服务通信
  • Etcd:用于服务发现和配置管理
  • Prometheus:用于监控和指标收集
  • Jaeger:用于分布式追踪
  • Docker & Kubernetes:用于容器化和部署

1.3 项目结构

api-gateway/
├── cmd/                    # 应用程序入口
│   └── gateway/            # 主程序
├── internal/               # 内部包
│   ├── config/             # 配置管理
│   ├── middleware/         # 中间件
│   ├── proxy/              # 代理实现
│   ├── router/             # 路由管理
│   ├── service/            # 服务发现
│   └── utils/              # 工具函数
├── pkg/                    # 可导出的包
│   ├── circuitbreaker/     # 熔断器
│   ├── limiter/            # 限流器
│   └── metrics/            # 指标收集
├── api/                    # API定义
├── configs/                # 配置文件
├── deployments/            # 部署配置
├── docs/                   # 文档
├── scripts/                # 脚本
└── test/                   # 测试

2. 核心功能实现

2.1 路由管理

路由管理是API网关的核心功能,它负责将请求路由到正确的后端服务。

2.1.1 路由配置

我们使用Etcd存储路由配置,支持动态更新:

// 路由配置结构
type RouteConfig struct {
    ID          string            `json:"id"`
    Path        string            `json:"path"`
    Method      string            `json:"method"`
    ServiceName string            `json:"service_name"`
    StripPrefix bool              `json:"strip_prefix"`
    Timeout     time.Duration     `json:"timeout"`
    Retry       int               `json:"retry"`
    Headers     map[string]string `json:"headers"`
}

// 路由管理器
type RouterManager struct {
    routes     map[string]*RouteConfig
    etcdClient *clientv3.Client
    mu         sync.RWMutex
}

// 初始化路由管理器
func NewRouterManager(etcdEndpoints []string) (*RouterManager, error) {
    // 连接Etcd
    etcdClient, err := clientv3.New(clientv3.Config{
        Endpoints: etcdEndpoints,
    })
    if err != nil {
        return nil, err
    }
    
    rm := &RouterManager{
        routes:     make(map[string]*RouteConfig),
        etcdClient: etcdClient,
    }
    
    // 加载初始路由配置
    if err := rm.loadRoutes(); err != nil {
        return nil, err
    }
    
    // 监听路由配置变化
    go rm.watchRoutes()
    
    return rm, nil
}
2.1.2 动态路由更新

通过监听Etcd中的配置变化,实现路由的动态更新:

// 监听路由配置变化
func (rm *RouterManager) watchRoutes() {
    watchChan := rm.etcdClient.Watch(context.Background(), "/routes/", clientv3.WithPrefix())
    
    for watchResp := range watchChan {
        for _, event := range watchResp.Events {
            switch event.Type {
            case clientv3.EventTypePut:
                // 更新或添加路由
                var route RouteConfig
                if err := json.Unmarshal(event.Kv.Value, &route); err != nil {
                    log.Printf("解析路由配置失败: %v", err)
                    continue
                }
                
                rm.mu.Lock()
                rm.routes[route.ID] = &route
                rm.mu.Unlock()
                
                log.Printf("路由已更新: %s", route.ID)
                
            case clientv3.EventTypeDelete:
                // 删除路由
                routeID := strings.TrimPrefix(string(event.Kv.Key), "/routes/")
                
                rm.mu.Lock()
                delete(rm.routes, routeID)
                rm.mu.Unlock()
                
                log.Printf("路由已删除: %s", routeID)
            }
        }
    }
}

2.2 服务发现与负载均衡

API网关需要能够发现后端服务并进行负载均衡。

2.2.1 服务发现

使用Etcd实现服务发现:

// 服务注册信息
type ServiceInstance struct {
    ID        string            `json:"id"`
    Name      string            `json:"name"`
    Address   string            `json:"address"`
    Port      int               `json:"port"`
    Metadata  map[string]string `json:"metadata"`
    Timestamp int64             `json:"timestamp"`
}

// 服务发现管理器
type ServiceDiscovery struct {
    services  map[string][]*ServiceInstance
    etcdClient *clientv3.Client
    mu        sync.RWMutex
}

// 获取服务实例
func (sd *ServiceDiscovery) GetInstances(serviceName string) ([]*ServiceInstance, error) {
    sd.mu.RLock()
    defer sd.mu.RUnlock()
    
    instances, ok := sd.services[serviceName]
    if !ok {
        return nil, fmt.Errorf("服务 %s 不存在", serviceName)
    }
    
    // 过滤掉过期的实例
    now := time.Now().Unix()
    validInstances := make([]*ServiceInstance, 0, len(instances))
    
    for _, instance := range instances {
        if now-instance.Timestamp < 30 { // 30秒内的实例视为有效
            validInstances = append(validInstances, instance)
        }
    }
    
    if len(validInstances) == 0 {
        return nil, fmt.Errorf("服务 %s 没有可用实例", serviceName)
    }
    
    return validInstances, nil
}
2.2.2 负载均衡

实现多种负载均衡策略:

// 负载均衡策略
type LoadBalancer interface {
    Next(instances []*ServiceInstance) *ServiceInstance
}

// 轮询负载均衡
type RoundRobinBalancer struct {
    current uint64
}

func (lb *RoundRobinBalancer) Next(instances []*ServiceInstance) *ServiceInstance {
    if len(instances) == 0 {
        return nil
    }
    
    // 原子操作获取下一个索引
    next := atomic.AddUint64(&lb.current, 1)
    index := next % uint64(len(instances))
    
    return instances[index]
}

// 随机负载均衡
type RandomBalancer struct{}

func (lb *RandomBalancer) Next(instances []*ServiceInstance) *ServiceInstance {
    if len(instances) == 0 {
        return nil
    }
    
    index := rand.Intn(len(instances))
    return instances[index]
}

// 加权轮询负载均衡
type WeightedRoundRobinBalancer struct {
    current uint64
    weights map[string]int
}

func (lb *WeightedRoundRobinBalancer) Next(instances []*ServiceInstance) *ServiceInstance {
    if len(instances) == 0 {
        return nil
    }
    
    // 计算总权重
    totalWeight := 0
    for _, instance := range instances {
        weight := lb.weights[instance.ID]
        if weight <= 0 {
            weight = 1 // 默认权重为1
        }
        totalWeight += weight
    }
    
    // 获取下一个索引
    next := atomic.AddUint64(&lb.current, 1)
    value := next % uint64(totalWeight)
    
    // 根据权重选择实例
    currentWeight := 0
    for _, instance := range instances {
        weight := lb.weights[instance.ID]
        if weight <= 0 {
            weight = 1
        }
        currentWeight += weight
        if uint64(currentWeight) > value {
            return instance
        }
    }
    
    // 默认返回第一个实例
    return instances[0]
}

2.3 请求转发与响应处理

实现请求转发和响应处理的核心逻辑:

// 代理处理器
type ProxyHandler struct {
    routerManager    *RouterManager
    serviceDiscovery *ServiceDiscovery
    loadBalancer    LoadBalancer
    httpClient      *http.Client
}

// 处理请求
func (ph *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 查找匹配的路由
    route := ph.findRoute(r)
    if route == nil {
        http.NotFound(w, r)
        return
    }
    
    // 获取服务实例
    instances, err := ph.serviceDiscovery.GetInstances(route.ServiceName)
    if err != nil {
        http.Error(w, "服务不可用", http.StatusServiceUnavailable)
        return
    }
    
    // 选择实例
    instance := ph.loadBalancer.Next(instances)
    if instance == nil {
        http.Error(w, "没有可用实例", http.StatusServiceUnavailable)
        return
    }
    
    // 构建目标URL
    targetURL := fmt.Sprintf("http://%s:%d", instance.Address, instance.Port)
    if route.StripPrefix {
        // 移除路径前缀
        path := strings.TrimPrefix(r.URL.Path, route.Path)
        targetURL += path
    } else {
        targetURL += r.URL.Path
    }
    
    // 创建请求
    req, err := http.NewRequest(r.Method, targetURL, r.Body)
    if err != nil {
        http.Error(w, "创建请求失败", http.StatusInternalServerError)
        return
    }
    
    // 复制请求头
    for key, values := range r.Header {
        for _, value := range values {
            req.Header.Add(key, value)
        }
    }
    
    // 添加自定义头
    for key, value := range route.Headers {
        req.Header.Set(key, value)
    }
    
    // 设置超时
    ctx, cancel := context.WithTimeout(r.Context(), route.Timeout)
    defer cancel()
    req = req.WithContext(ctx)
    
    // 发送请求
    resp, err := ph.httpClient.Do(req)
    if err != nil {
        http.Error(w, "请求失败", http.StatusBadGateway)
        return
    }
    defer resp.Body.Close()
    
    // 复制响应头
    for key, values := range resp.Header {
        for _, value := range values {
            w.Header().Add(key, value)
        }
    }
    
    // 设置状态码
    w.WriteHeader(resp.StatusCode)
    
    // 复制响应体
    io.Copy(w, resp.Body)
}

2.4 限流与熔断

实现限流和熔断机制,保护后端服务:

2.4.1 限流实现
// 限流器接口
type RateLimiter interface {
    Allow(key string) bool
}

// 令牌桶限流器
type TokenBucketLimiter struct {
    buckets map[string]*tokenBucket
    mu      sync.RWMutex
}

type tokenBucket struct {
    rate       float64
    capacity   int
    tokens     float64
    lastUpdate time.Time
}

func NewTokenBucketLimiter() *TokenBucketLimiter {
    return &TokenBucketLimiter{
        buckets: make(map[string]*tokenBucket),
    }
}

func (l *TokenBucketLimiter) Allow(key string) bool {
    l.mu.Lock()
    defer l.mu.Unlock()
    
    bucket, ok := l.buckets[key]
    if !ok {
        // 默认配置:每秒10个请求,容量20
        bucket = &tokenBucket{
            rate:       10,
            capacity:   20,
            tokens:     20,
            lastUpdate: time.Now(),
        }
        l.buckets[key] = bucket
    }
    
    now := time.Now()
    // 添加新令牌
    elapsed := now.Sub(bucket.lastUpdate).Seconds()
    bucket.tokens = math.Min(bucket.capacity, bucket.tokens+elapsed*bucket.rate)
    bucket.lastUpdate = now
    
    if bucket.tokens >= 1 {
        bucket.tokens--
        return true
    }
    
    return false
}
2.4.2 熔断实现
// 熔断器状态
type CircuitState int

const (
    StateClosed CircuitState = iota
    StateHalfOpen
    StateOpen
)

// 熔断器
type CircuitBreaker struct {
    name           string
    state          CircuitState
    failureCount   int
    lastFailureTime time.Time
    threshold      int
    timeout        time.Duration
    mu             sync.RWMutex
}

func NewCircuitBreaker(name string, threshold int, timeout time.Duration) *CircuitBreaker {
    return &CircuitBreaker{
        name:      name,
        state:     StateClosed,
        threshold: threshold,
        timeout:   timeout,
    }
}

func (cb *CircuitBreaker) Execute(fn func() error) error {
    if !cb.AllowRequest() {
        return fmt.Errorf("熔断器 %s 已打开", cb.name)
    }
    
    err := fn()
    
    cb.RecordResult(err)
    
    return err
}

func (cb *CircuitBreaker) AllowRequest() bool {
    cb.mu.RLock()
    defer cb.mu.RUnlock()
    
    switch cb.state {
    case StateClosed:
        return true
    case StateHalfOpen:
        return true
    case StateOpen:
        // 检查是否超过超时时间
        if time.Since(cb.lastFailureTime) > cb.timeout {
            cb.mu.RUnlock()
            cb.mu.Lock()
            // 再次检查状态,避免并发问题
            if cb.state == StateOpen {
                cb.state = StateHalfOpen
                cb.failureCount = 0
            }
            cb.mu.Unlock()
            cb.mu.RLock()
            return true
        }
        return false
    default:
        return false
    }
}

func (cb *CircuitBreaker) RecordResult(err error) {
    cb.mu.Lock()
    defer cb.mu.Unlock()
    
    if err != nil {
        cb.failureCount++
        cb.lastFailureTime = time.Now()
        
        if cb.state == StateClosed && cb.failureCount >= cb.threshold {
            cb.state = StateOpen
        }
    } else {
        if cb.state == StateHalfOpen {
            cb.state = StateClosed
            cb.failureCount = 0
        }
    }
}

2.5 认证与授权

实现基本的认证和授权机制:

// 认证中间件
func AuthMiddleware(config *config.AuthConfig) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取认证头
        authHeader := c.GetHeader("Authorization")
        if authHeader == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "未提供认证信息"})
            return
        }
        
        // 解析认证头
        parts := strings.Split(authHeader, " ")
        if len(parts) != 2 || parts[0] != "Bearer" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "认证格式错误"})
            return
        }
        
        token := parts[1]
        
        // 验证JWT令牌
        claims, err := validateJWT(token, config.JWTSecret)
        if err != nil {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "无效的令牌"})
            return
        }
        
        // 将用户信息存储在上下文中
        c.Set("user_id", claims.UserID)
        c.Set("roles", claims.Roles)
        
        c.Next()
    }
}

// 授权中间件
func AuthorizationMiddleware(requiredRoles ...string) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取用户角色
        roles, exists := c.Get("roles")
        if !exists {
            c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "未授权"})
            return
        }
        
        userRoles := roles.([]string)
        
        // 检查是否有所需角色
        for _, requiredRole := range requiredRoles {
            for _, userRole := range userRoles {
                if userRole == requiredRole {
                    c.Next()
                    return
                }
            }
        }
        
        c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "权限不足"})
    }
}

3. 性能优化

3.1 连接池优化

优化HTTP客户端连接池,提高性能:

// 创建优化的HTTP客户端
func createOptimizedHTTPClient() *http.Client {
    transport := &http.Transport{
        Proxy: http.ProxyFromEnvironment,
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).DialContext,
        MaxIdleConns:          100,
        MaxIdleConnsPerHost:   100,
        IdleConnTimeout:       90 * time.Second,
        TLSHandshakeTimeout:   10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
        DisableCompression:    true, // 禁用压缩,减少CPU使用
    }
    
    return &http.Client{
        Transport: transport,
        Timeout:   10 * time.Second,
    }
}

3.2 内存优化

使用对象池减少内存分配:

// 请求上下文对象池
var requestContextPool = sync.Pool{
    New: func() interface{} {
        return &RequestContext{}
    },
}

// 获取请求上下文
func getRequestContext() *RequestContext {
    return requestContextPool.Get().(*RequestContext)
}

// 释放请求上下文
func releaseRequestContext(ctx *RequestContext) {
    // 重置字段
    ctx.Reset()
    requestContextPool.Put(ctx)
}

// 请求上下文
type RequestContext struct {
    Route      *RouteConfig
    Instance   *ServiceInstance
    StartTime  time.Time
    TraceID    string
}

// 重置请求上下文
func (ctx *RequestContext) Reset() {
    ctx.Route = nil
    ctx.Instance = nil
    ctx.StartTime = time.Time{}
    ctx.TraceID = ""
}

3.3 并发优化

使用工作池处理请求:

// 工作池
type WorkerPool struct {
    workers  int
    tasks    chan func()
    wg       sync.WaitGroup
}

// 创建工作池
func NewWorkerPool(workers int) *WorkerPool {
    pool := &WorkerPool{
        workers: workers,
        tasks:   make(chan func(), 1000),
    }
    
    pool.Start()
    
    return pool
}

// 启动工作池
func (p *WorkerPool) Start() {
    p.wg.Add(p.workers)
    
    for i := 0; i < p.workers; i++ {
        go func() {
            defer p.wg.Done()
            
            for task := range p.tasks {
                task()
            }
        }()
    }
}

// 提交任务
func (p *WorkerPool) Submit(task func()) {
    p.tasks <- task
}

// 关闭工作池
func (p *WorkerPool) Shutdown() {
    close(p.tasks)
    p.wg.Wait()
}

4. 监控与可观测性

4.1 指标收集

使用Prometheus收集指标:

// 指标定义
var (
    requestCounter = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "api_gateway_requests_total",
            Help: "API网关请求总数",
        },
        []string{"method", "path", "status"},
    )
    
    requestDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "api_gateway_request_duration_seconds",
            Help:    "API网关请求处理时间",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "path"},
    )
    
    activeRequests = prometheus.NewGauge(
        prometheus.GaugeOpts{
            Name: "api_gateway_active_requests",
            Help: "当前活跃请求数",
        },
    )
)

// 初始化指标
func initMetrics() {
    prometheus.MustRegister(requestCounter)
    prometheus.MustRegister(requestDuration)
    prometheus.MustRegister(activeRequests)
}

// 指标中间件
func MetricsMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        
        // 增加活跃请求计数
        activeRequests.Inc()
        defer activeRequests.Dec()
        
        // 处理请求
        c.Next()
        
        // 记录请求计数
        requestCounter.WithLabelValues(
            c.Request.Method,
            c.Request.URL.Path,
            fmt.Sprintf("%d", c.Writer.Status()),
        ).Inc()
        
        // 记录请求处理时间
        requestDuration.WithLabelValues(
            c.Request.Method,
            c.Request.URL.Path,
        ).Observe(time.Since(start).Seconds())
    }
}

4.2 分布式追踪

使用Jaeger实现分布式追踪:

// 初始化追踪器
func initTracer(serviceName string, jaegerEndpoint string) (opentracing.Tracer, error) {
    cfg := &jaeger.Config{
        ServiceName: serviceName,
        Sampler: &jaeger.SamplerConfig{
            Type:  jaeger.SamplerTypeConst,
            Param: 1,
        },
        Reporter: &jaeger.ReporterConfig{
            LogSpans:           true,
            LocalAgentHostPort: jaegerEndpoint,
        },
    }
    
    tracer, _, err := cfg.NewTracer()
    if err != nil {
        return nil, err
    }
    
    opentracing.SetGlobalTracer(tracer)
    
    return tracer, nil
}

// 追踪中间件
func TracingMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 从请求头中提取追踪上下文
        spanCtx, err := opentracing.GlobalTracer().Extract(
            opentracing.HTTPHeaders,
            opentracing.HTTPHeadersCarrier(c.Request.Header),
        )
        
        var span opentracing.Span
        if err == nil {
            // 创建子span
            span = opentracing.GlobalTracer().StartSpan(
                c.Request.URL.Path,
                opentracing.ChildOf(spanCtx),
            )
        } else {
            // 创建根span
            span = opentracing.GlobalTracer().StartSpan(c.Request.URL.Path)
        }
        
        defer span.Finish()
        
        // 将span上下文注入请求头
        err = opentracing.GlobalTracer().Inject(
            span.Context(),
            opentracing.HTTPHeaders,
            opentracing.HTTPHeadersCarrier(c.Request.Header),
        )
        
        if err != nil {
            log.Printf("注入追踪上下文失败: %v", err)
        }
        
        // 将span存储在上下文中
        c.Set("span", span)
        
        c.Next()
        
        // 记录响应状态码
        span.SetTag("http.status_code", c.Writer.Status())
    }
}

4.3 日志记录

使用结构化日志记录请求和响应:

// 日志中间件
func LoggingMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        
        // 处理请求
        c.Next()
        
        // 计算处理时间
        latency := time.Since(start)
        
        // 获取追踪ID
        traceID := ""
        if span, exists := c.Get("span"); exists {
            if s, ok := span.(opentracing.Span); ok {
                traceID = fmt.Sprintf("%v", s.Context().(jaeger.SpanContext).TraceID())
            }
        }
        
        // 记录结构化日志
        log.WithFields(log.Fields{
            "trace_id":    traceID,
            "client_ip":   c.ClientIP(),
            "method":      c.Request.Method,
            "path":        c.Request.URL.Path,
            "status":      c.Writer.Status(),
            "latency_ms":  latency.Milliseconds(),
            "user_agent":  c.Request.UserAgent(),
            "error":       c.Errors.String(),
        }).Info("请求处理完成")
    }
}

5. 部署与扩展

5.1 Docker容器化

创建Dockerfile:

# 构建阶段
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 复制依赖文件
COPY go.mod go.sum ./

# 下载依赖
RUN go mod download

# 复制源代码
COPY . .

# 构建应用
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o api-gateway ./cmd/gateway

# 运行阶段
FROM alpine:latest

WORKDIR /app

# 从构建阶段复制二进制文件
COPY --from=builder /app/api-gateway .

# 暴露端口
EXPOSE 8080

# 运行应用
CMD ["./api-gateway"]

5.2 Kubernetes部署

创建Kubernetes部署配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-gateway
  labels:
    app: api-gateway
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-gateway
  template:
    metadata:
      labels:
        app: api-gateway
    spec:
      containers:
      - name: api-gateway
        image: api-gateway:latest
        ports:
        - containerPort: 8080
        env:
        - name: ETCD_ENDPOINTS
          value: "etcd-0.etcd-headless:2379,etcd-1.etcd-headless:2379,etcd-2.etcd-headless:2379"
        - name: JAEGER_ENDPOINT
          value: "jaeger-agent:6831"
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
  name: api-gateway
spec:
  selector:
    app: api-gateway
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

5.3 水平扩展策略

实现水平扩展的关键点:

  1. 无状态设计:确保API网关是无状态的,所有状态都存储在外部系统(如Etcd)中
  2. 会话亲和性:对于需要会话亲和性的场景,使用基于客户端的路由
  3. 配置同步:确保所有实例共享相同的配置
  4. 负载均衡:使用Kubernetes的Service或外部负载均衡器分发流量

👨‍💻 关于作者与Gopher部落

"Gopher部落"专注于Go语言技术分享,提供从入门到精通的完整学习路线。

🌟 为什么关注我们?

  1. 系统化学习路径:本系列50篇文章循序渐进,带你完整掌握Go开发
  2. 实战驱动教学:理论结合实践,每篇文章都有可操作的代码示例
  3. 持续更新内容:定期分享最新Go生态技术动态与大厂实践经验
  4. 专业技术社区:加入我们的技术交流群,与众多Go开发者共同成长

📱 关注方式

  1. 微信公众号:搜索 “Gopher部落”“GopherTribe”
  2. 优快云专栏:点击页面右上角"关注"按钮

💡 读者福利

关注公众号回复 “API网关” 即可获取:

  • 高性能API网关完整源码
  • 性能优化实战指南
  • 微服务架构设计文档

期待与您在Go语言的学习旅程中共同成长!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gopher部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值