Skip to content

性能优化

VEF Framework 应用的性能优化建议。

数据库优化

使用索引

go
type User struct {
    orm.Model
    Username     string `gorm:"size:50;uniqueIndex"`
    Email        string `gorm:"size:100;index"`
    DepartmentId string `gorm:"size:36;index"`
    CreatedAt    time.Time `gorm:"index"`
}

选择必要字段

go
// Good - select only needed fields
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithSelect("id", "username", "email", "created_at")

// Bad - select all fields
apis.NewFindPageApi[models.User, payloads.UserSearch]()

避免 N+1 查询

go
// Good - use preload
apis.NewFindPageApi[models.User, payloads.UserSearch]().
    WithPreload("Department", "Roles")

// Bad - query in loop
for _, user := range users {
    orm.DB().First(&user.Department, user.DepartmentId)
}

批量操作

go
// Good - batch insert
orm.DB().CreateInBatches(users, 100)

// Bad - insert one by one
for _, user := range users {
    orm.DB().Create(&user)
}

缓存策略

缓存热点数据

go
func (s *ConfigService) Get(key string) (string, error) {
    cacheKey := fmt.Sprintf("config:%s", key)
    
    // Try cache first
    var value string
    if err := cache.Default().Get(cacheKey, &value); err == nil {
        return value, nil
    }
    
    // Load from database
    var config models.Config
    if err := orm.DB().First(&config, "key = ?", key).Error; err != nil {
        return "", err
    }
    
    // Cache for 5 minutes
    cache.Default().Set(cacheKey, config.Value, cache.WithTTL(5*time.Minute))
    
    return config.Value, nil
}

缓存失效策略

go
// Invalidate on update
func (s *ConfigService) Update(key, value string) error {
    if err := orm.DB().Model(&models.Config{}).
        Where("key = ?", key).
        Update("value", value).Error; err != nil {
        return err
    }
    
    // Invalidate cache
    cache.Default().Delete(fmt.Sprintf("config:%s", key))
    
    return nil
}

连接池配置

数据库连接池

yaml
database:
  maxIdleConns: 10      # Minimum connections
  maxOpenConns: 100     # Maximum connections
  connMaxLifetime: 1h   # Connection lifetime
  connMaxIdleTime: 10m  # Idle connection timeout

Redis 连接池

yaml
redis:
  poolSize: 10          # Connection pool size
  minIdleConns: 5       # Minimum idle connections
  maxRetries: 3         # Max retries

分页优化

使用游标分页

go
// For large datasets, use cursor-based pagination
type CursorPageParams struct {
    Cursor   string `json:"cursor"`
    PageSize int    `json:"pageSize"`
}

func (s *OrderService) FindWithCursor(params CursorPageParams) ([]models.Order, string, error) {
    pageSize := params.PageSize
    if pageSize <= 0 || pageSize > 100 {
        pageSize = 20
    }
    
    query := orm.DB().Model(&models.Order{}).Order("created_at DESC, id DESC")
    
    if params.Cursor != "" {
        // Decode cursor (timestamp:id)
        parts := strings.Split(params.Cursor, ":")
        query = query.Where("(created_at, id) < (?, ?)", parts[0], parts[1])
    }
    
    var orders []models.Order
    query.Limit(pageSize + 1).Find(&orders)
    
    var nextCursor string
    if len(orders) > pageSize {
        last := orders[pageSize-1]
        nextCursor = fmt.Sprintf("%s:%s", last.CreatedAt.Format(time.RFC3339), last.Id)
        orders = orders[:pageSize]
    }
    
    return orders, nextCursor, nil
}

异步处理

使用 goroutine

go
func (r *UserResource) CreateUser(ctx fiber.Ctx, params UserParams) error {
    user, err := r.userService.Create(params)
    if err != nil {
        return api.Error(ctx, err.Error())
    }
    
    // Send email asynchronously
    go func() {
        if err := r.emailService.SendWelcomeEmail(user.Email); err != nil {
            log.WithError(err).Error("Failed to send welcome email")
        }
    }()
    
    return api.Success(ctx, user)
}

使用事件总线

go
// Decouple with events
apis.NewCreateApi[models.User, payloads.UserParams]().
    WithHook(api.AfterCreate, func(ctx fiber.Ctx, user *models.User) error {
        // Publish event instead of direct call
        eventbus.PublishAsync(events.UserCreatedEvent{
            UserId:   user.Id,
            Username: user.Username,
            Email:    user.Email,
        })
        return nil
    })

查询优化

使用 Explain 分析

go
// Analyze query performance
var result []map[string]interface{}
orm.DB().Raw("EXPLAIN SELECT * FROM users WHERE department_id = ?", deptId).Scan(&result)
log.WithField("explain", result).Debug("Query explain")

避免全表扫描

go
// Good - use index
orm.DB().Where("department_id = ?", deptId).Find(&users)

// Bad - function on column prevents index use
orm.DB().Where("YEAR(created_at) = ?", 2024).Find(&users)

// Better - use range
orm.DB().Where("created_at >= ? AND created_at < ?", 
    "2024-01-01", "2025-01-01").Find(&users)

监控和分析

慢查询日志

yaml
database:
  logLevel: "warn"  # Log slow queries
  slowThreshold: 200ms

性能指标

go
// Record API response time
func MetricsMiddleware() fiber.Handler {
    return func(ctx *fiber.Ctx) error {
        start := time.Now()
        
        err := ctx.Next()
        
        duration := time.Since(start)
        
        // Record metrics
        metrics.RecordAPILatency(ctx.Path(), ctx.Method(), duration)
        
        return err
    }
}

下一步

基于 Apache License 2.0 许可发布