537 lines
11 KiB
Markdown
537 lines
11 KiB
Markdown
|
|
# 📋 最佳实践指南
|
|||
|
|
|
|||
|
|
## 开发最佳实践
|
|||
|
|
|
|||
|
|
### 1. 代码规范
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 格式化代码
|
|||
|
|
gofmt -w .
|
|||
|
|
goimports -w .
|
|||
|
|
|
|||
|
|
# 代码检查
|
|||
|
|
golangci-lint run
|
|||
|
|
|
|||
|
|
# 生成文档
|
|||
|
|
godoc -http=:6060
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**编码标准**:
|
|||
|
|
|
|||
|
|
- 遵循 Go 官方编码规范
|
|||
|
|
- 使用有意义的变量和函数名
|
|||
|
|
- 保持函数简洁,单一职责
|
|||
|
|
- 添加必要的注释和文档
|
|||
|
|
|
|||
|
|
### 2. Git 工作流
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 功能分支开发
|
|||
|
|
git checkout -b feature/user-profile
|
|||
|
|
git add .
|
|||
|
|
git commit -m "feat: add user profile management"
|
|||
|
|
git push origin feature/user-profile
|
|||
|
|
|
|||
|
|
# 代码审查后合并
|
|||
|
|
git checkout main
|
|||
|
|
git merge feature/user-profile
|
|||
|
|
git push origin main
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**提交规范**:
|
|||
|
|
|
|||
|
|
- `feat`: 新功能
|
|||
|
|
- `fix`: 修复问题
|
|||
|
|
- `docs`: 文档更新
|
|||
|
|
- `style`: 代码格式修改
|
|||
|
|
- `refactor`: 代码重构
|
|||
|
|
- `test`: 测试相关
|
|||
|
|
- `chore`: 构建过程或辅助工具的变动
|
|||
|
|
|
|||
|
|
### 3. 测试策略
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 运行所有测试
|
|||
|
|
make test
|
|||
|
|
|
|||
|
|
# 只运行单元测试
|
|||
|
|
go test ./internal/domains/...
|
|||
|
|
|
|||
|
|
# 运行集成测试
|
|||
|
|
go test -tags=integration ./test/integration/...
|
|||
|
|
|
|||
|
|
# 生成覆盖率报告
|
|||
|
|
make test-coverage
|
|||
|
|
open coverage.html
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**测试金字塔**:
|
|||
|
|
|
|||
|
|
- **单元测试**:70% - 测试单个函数/方法
|
|||
|
|
- **集成测试**:20% - 测试模块间交互
|
|||
|
|
- **端到端测试**:10% - 测试完整用户流程
|
|||
|
|
|
|||
|
|
### 4. 错误处理
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 统一错误处理
|
|||
|
|
func (s *userService) CreateUser(ctx context.Context, req *dto.CreateUserRequest) (*dto.UserResponse, error) {
|
|||
|
|
// 参数验证
|
|||
|
|
if err := req.Validate(); err != nil {
|
|||
|
|
return nil, errors.NewValidationError("invalid request", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 业务逻辑
|
|||
|
|
user, err := s.userRepo.Create(ctx, req.ToEntity())
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("failed to create user", zap.Error(err))
|
|||
|
|
return nil, errors.NewInternalError("failed to create user")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return dto.ToUserResponse(user), nil
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 日志记录
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 结构化日志
|
|||
|
|
logger.Info("user created successfully",
|
|||
|
|
zap.String("user_id", user.ID),
|
|||
|
|
zap.String("username", user.Username),
|
|||
|
|
zap.Duration("duration", time.Since(start)))
|
|||
|
|
|
|||
|
|
// 错误日志
|
|||
|
|
logger.Error("database connection failed",
|
|||
|
|
zap.Error(err),
|
|||
|
|
zap.String("host", dbHost),
|
|||
|
|
zap.String("database", dbName))
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**日志级别使用**:
|
|||
|
|
|
|||
|
|
- `DEBUG`: 详细调试信息
|
|||
|
|
- `INFO`: 一般信息记录
|
|||
|
|
- `WARN`: 警告信息
|
|||
|
|
- `ERROR`: 错误信息
|
|||
|
|
- `FATAL`: 致命错误
|
|||
|
|
|
|||
|
|
## 安全最佳实践
|
|||
|
|
|
|||
|
|
### 1. 认证和授权
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// JWT 令牌配置
|
|||
|
|
type JWTConfig struct {
|
|||
|
|
Secret string `yaml:"secret"`
|
|||
|
|
AccessTokenTTL time.Duration `yaml:"access_token_ttl"`
|
|||
|
|
RefreshTokenTTL time.Duration `yaml:"refresh_token_ttl"`
|
|||
|
|
Issuer string `yaml:"issuer"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 密码加密
|
|||
|
|
func HashPassword(password string) (string, error) {
|
|||
|
|
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|||
|
|
return string(bytes), err
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 输入验证
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 请求验证
|
|||
|
|
type CreateUserRequest struct {
|
|||
|
|
Username string `json:"username" validate:"required,min=3,max=20,alphanum"`
|
|||
|
|
Email string `json:"email" validate:"required,email"`
|
|||
|
|
Password string `json:"password" validate:"required,min=8,containsany=!@#$%^&*"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (r *CreateUserRequest) Validate() error {
|
|||
|
|
validate := validator.New()
|
|||
|
|
return validate.Struct(r)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. SQL 注入防护
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 使用参数化查询
|
|||
|
|
func (r *userRepository) FindByEmail(ctx context.Context, email string) (*entities.User, error) {
|
|||
|
|
var user entities.User
|
|||
|
|
err := r.db.WithContext(ctx).
|
|||
|
|
Where("email = ?", email). // 参数化查询
|
|||
|
|
First(&user).Error
|
|||
|
|
return &user, err
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. HTTPS 配置
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# 生产环境配置
|
|||
|
|
server:
|
|||
|
|
tls:
|
|||
|
|
enabled: true
|
|||
|
|
cert_file: "/etc/ssl/certs/server.crt"
|
|||
|
|
key_file: "/etc/ssl/private/server.key"
|
|||
|
|
min_version: "1.2"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 性能最佳实践
|
|||
|
|
|
|||
|
|
### 1. 数据库优化
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 连接池配置
|
|||
|
|
func setupDB(config *config.DatabaseConfig) (*gorm.DB, error) {
|
|||
|
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sqlDB, err := db.DB()
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 连接池设置
|
|||
|
|
sqlDB.SetMaxOpenConns(config.MaxOpenConns) // 最大连接数
|
|||
|
|
sqlDB.SetMaxIdleConns(config.MaxIdleConns) // 最大空闲连接
|
|||
|
|
sqlDB.SetConnMaxLifetime(config.ConnMaxLifetime) // 连接最大生命周期
|
|||
|
|
|
|||
|
|
return db, nil
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查询优化**:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 添加索引
|
|||
|
|
CREATE INDEX idx_users_email ON users(email);
|
|||
|
|
CREATE INDEX idx_users_created_at ON users(created_at);
|
|||
|
|
|
|||
|
|
-- 复合索引
|
|||
|
|
CREATE INDEX idx_users_status_created ON users(status, created_at);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 缓存策略
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 多级缓存
|
|||
|
|
type CacheService struct {
|
|||
|
|
localCache cache.Cache
|
|||
|
|
redisCache redis.Client
|
|||
|
|
ttl time.Duration
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (c *CacheService) Get(ctx context.Context, key string) (string, error) {
|
|||
|
|
// L1: 本地缓存
|
|||
|
|
if value, ok := c.localCache.Get(key); ok {
|
|||
|
|
return value.(string), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// L2: Redis 缓存
|
|||
|
|
value, err := c.redisCache.Get(ctx, key).Result()
|
|||
|
|
if err == nil {
|
|||
|
|
c.localCache.Set(key, value, c.ttl)
|
|||
|
|
return value, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return "", cache.ErrCacheMiss
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 异步处理
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 使用工作池处理任务
|
|||
|
|
type WorkerPool struct {
|
|||
|
|
workers int
|
|||
|
|
jobQueue chan Job
|
|||
|
|
wg sync.WaitGroup
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (wp *WorkerPool) Start() {
|
|||
|
|
for i := 0; i < wp.workers; i++ {
|
|||
|
|
wp.wg.Add(1)
|
|||
|
|
go wp.worker()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (wp *WorkerPool) Submit(job Job) {
|
|||
|
|
wp.jobQueue <- job
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 内存管理
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 对象池减少GC压力
|
|||
|
|
var bufferPool = sync.Pool{
|
|||
|
|
New: func() interface{} {
|
|||
|
|
return make([]byte, 4096)
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func processData(data []byte) error {
|
|||
|
|
buffer := bufferPool.Get().([]byte)
|
|||
|
|
defer bufferPool.Put(buffer)
|
|||
|
|
|
|||
|
|
// 使用buffer处理数据
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 运维最佳实践
|
|||
|
|
|
|||
|
|
### 1. 监控告警
|
|||
|
|
|
|||
|
|
**关键指标监控**:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# Prometheus 告警规则
|
|||
|
|
groups:
|
|||
|
|
- name: tyapi-server
|
|||
|
|
rules:
|
|||
|
|
- alert: HighErrorRate
|
|||
|
|
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
|
|||
|
|
labels:
|
|||
|
|
severity: critical
|
|||
|
|
annotations:
|
|||
|
|
summary: "High error rate detected"
|
|||
|
|
|
|||
|
|
- alert: HighResponseTime
|
|||
|
|
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
|
|||
|
|
labels:
|
|||
|
|
severity: warning
|
|||
|
|
annotations:
|
|||
|
|
summary: "High response time detected"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 备份策略
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
#!/bin/bash
|
|||
|
|
# 数据库备份脚本
|
|||
|
|
|
|||
|
|
BACKUP_DIR="/backups/tyapi"
|
|||
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
|||
|
|
BACKUP_FILE="$BACKUP_DIR/tyapi_backup_$DATE.sql"
|
|||
|
|
|
|||
|
|
# 创建备份
|
|||
|
|
pg_dump -h localhost -U postgres tyapi_prod > $BACKUP_FILE
|
|||
|
|
|
|||
|
|
# 压缩备份文件
|
|||
|
|
gzip $BACKUP_FILE
|
|||
|
|
|
|||
|
|
# 保留最近7天的备份
|
|||
|
|
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
|
|||
|
|
|
|||
|
|
# 上传到云存储
|
|||
|
|
aws s3 cp $BACKUP_FILE.gz s3://tyapi-backups/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 配置管理
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# 生产环境配置模板
|
|||
|
|
server:
|
|||
|
|
port: 8080
|
|||
|
|
mode: release
|
|||
|
|
read_timeout: 30s
|
|||
|
|
write_timeout: 30s
|
|||
|
|
|
|||
|
|
database:
|
|||
|
|
host: ${DB_HOST}
|
|||
|
|
port: ${DB_PORT}
|
|||
|
|
user: ${DB_USER}
|
|||
|
|
password: ${DB_PASSWORD}
|
|||
|
|
name: ${DB_NAME}
|
|||
|
|
max_open_conns: 100
|
|||
|
|
max_idle_conns: 10
|
|||
|
|
|
|||
|
|
redis:
|
|||
|
|
host: ${REDIS_HOST}
|
|||
|
|
port: ${REDIS_PORT}
|
|||
|
|
password: ${REDIS_PASSWORD}
|
|||
|
|
pool_size: 10
|
|||
|
|
|
|||
|
|
security:
|
|||
|
|
jwt_secret: ${JWT_SECRET}
|
|||
|
|
bcrypt_cost: 12
|
|||
|
|
|
|||
|
|
logging:
|
|||
|
|
level: info
|
|||
|
|
format: json
|
|||
|
|
output: stdout
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 容器化最佳实践
|
|||
|
|
|
|||
|
|
```dockerfile
|
|||
|
|
# 多阶段构建 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 main ./cmd/api
|
|||
|
|
|
|||
|
|
FROM alpine:3.18
|
|||
|
|
|
|||
|
|
# 安全加固
|
|||
|
|
RUN adduser -D -s /bin/sh appuser
|
|||
|
|
RUN apk --no-cache add ca-certificates tzdata
|
|||
|
|
|
|||
|
|
WORKDIR /root/
|
|||
|
|
|
|||
|
|
COPY --from=builder /app/main .
|
|||
|
|
COPY --from=builder /app/config.yaml .
|
|||
|
|
|
|||
|
|
USER appuser
|
|||
|
|
|
|||
|
|
EXPOSE 8080
|
|||
|
|
|
|||
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|||
|
|
CMD curl -f http://localhost:8080/api/v1/health || exit 1
|
|||
|
|
|
|||
|
|
CMD ["./main"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 团队协作最佳实践
|
|||
|
|
|
|||
|
|
### 1. 代码审查
|
|||
|
|
|
|||
|
|
**审查检查清单**:
|
|||
|
|
|
|||
|
|
- [ ] 代码符合项目规范
|
|||
|
|
- [ ] 测试覆盖率充足
|
|||
|
|
- [ ] 错误处理正确
|
|||
|
|
- [ ] 性能影响评估
|
|||
|
|
- [ ] 安全漏洞检查
|
|||
|
|
- [ ] 文档更新
|
|||
|
|
|
|||
|
|
### 2. CI/CD 流程
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# GitHub Actions 示例
|
|||
|
|
name: CI/CD Pipeline
|
|||
|
|
|
|||
|
|
on:
|
|||
|
|
push:
|
|||
|
|
branches: [main, develop]
|
|||
|
|
pull_request:
|
|||
|
|
branches: [main]
|
|||
|
|
|
|||
|
|
jobs:
|
|||
|
|
test:
|
|||
|
|
runs-on: ubuntu-latest
|
|||
|
|
steps:
|
|||
|
|
- uses: actions/checkout@v3
|
|||
|
|
- uses: actions/setup-go@v3
|
|||
|
|
with:
|
|||
|
|
go-version: 1.21
|
|||
|
|
|
|||
|
|
- name: Run tests
|
|||
|
|
run: |
|
|||
|
|
go test -v -race -coverprofile=coverage.out ./...
|
|||
|
|
go tool cover -html=coverage.out -o coverage.html
|
|||
|
|
|
|||
|
|
- name: Upload coverage
|
|||
|
|
uses: codecov/codecov-action@v3
|
|||
|
|
|
|||
|
|
deploy:
|
|||
|
|
needs: test
|
|||
|
|
runs-on: ubuntu-latest
|
|||
|
|
if: github.ref == 'refs/heads/main'
|
|||
|
|
steps:
|
|||
|
|
- name: Deploy to production
|
|||
|
|
run: |
|
|||
|
|
echo "Deploying to production..."
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 文档维护
|
|||
|
|
|
|||
|
|
- **API 文档**:使用 Swagger/OpenAPI 自动生成
|
|||
|
|
- **架构文档**:定期更新系统架构图
|
|||
|
|
- **运维手册**:记录部署和运维流程
|
|||
|
|
- **故障手册**:记录常见问题和解决方案
|
|||
|
|
|
|||
|
|
### 4. 版本管理
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 语义化版本控制
|
|||
|
|
git tag v1.2.3
|
|||
|
|
|
|||
|
|
# 版本发布流程
|
|||
|
|
git checkout main
|
|||
|
|
git pull origin main
|
|||
|
|
git tag v1.2.3
|
|||
|
|
git push origin v1.2.3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**版本号规则**:
|
|||
|
|
|
|||
|
|
- **MAJOR**:不兼容的 API 修改
|
|||
|
|
- **MINOR**:向下兼容的功能性新增
|
|||
|
|
- **PATCH**:向下兼容的问题修正
|
|||
|
|
|
|||
|
|
## 扩展性最佳实践
|
|||
|
|
|
|||
|
|
### 1. 微服务拆分
|
|||
|
|
|
|||
|
|
**拆分原则**:
|
|||
|
|
|
|||
|
|
- 按业务边界拆分
|
|||
|
|
- 保持服务自治
|
|||
|
|
- 数据库分离
|
|||
|
|
- 独立部署
|
|||
|
|
|
|||
|
|
### 2. 事件驱动架构
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 事件发布
|
|||
|
|
type EventBus interface {
|
|||
|
|
Publish(ctx context.Context, event Event) error
|
|||
|
|
Subscribe(eventType string, handler EventHandler) error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 事件处理
|
|||
|
|
func (h *UserEventHandler) HandleUserCreated(ctx context.Context, event *UserCreatedEvent) error {
|
|||
|
|
// 发送欢迎邮件
|
|||
|
|
return h.emailService.SendWelcomeEmail(ctx, event.UserID)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 配置外部化
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 配置热重载
|
|||
|
|
type ConfigManager struct {
|
|||
|
|
config *Config
|
|||
|
|
watchers []ConfigWatcher
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (cm *ConfigManager) Watch() {
|
|||
|
|
for {
|
|||
|
|
if changed := cm.checkConfigChange(); changed {
|
|||
|
|
cm.reloadConfig()
|
|||
|
|
cm.notifyWatchers()
|
|||
|
|
}
|
|||
|
|
time.Sleep(time.Second * 10)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 服务治理
|
|||
|
|
|
|||
|
|
- **服务注册与发现**
|
|||
|
|
- **负载均衡**
|
|||
|
|
- **熔断器**
|
|||
|
|
- **限流器**
|
|||
|
|
- **链路追踪**
|
|||
|
|
|
|||
|
|
通过遵循这些最佳实践,可以确保 TYAPI Server 项目的高质量、高性能和高可维护性。
|