README
¶
示例 04: 生产环境配置
本示例展示完整的生产环境配置,包含所有最佳实践。
功能展示
- 完整的可观测性:Log + Trace + Metric 三件套
- 生产级配置:连接池、超时、重试等
- 健康检查:数据库连接状态监控
- 优雅关闭:正确清理资源
- 错误处理:重试机制和错误恢复
- 事务支持:ACID 保证
配置清单
Logger 配置
logger.Init(
logger.WithLevel(logger.InfoLevel), // Info 级别
logger.WithFormat(logger.JSONFormat), // JSON 格式
logger.WithStdout(), // 标准输出
logger.WithFile( // 文件输出
"/var/log/app/app.log",
logger.WithFileMaxSize(100), // 100MB 轮转
logger.WithFileMaxAge(7), // 保留 7 天
logger.WithFileMaxBackups(3), // 3 个备份
),
logger.WithTrace("my-service"), // Trace 集成
logger.WithCaller(true), // 记录调用者
)
ORM 配置
client, err := orm.New(
mysql.Open(dsn),
// 日志配置
orm.WithLogger(logger.L()),
orm.WithSlowThreshold(200*time.Millisecond),
orm.WithIgnoreRecordNotFoundError(),
// Trace 配置
orm.WithTrace("orm-client"),
// Metric 配置
orm.WithMetric(metricRecorder),
// 连接池配置(关键!)
orm.WithMaxIdleConns(10),
orm.WithMaxOpenConns(100),
orm.WithConnMaxLifetime(time.Hour),
orm.WithConnMaxIdleTime(10*time.Minute),
)
Trace 配置
import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
exporter, err := otlptracehttp.New(
context.Background(),
otlptracehttp.WithEndpoint("signoz:4318"),
otlptracehttp.WithInsecure(),
)
tp := trace.NewTracerProvider(
trace.WithBatcher(exporter),
trace.WithSampler(trace.TraceIDRatioBased(0.1)), // 10% 采样
)
otel.SetTracerProvider(tp)
连接池配置详解
参数说明
| 参数 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
MaxIdleConns |
10 | 10-20 | 最大空闲连接数 |
MaxOpenConns |
100 | 50-200 | 最大打开连接数 |
ConnMaxLifetime |
1h | 1h | 连接最大生命周期 |
ConnMaxIdleTime |
10m | 5-10m | 连接最大空闲时间 |
如何确定合适的值?
1. MaxOpenConns
MaxOpenConns = (并发请求数 × 平均查询时间) / 目标响应时间
示例:
- 并发请求:1000 QPS
- 平均查询时间:10ms
- 目标响应时间:50ms
MaxOpenConns = (1000 × 0.01) / 0.05 = 200
2. MaxIdleConns
通常设置为 MaxOpenConns 的 10-20%:
MaxIdleConns = MaxOpenConns × 0.15 = 200 × 0.15 = 30
3. 监控和调整
通过健康检查观察:
stats := sqlDB.Stats()
fmt.Printf("Open: %d, InUse: %d, Idle: %d, WaitCount: %d\n",
stats.OpenConnections,
stats.InUse,
stats.Idle,
stats.WaitCount,
)
调整策略:
WaitCount持续增长 → 增加MaxOpenConnsIdle总是很高 → 减少MaxIdleConnsWaitDuration过长 → 增加MaxOpenConns
错误处理最佳实践
1. 重试机制
maxRetries := 3
for i := 0; i < maxRetries; i++ {
if err := client.WithContext(ctx).Create(&user).Error; err != nil {
logger.Warn(ctx, "Operation failed, retrying",
"attempt", i+1,
"error", err,
)
time.Sleep(time.Second * time.Duration(i+1)) // 指数退避
continue
}
break
}
2. 事务处理
err := client.WithContext(ctx).Transaction(func(tx *orm.Client) error {
// 操作 1
if err := tx.Create(&user).Error; err != nil {
return err // 自动回滚
}
// 操作 2
if err := tx.Create(&profile).Error; err != nil {
return err // 自动回滚
}
return nil // 自动提交
})
if err != nil {
logger.Error(ctx, "Transaction failed", "error", err)
}
3. 超时控制
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 查询会在 5 秒后超时
err := client.WithContext(ctx).Find(&users).Error
健康检查
1. HTTP 端点
import "net/http"
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
if err := checkDatabaseHealth(client, r.Context()); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]string{
"status": "unhealthy",
"error": err.Error(),
})
return
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "healthy",
})
})
2. Kubernetes Liveness/Readiness Probe
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
监控和告警
关键指标
-
连接池指标
db_pool_open_connectionsdb_pool_in_usedb_pool_idledb_pool_wait_count
-
查询性能指标
db_query_duration_secondsdb_slow_query_countdb_query_errors_total
-
业务指标
db_query_total(按操作类型)db_rows_affected_total
告警规则示例
# Prometheus Alert Rules
groups:
- name: database
rules:
# 慢查询告警
- alert: HighSlowQueryRate
expr: rate(db_slow_query_count[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "High slow query rate detected"
# 错误率告警
- alert: HighDatabaseErrorRate
expr: rate(db_query_errors_total[5m]) / rate(db_query_total[5m]) > 0.01
for: 5m
labels:
severity: critical
annotations:
summary: "High database error rate (> 1%)"
# 连接池耗尽告警
- alert: DatabaseConnectionPoolExhausted
expr: db_pool_wait_count > 100
for: 5m
labels:
severity: warning
annotations:
summary: "Database connection pool wait count is high"
性能优化建议
1. 索引优化
type User struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"size:100;index"` // 单列索引
Email string `gorm:"size:100;uniqueIndex"` // 唯一索引
Age int `gorm:"index:idx_age_name,priority:1"` // 复合索引
}
2. 查询优化
// ✅ 好:只查询需要的字段
client.Select("id", "name").Find(&users)
// ❌ 坏:查询所有字段
client.Find(&users)
// ✅ 好:使用预加载
client.Preload("Profile").Find(&users)
// ❌ 坏:N+1 查询
for _, user := range users {
client.First(&user.Profile, "user_id = ?", user.ID)
}
3. 批量操作
// ✅ 好:批量插入
client.CreateInBatches(users, 100)
// ❌ 坏:逐条插入
for _, user := range users {
client.Create(&user)
}
4. 连接复用
// ✅ 好:复用连接
db := client.WithContext(ctx)
db.First(&user1)
db.First(&user2)
// ❌ 坏:每次创建新连接
client.WithContext(ctx).First(&user1)
client.WithContext(ctx).First(&user2)
部署检查清单
- 配置从环境变量或配置文件读取
- 日志输出到文件和 stdout
- 启用 JSON 格式日志
- 配置合适的连接池参数
- 启用 Trace 并连接到后端
- 启用 Metric 并暴露端点
- 实现健康检查端点
- 配置慢查询阈值
- 设置监控告警规则
- 测试故障恢复机制
- 准备数据库迁移脚本
- 配置数据库备份策略
运行示例
cd examples/04_production
go run main.go
环境变量配置示例
# .env
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=password
DB_NAME=testdb
DB_MAX_IDLE_CONNS=10
DB_MAX_OPEN_CONNS=100
DB_CONN_MAX_LIFETIME=3600
DB_SLOW_THRESHOLD=200
OTEL_EXPORTER_OTLP_ENDPOINT=signoz:4318
OTEL_SERVICE_NAME=my-service
OTEL_TRACE_SAMPLER=traceidratio
OTEL_TRACE_SAMPLER_ARG=0.1
LOG_LEVEL=info
LOG_FORMAT=json
LOG_FILE=/var/log/app/app.log
生产环境清单
数据库配置
- ✅ 使用连接池
- ✅ 设置超时
- ✅ 启用慢查询日志
- ✅ 配置读写分离(如需要)
- ✅ 使用事务
- ✅ 定期备份
可观测性
- ✅ 结构化日志
- ✅ 分布式追踪
- ✅ 性能指标
- ✅ 健康检查
- ✅ 告警规则
安全性
- ✅ 参数化查询(防 SQL 注入)
- ✅ 最小权限原则
- ✅ 加密敏感信息
- ✅ 审计日志
高可用
- ✅ 自动重试
- ✅ 故障转移
- ✅ 优雅降级
- ✅ 熔断器
相关资源
Documentation
¶
There is no documentation for this package.
Click to show internal directories.
Click to hide internal directories.