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(排名聚合)
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(配置聚合)
class LeaderboardConfig {
// 标识
id: bigint;
configKey: string;
// 榜单开关
dailyEnabled: boolean;
weeklyEnabled: boolean;
monthlyEnabled: boolean;
// 虚拟排名设置
virtualRankingEnabled: boolean;
virtualAccountCount: number;
// 显示设置
displayLimit: number;
refreshIntervalMinutes: number;
}
3.2 值对象
RankingScore(排名分值)
// 龙虎榜分值计算公式:
// 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(周期)
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 日志
// 结构化日志
{
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 垂直扩展