486 lines
22 KiB
Markdown
486 lines
22 KiB
Markdown
# Leaderboard Service 架构设计文档
|
||
|
||
## 1. 概述
|
||
|
||
Leaderboard Service(龙虎榜服务)是一个基于 NestJS 框架的微服务,负责管理和展示用户的团队认种排名。服务采用 **领域驱动设计(DDD)** 结合 **六边形架构(Hexagonal Architecture)** 的设计模式。
|
||
|
||
### 1.1 核心功能
|
||
|
||
- **日榜/周榜/月榜管理**: 支持多种时间周期的排行榜
|
||
- **排名计算**: 基于团队认种数据计算龙虎榜分值
|
||
- **虚拟排名**: 支持系统虚拟账户占位显示
|
||
- **实时更新**: 定时刷新排名数据
|
||
- **缓存优化**: Redis 缓存热点数据
|
||
|
||
### 1.2 技术栈
|
||
|
||
| 组件 | 技术 | 版本 |
|
||
|------|------|------|
|
||
| 框架 | NestJS | 10.x |
|
||
| 语言 | TypeScript | 5.x |
|
||
| 数据库 | PostgreSQL | 15.x |
|
||
| ORM | Prisma | 5.x |
|
||
| 缓存 | Redis (ioredis) | 7.x |
|
||
| 消息队列 | Kafka (kafkajs) | 2.x |
|
||
| 认证 | JWT + Passport | - |
|
||
| API 文档 | Swagger | 7.x |
|
||
|
||
## 2. 架构设计
|
||
|
||
### 2.1 六边形架构(端口与适配器)
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ API Layer │
|
||
│ (Controllers, DTOs, Guards, Swagger) │
|
||
└─────────────────┬───────────────────────┘
|
||
│
|
||
┌─────────────────▼───────────────────────┐
|
||
│ Application Layer │
|
||
│ (Application Services, Schedulers) │
|
||
└─────────────────┬───────────────────────┘
|
||
│
|
||
┌─────────────────────────────┼─────────────────────────────┐
|
||
│ │ │
|
||
│ ┌────────────────▼────────────────┐ │
|
||
│ │ Domain Layer │ │
|
||
│ │ (Aggregates, Entities, VOs, │ │
|
||
│ │ Domain Services, Events) │ │
|
||
│ └────────────────┬────────────────┘ │
|
||
│ │ │
|
||
└─────────────────────────────┼─────────────────────────────┘
|
||
│
|
||
┌─────────────────▼───────────────────────┐
|
||
│ Infrastructure Layer │
|
||
│ (Repositories, External Services, │
|
||
│ Cache, Messaging, Database) │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 2.2 目录结构
|
||
|
||
```
|
||
src/
|
||
├── api/ # API 层(入站适配器)
|
||
│ ├── controllers/ # HTTP 控制器
|
||
│ │ ├── health.controller.ts
|
||
│ │ ├── leaderboard.controller.ts
|
||
│ │ ├── leaderboard-config.controller.ts
|
||
│ │ └── virtual-account.controller.ts
|
||
│ ├── dto/ # 数据传输对象
|
||
│ │ ├── leaderboard.dto.ts
|
||
│ │ ├── leaderboard-config.dto.ts
|
||
│ │ └── virtual-account.dto.ts
|
||
│ ├── guards/ # 认证守卫
|
||
│ │ ├── jwt-auth.guard.ts
|
||
│ │ └── admin.guard.ts
|
||
│ ├── decorators/ # 自定义装饰器
|
||
│ │ ├── public.decorator.ts
|
||
│ │ └── current-user.decorator.ts
|
||
│ └── strategies/ # Passport 策略
|
||
│ └── jwt.strategy.ts
|
||
│
|
||
├── application/ # 应用层
|
||
│ ├── services/ # 应用服务
|
||
│ │ └── leaderboard-application.service.ts
|
||
│ └── schedulers/ # 定时任务
|
||
│ └── leaderboard-refresh.scheduler.ts
|
||
│
|
||
├── domain/ # 领域层(核心业务逻辑)
|
||
│ ├── aggregates/ # 聚合根
|
||
│ │ ├── leaderboard-ranking/
|
||
│ │ │ └── leaderboard-ranking.aggregate.ts
|
||
│ │ └── leaderboard-config/
|
||
│ │ └── leaderboard-config.aggregate.ts
|
||
│ ├── entities/ # 实体
|
||
│ │ └── virtual-account.entity.ts
|
||
│ ├── value-objects/ # 值对象
|
||
│ │ ├── leaderboard-type.enum.ts
|
||
│ │ ├── leaderboard-period.vo.ts
|
||
│ │ ├── ranking-score.vo.ts
|
||
│ │ ├── rank-position.vo.ts
|
||
│ │ ├── user-snapshot.vo.ts
|
||
│ │ └── virtual-account-type.enum.ts
|
||
│ ├── events/ # 领域事件
|
||
│ │ ├── domain-event.base.ts
|
||
│ │ ├── leaderboard-refreshed.event.ts
|
||
│ │ ├── config-updated.event.ts
|
||
│ │ └── ranking-changed.event.ts
|
||
│ ├── repositories/ # 仓储接口(端口)
|
||
│ │ ├── leaderboard-ranking.repository.interface.ts
|
||
│ │ ├── leaderboard-config.repository.interface.ts
|
||
│ │ └── virtual-account.repository.interface.ts
|
||
│ └── services/ # 领域服务
|
||
│ ├── leaderboard-calculation.service.ts
|
||
│ ├── virtual-ranking-generator.service.ts
|
||
│ └── ranking-merger.service.ts
|
||
│
|
||
├── infrastructure/ # 基础设施层(出站适配器)
|
||
│ ├── database/ # 数据库
|
||
│ │ └── prisma.service.ts
|
||
│ ├── repositories/ # 仓储实现
|
||
│ │ ├── leaderboard-ranking.repository.impl.ts
|
||
│ │ ├── leaderboard-config.repository.impl.ts
|
||
│ │ └── virtual-account.repository.impl.ts
|
||
│ ├── cache/ # 缓存服务
|
||
│ │ ├── redis.service.ts
|
||
│ │ └── leaderboard-cache.service.ts
|
||
│ ├── messaging/ # 消息队列
|
||
│ │ ├── kafka.service.ts
|
||
│ │ ├── event-publisher.service.ts
|
||
│ │ └── event-consumer.service.ts
|
||
│ └── external/ # 外部服务客户端
|
||
│ ├── referral-service.client.ts
|
||
│ └── identity-service.client.ts
|
||
│
|
||
├── modules/ # NestJS 模块定义
|
||
│ ├── domain.module.ts
|
||
│ ├── infrastructure.module.ts
|
||
│ ├── application.module.ts
|
||
│ └── api.module.ts
|
||
│
|
||
├── app.module.ts # 应用根模块
|
||
└── main.ts # 应用入口
|
||
```
|
||
|
||
## 3. 领域模型设计
|
||
|
||
### 3.1 聚合根
|
||
|
||
#### LeaderboardRanking(排名聚合)
|
||
|
||
```typescript
|
||
class LeaderboardRanking {
|
||
// 标识
|
||
id: bigint;
|
||
|
||
// 榜单信息
|
||
leaderboardType: LeaderboardType; // DAILY | WEEKLY | MONTHLY
|
||
period: LeaderboardPeriod;
|
||
|
||
// 用户信息
|
||
userId: bigint;
|
||
isVirtual: boolean;
|
||
|
||
// 排名信息
|
||
rankPosition: RankPosition; // 实际排名
|
||
displayPosition: RankPosition; // 显示排名
|
||
previousRank: RankPosition | null;
|
||
|
||
// 分值信息
|
||
score: RankingScore;
|
||
|
||
// 用户快照
|
||
userSnapshot: UserSnapshot;
|
||
}
|
||
```
|
||
|
||
#### LeaderboardConfig(配置聚合)
|
||
|
||
```typescript
|
||
class LeaderboardConfig {
|
||
// 标识
|
||
id: bigint;
|
||
configKey: string;
|
||
|
||
// 榜单开关
|
||
dailyEnabled: boolean;
|
||
weeklyEnabled: boolean;
|
||
monthlyEnabled: boolean;
|
||
|
||
// 虚拟排名设置
|
||
virtualRankingEnabled: boolean;
|
||
virtualAccountCount: number;
|
||
|
||
// 显示设置
|
||
displayLimit: number;
|
||
refreshIntervalMinutes: number;
|
||
}
|
||
```
|
||
|
||
### 3.2 值对象
|
||
|
||
#### RankingScore(排名分值)
|
||
|
||
```typescript
|
||
// 龙虎榜分值计算公式:
|
||
// effectiveScore = totalTeamPlanting - maxDirectTeamPlanting
|
||
|
||
class RankingScore {
|
||
totalTeamPlanting: number; // 团队总认种
|
||
maxDirectTeamPlanting: number; // 最大单个直推团队认种
|
||
effectiveScore: number; // 有效分值(龙虎榜分值)
|
||
|
||
static calculate(total: number, maxDirect: number): RankingScore {
|
||
const effective = Math.max(0, total - maxDirect);
|
||
return new RankingScore(total, maxDirect, effective);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### LeaderboardPeriod(周期)
|
||
|
||
```typescript
|
||
class LeaderboardPeriod {
|
||
key: string; // 2024-01-15 | 2024-W03 | 2024-01
|
||
startAt: Date;
|
||
endAt: Date;
|
||
|
||
static currentDaily(): LeaderboardPeriod;
|
||
static currentWeekly(): LeaderboardPeriod;
|
||
static currentMonthly(): LeaderboardPeriod;
|
||
}
|
||
```
|
||
|
||
### 3.3 领域事件
|
||
|
||
| 事件 | 触发时机 | 数据 |
|
||
|------|----------|------|
|
||
| LeaderboardRefreshedEvent | 榜单刷新完成 | type, period, rankings |
|
||
| ConfigUpdatedEvent | 配置变更 | configKey, changes |
|
||
| RankingChangedEvent | 用户排名变化 | userId, oldRank, newRank |
|
||
|
||
## 4. 数据模型
|
||
|
||
### 4.1 数据库表设计
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ leaderboard_rankings │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ ranking_id (PK) │ 排名ID │
|
||
│ leaderboard_type │ 榜单类型 (DAILY/WEEKLY/MONTHLY) │
|
||
│ period_key │ 周期标识 │
|
||
│ user_id │ 用户ID │
|
||
│ is_virtual │ 是否虚拟账户 │
|
||
│ rank_position │ 实际排名 │
|
||
│ display_position │ 显示排名 │
|
||
│ previous_rank │ 上次排名 │
|
||
│ total_team_planting │ 团队总认种 │
|
||
│ max_direct_team_planting│ 最大直推团队认种 │
|
||
│ effective_score │ 有效分值 │
|
||
│ user_snapshot │ 用户快照 (JSON) │
|
||
│ period_start_at │ 周期开始时间 │
|
||
│ period_end_at │ 周期结束时间 │
|
||
│ calculated_at │ 计算时间 │
|
||
│ created_at │ 创建时间 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ UK: (leaderboard_type, period_key, user_id) │
|
||
│ IDX: (leaderboard_type, period_key, display_position) │
|
||
│ IDX: (leaderboard_type, period_key, effective_score DESC) │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ leaderboard_configs │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ config_id (PK) │ 配置ID │
|
||
│ config_key (UK) │ 配置键 (GLOBAL) │
|
||
│ daily_enabled │ 日榜开关 │
|
||
│ weekly_enabled │ 周榜开关 │
|
||
│ monthly_enabled │ 月榜开关 │
|
||
│ virtual_ranking_enabled │ 虚拟排名开关 │
|
||
│ virtual_account_count │ 虚拟账户数量 │
|
||
│ display_limit │ 显示数量限制 │
|
||
│ refresh_interval_minutes│ 刷新间隔(分钟) │
|
||
│ created_at │ 创建时间 │
|
||
│ updated_at │ 更新时间 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ virtual_accounts │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ virtual_account_id (PK) │ 虚拟账户ID │
|
||
│ account_type │ 账户类型 │
|
||
│ display_name │ 显示名称 │
|
||
│ avatar │ 头像URL │
|
||
│ province_code │ 省份代码 │
|
||
│ city_code │ 城市代码 │
|
||
│ min_score │ 最小分值 │
|
||
│ max_score │ 最大分值 │
|
||
│ current_score │ 当前分值 │
|
||
│ usdt_balance │ USDT余额 │
|
||
│ hashpower_balance │ 算力余额 │
|
||
│ is_active │ 是否激活 │
|
||
│ created_at │ 创建时间 │
|
||
│ updated_at │ 更新时间 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 4.2 缓存设计
|
||
|
||
```
|
||
Redis Key 设计:
|
||
|
||
leaderboard:{type}:{period}:rankings # 排名列表 (ZSET)
|
||
leaderboard:{type}:{period}:user:{id} # 用户排名详情 (HASH)
|
||
leaderboard:config # 全局配置 (HASH)
|
||
leaderboard:virtual:accounts # 虚拟账户列表 (LIST)
|
||
|
||
TTL:
|
||
- 日榜: 10 分钟
|
||
- 周榜: 30 分钟
|
||
- 月榜: 1 小时
|
||
- 配置: 5 分钟
|
||
```
|
||
|
||
## 5. 核心业务流程
|
||
|
||
### 5.1 排名刷新流程
|
||
|
||
```
|
||
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
|
||
│ Scheduler │────▶│ Application │────▶│ ReferralService │
|
||
│ (Cron) │ │ Service │ │ (External) │
|
||
└─────────────┘ └──────┬───────┘ └────────┬────────┘
|
||
│ │
|
||
│ 获取团队数据 │
|
||
│◀──────────────────────┘
|
||
│
|
||
▼
|
||
┌───────────────────────┐
|
||
│ LeaderboardCalculation│
|
||
│ Service │
|
||
│ - 计算有效分值 │
|
||
│ - 排序 │
|
||
│ - 生成排名 │
|
||
└───────────┬───────────┘
|
||
│
|
||
▼
|
||
┌───────────────────────┐
|
||
│ VirtualRanking │
|
||
│ Generator │
|
||
│ - 生成虚拟排名 │
|
||
└───────────┬───────────┘
|
||
│
|
||
▼
|
||
┌───────────────────────┐
|
||
│ RankingMerger │
|
||
│ - 合并真实/虚拟排名 │
|
||
│ - 调整显示位置 │
|
||
└───────────┬───────────┘
|
||
│
|
||
┌─────────────────┼─────────────────┐
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||
│ Database │ │ Cache │ │ Kafka │
|
||
│ (Persist) │ │ (Update) │ │ (Publish) │
|
||
└───────────────┘ └───────────────┘ └───────────────┘
|
||
```
|
||
|
||
### 5.2 排名查询流程
|
||
|
||
```
|
||
┌─────────┐ ┌────────────┐ ┌─────────┐
|
||
│ Client │────▶│ Controller │────▶│ Cache │
|
||
└─────────┘ └─────┬──────┘ └────┬────┘
|
||
│ │
|
||
│ Cache Hit? │
|
||
│◀────────────────┘
|
||
│
|
||
┌───────┴───────┐
|
||
│ Yes No│
|
||
▼ ▼
|
||
┌──────────┐ ┌──────────┐
|
||
│ Return │ │ Database │
|
||
│ Cached │ │ Query │
|
||
└──────────┘ └────┬─────┘
|
||
│
|
||
▼
|
||
┌──────────┐
|
||
│ Update │
|
||
│ Cache │
|
||
└────┬─────┘
|
||
│
|
||
▼
|
||
┌──────────┐
|
||
│ Return │
|
||
└──────────┘
|
||
```
|
||
|
||
## 6. 安全设计
|
||
|
||
### 6.1 认证与授权
|
||
|
||
| 端点 | 认证要求 | 权限要求 |
|
||
|------|----------|----------|
|
||
| GET /leaderboard/* | 无 (公开) | - |
|
||
| GET /leaderboard/my-rank | JWT | 用户 |
|
||
| GET /leaderboard/config | JWT | 管理员 |
|
||
| POST /leaderboard/config/* | JWT | 管理员 |
|
||
| * /virtual-accounts/* | JWT | 管理员 |
|
||
|
||
### 6.2 数据安全
|
||
|
||
- 用户敏感信息脱敏
|
||
- BigInt ID 防止遍历
|
||
- 输入验证与清洗
|
||
- SQL 注入防护 (Prisma)
|
||
|
||
## 7. 性能优化
|
||
|
||
### 7.1 缓存策略
|
||
|
||
- **L1**: 应用内存缓存(热点数据)
|
||
- **L2**: Redis 分布式缓存
|
||
- **缓存预热**: 服务启动时加载
|
||
|
||
### 7.2 数据库优化
|
||
|
||
- 合理索引设计
|
||
- 分页查询
|
||
- 批量操作
|
||
- 读写分离(可选)
|
||
|
||
### 7.3 异步处理
|
||
|
||
- 排名计算异步执行
|
||
- 事件驱动更新
|
||
- 消息队列削峰
|
||
|
||
## 8. 可观测性
|
||
|
||
### 8.1 日志
|
||
|
||
```typescript
|
||
// 结构化日志
|
||
{
|
||
level: 'info',
|
||
timestamp: '2024-01-15T10:30:00Z',
|
||
service: 'leaderboard-service',
|
||
traceId: 'abc123',
|
||
message: 'Leaderboard refreshed',
|
||
context: {
|
||
type: 'DAILY',
|
||
period: '2024-01-15',
|
||
totalRankings: 100
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.2 健康检查
|
||
|
||
- `/health` - 服务存活检查
|
||
- `/health/ready` - 服务就绪检查(含依赖)
|
||
|
||
### 8.3 指标 (Metrics)
|
||
|
||
- 请求延迟
|
||
- 缓存命中率
|
||
- 排名计算耗时
|
||
- 数据库连接池状态
|
||
|
||
## 9. 扩展性考虑
|
||
|
||
### 9.1 水平扩展
|
||
|
||
- 无状态服务设计
|
||
- Redis 集群支持
|
||
- Kafka 分区消费
|
||
|
||
### 9.2 垂直扩展
|
||
|
||
- 异步任务队列
|
||
- 数据库分片(未来)
|
||
- 冷热数据分离
|