# 数据持久化与异步任务处理集成 - 架构说明 **功能编号**: 002-gorm-postgres-asynq **更新日期**: 2025-11-13 --- ## 系统架构概览 ``` ┌─────────────────┐ │ Load Balancer │ │ (Nginx) │ └────────┬────────┘ │ ┌────────────────┼────────────────┐ │ │ │ ┌─────────▼────────┐ ┌───▼──────────┐ ┌──▼─────────┐ │ API Server 1 │ │ API Server 2 │ │ API N │ │ (Fiber:8080) │ │(Fiber:8080) │ │(Fiber:8080)│ └─────────┬────────┘ └───┬──────────┘ └──┬─────────┘ │ │ │ └──────────────┼───────────────┘ │ ┌──────────────┼──────────────┐ │ │ │ ┌─────▼────┐ ┌───▼───────┐ ┌───▼─────────┐ │PostgreSQL│ │ Redis │ │Worker Cluster│ │ (Primary)│ │ (Queue) │ │ (Asynq) │ └────┬─────┘ └───────────┘ └─────────────┘ │ ┌──────▼──────┐ │ PostgreSQL │ │ (Replica) │ └─────────────┘ ``` --- ## 双服务架构 ### API 服务 (cmd/api/) **职责**: - HTTP 请求处理 - 业务逻辑执行 - 数据库 CRUD 操作 - 任务提交到队列 **特点**: - 无状态设计,支持水平扩展 - RESTful API 设计 - 统一错误处理和响应格式 - 集成认证、限流、日志中间件 ### Worker 服务 (cmd/worker/) **职责**: - 从队列消费任务 - 执行后台异步任务 - 任务重试管理 - 幂等性保障 **特点**: - 多实例部署,自动负载均衡 - 支持多优先级队列 - 优雅关闭(等待任务完成) - 可配置并发数 --- ## 分层架构 ### Handler 层 (internal/handler/) **职责**: HTTP 请求处理 ``` - 请求参数验证 - 调用 Service 层 - 响应封装 - 错误处理 ``` **设计原则**: - 不包含业务逻辑 - 薄层设计 - 统一使用 pkg/response/ ### Service 层 (internal/service/) **职责**: 业务逻辑 ``` - 业务规则实现 - 跨模块协调 - 事务管理 - 错误转换 ``` **设计原则**: - 可复用的业务逻辑 - 支持依赖注入 - 使用 pkg/errors/ 错误码 ### Store 层 (internal/store/) **职责**: 数据访问 ``` - CRUD 操作 - 查询构建 - 事务封装 - 数据库交互 ``` **设计原则**: - 只返回 GORM 原始错误 - 不包含业务逻辑 - 支持事务传递 ### Model 层 (internal/model/) **职责**: 数据模型定义 ``` - 实体定义 - DTO 定义 - 验证规则 ``` --- ## 数据流 ### CRUD 操作流程 ``` HTTP Request ↓ Handler (参数验证) ↓ Service (业务逻辑) ↓ Store (数据访问) ↓ PostgreSQL ↓ Store (返回数据) ↓ Service (转换) ↓ Handler (响应) ↓ HTTP Response ``` ### 异步任务流程 ``` HTTP Request (任务提交) ↓ Handler ↓ Service (构造 Payload) ↓ Queue Client (Asynq) ↓ Redis (持久化) ↓ Worker (消费任务) ↓ Task Handler (执行任务) ↓ PostgreSQL/外部服务 ``` --- ## 核心设计决策 ### 1. 为什么使用 GORM? **优势**: - Go 生态最成熟的 ORM - 自动参数化查询(防 SQL 注入) - 预编译语句缓存 - 软删除支持 - 钩子函数支持 ### 2. 为什么使用 golang-migrate? **理由**: - 版本控制: 每个迁移有版本号 - 可回滚: up/down 脚本 - 团队协作: 迁移文件可 review - 生产安全: 明确的 SQL 语句 **不用 GORM AutoMigrate**: - 无法回滚 - 无法删除列 - 生产环境风险高 ### 3. 为什么使用 Asynq? **优势**: - 基于 Redis,无需额外中间件 - 任务持久化(系统重启自动恢复) - 自动重试(指数退避) - Web UI 监控(asynqmon) - 分布式锁支持 --- ## 关键技术实现 ### 幂等性设计 **方案 1: Redis 锁** ```go key := constants.RedisTaskLockKey(requestID) if exists, _ := rdb.SetNX(ctx, key, "1", 24*time.Hour).Result(); !exists { return nil // 跳过重复任务 } ``` **方案 2: 数据库唯一约束** ```sql CREATE UNIQUE INDEX idx_order_id ON tb_order(order_id); ``` **方案 3: 状态机** ```go if order.Status != "pending" { return nil // 状态不匹配,跳过 } ``` ### 事务管理 ```go func (s *Store) Transaction(ctx context.Context, fn func(*Store) error) error { return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { txStore := &Store{db: tx, logger: s.logger} return fn(txStore) }) } ``` ### 连接池配置 **PostgreSQL**: - MaxOpenConns: 25(最大连接) - MaxIdleConns: 10(空闲连接) - ConnMaxLifetime: 5m(连接生命周期) **Redis**: - PoolSize: 10 - MinIdleConns: 5 --- ## 扩展性设计 ### 水平扩展 **API 服务**: - 无状态设计 - 通过负载均衡器分发请求 - 自动扩缩容(K8s HPA) **Worker 服务**: - 多实例连接同一 Redis - Asynq 自动负载均衡 - 按队列权重分配任务 ### 数据库扩展 **读写分离**: ``` Primary (写) → Replica (读) ``` **分库分表**: - 按业务模块垂直分库 - 按数据量水平分表 --- ## 监控与可观测性 ### 健康检查 - PostgreSQL Ping - Redis Ping - 连接池状态 ### 日志 - 访问日志: 所有 HTTP 请求 - 错误日志: 错误详情 - 慢查询日志: > 100ms - 任务日志: 提交/执行/失败 ### 指标(建议) - API 响应时间 - 数据库连接数 - 任务队列长度 - 任务失败率 --- ## 安全设计 ### 数据安全 - SQL 注入防护(GORM 参数化) - 密码哈希(bcrypt) - 敏感字段不返回(`json:"-"`) ### 配置安全 - 生产环境使用环境变量 - 数据库 SSL 连接 - Redis 密码认证 --- ## 性能优化 ### 数据库 - 适当索引 - 批量操作 - 分页查询 - 慢查询监控 ### 任务队列 - 优先级队列 - 并发控制 - 超时设置 - 幂等性保障 --- ## 参考文档 - [功能总结](./功能总结.md) - [使用指南](./使用指南.md) - [项目 Constitution](../../.specify/memory/constitution.md)