docs(constitution): 新增数据库设计原则(v2.4.0)
在项目宪章中新增第九条原则"数据库设计原则",明确禁止使用数据库外键约束和ORM关联标签。 主要变更: - 新增原则IX:数据库设计原则(Database Design Principles) - 强制要求:数据库表不得使用外键约束 - 强制要求:GORM模型不得使用ORM关联标签(foreignKey、hasMany等) - 强制要求:表关系必须通过ID字段手动维护 - 强制要求:关联数据查询必须显式编写,避免ORM魔法 - 强制要求:时间字段由GORM处理,不使用数据库触发器 设计理念: - 提升业务逻辑灵活性(无数据库约束限制) - 优化高并发性能(无外键检查开销) - 增强代码可读性(显式查询,无隐式预加载) - 简化数据库架构和迁移流程 - 支持分布式和微服务场景 版本升级:2.3.0 → 2.4.0(MINOR)
This commit is contained in:
352
docs/002-gorm-postgres-asynq/架构说明.md
Normal file
352
docs/002-gorm-postgres-asynq/架构说明.md
Normal file
@@ -0,0 +1,352 @@
|
||||
# 数据持久化与异步任务处理集成 - 架构说明
|
||||
|
||||
**功能编号**: 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)
|
||||
Reference in New Issue
Block a user