20 KiB
20 KiB
微服务架构设计文档
一、架构设计原则
1.1 拆分原则
- 领域驱动设计(DDD):按业务领域拆分,而非技术层次
- 高内聚低耦合:同一领域的功能放在同一服务
- 独立部署:服务可独立扩展和部署
- 数据隔离:每个服务拥有独立数据库(或逻辑隔离)
- 渐进式拆分:初期可适当合并,后续按需拆分
1.2 粉丝身份隔离方案
实现方式:账号ID + 明星ID(star_id)作为联合主键/隔离键
JWT Token设计:
- JWT Claims:
{"user_id": 10000001, "star_id": 123, "updated_at": 1704067200000, "iat": 1704067200000, "exp": 1704672000000} - Token中包含所有必要信息(user_id、star_id等),前端可直接解析JWT获取
- 后端验证Token时,从Claims中提取user_id和star_id
数据库设计:
- 用户表:
users(user_id, mobile, password_hash, ...) - 粉丝档案表:
fan_profiles(user_id, star_id, nickname, level, ...) - 联合主键 - 所有业务表都包含
star_id作为隔离键
二、微服务拆分方案
方案A:核心服务拆分(推荐初期方案)
2.1 服务列表
1. User Service(用户与认证服务)
2. Asset Service(资产服务)
3. Social Service(社交服务)
4. Gallery Service(展馆服务)
5. Task Service(任务服务)
2.2 服务职责划分
2.2.1 User Service(用户与认证服务)
职责:
- 用户注册、登录、登出
- JWT Token 生成、刷新、验证
- 用户基本信息管理
- 粉丝档案(FanProfile)管理
- 粉丝身份列表管理与切换
- 个人信息页数据
- 密码管理
核心功能(认证相关):
POST /api/auth/register- 注册(同时创建第一个粉丝身份)POST /api/auth/login- 登录(返回JWT Token,Token中已包含star_id)POST /api/auth/logout- 登出POST /api/auth/refresh- 刷新TokenGET /api/auth/me- 获取当前登录用户信息
核心功能(用户信息相关):
GET /api/users/{user_id}- 获取用户信息GET /api/users/{user_id}/fan-profiles/{star_id}- 获取粉丝档案GET /api/fan-identities- 获取可选粉丝身份列表POST /api/my/fan-identities- 新增粉丝身份(最多2个)POST /api/my/fan-identities/switch- 切换粉丝身份(返回新token)GET /api/me/profile- 获取个人信息页POST /api/me/profile- 修改昵称POST /api/account/password- 修改密码
数据库:
users- 用户账号表(user_id, mobile, password_hash, global_wallet_address, ...)fan_profiles- 粉丝档案表(user_id, star_id, nickname, level, crystal_balance, ...)stars- 明星信息表(star_id, name, pic_url, ...)user_sessions- 用户会话表(Token黑名单)
数据隔离:所有查询都基于 user_id + star_id 联合查询
优势:
- 认证和用户管理逻辑紧密相关,合并后减少服务间调用
- 注册、登录、身份切换等操作可以在同一服务内完成,保证事务一致性
- 简化架构,降低维护成本
2.2.2 Asset Service(资产服务)
职责:
- 数字藏品的铸造(链下记录 + 链上确权)
- 资产查询与列表
- 资产详情
- 素材管理(平台素材)
- 图片上传与审核
核心功能:
POST /api/uploadPic- 上传藏品封面图片DELETE /api/cancelMint- 取消铸造POST /api/mints- 创建铸造订单(异步)GET /api/starbooks/me/items- 获取我的藏品列表GET /api/assets/{asset_id}- 获取藏品详情GET /api/materials/platform- 获取平台素材列表GET /api/assets/{asset_id}/status- 查询上链状态
数据库:
assets- 资产表(asset_id, owner_uid, star_id, name, cover_url, status, tx_hash, token_id, ...)mint_orders- 铸造订单表(order_id, asset_id, status, created_at, ...)materials- 素材表(material_id, star_id, pic_url, ...)upload_tasks- 图片上传任务表(task_id, pic_url, status, ...)
外部依赖:
- 区块链服务(上链确权,异步)
- AI服务(生成封面,可选)
- 存储服务(MinIO/S3,图片存储)
触发事件:
- 铸造完成 → 发布事件 → Task Service(更新任务进度)
2.2.3 Social Service(社交服务)
职责:
- 好友关系管理(申请、同意、拒绝、删除)
- 好友列表查询
- 用户搜索
- 系统推荐好友
- 点赞功能
核心功能:
GET /api/users/search- 搜索用户(按UID)GET /api/friends/recommendations- 系统推荐好友POST /api/friends/requests- 发起好友申请POST /api/friends/requests/respond- 处理好友申请(action: true=同意)GET /api/friend-list- 好友列表DELETE /api/friends/{friend_uid}- 删除好友POST /api/assets/likes- 点赞藏品DELETE /api/assets/{asset_id}/likes- 取消点赞
数据库:
friend_relations- 好友关系表(id, user_a, user_b, star_id, status, created_at)friend_requests- 好友申请表(request_id, from_uid, to_uid, star_id, status, created_at)asset_likes- 点赞表(id, asset_id, user_id, star_id, created_at)
数据隔离:所有操作都基于 star_id 隔离
2.2.4 Gallery Service(展馆服务)
职责:
- 展馆管理(我的展馆、他人展馆)
- 展位管理(槽位列表、解锁/购买展位)
- 展品展示(放置、下架、踢走占位)
- 展位规则管理(从PostgreSQL加载)
核心功能:
GET /api/mygalleries- 获取我的展馆GET /api/galleries/{target_uid}- 获取他人展馆POST /api/galleries/place- 在展位展示藏品POST /api/galleries/remove- 下架展位藏品POST /api/galleries/me/slots/{slot_id}/kick- 踢走占位POST /api/galleries/slots_unlock- 解锁/购买新展位
数据库:
booth_slots- 展位表(slot_id, host_profile_id, star_id, slot_index, visibility, is_enabled, ...)exhibitions- 展品展示表(id, asset_id, slot_id, host_profile_id, occupier_uid, start_time, expire_at, ...)
规则表(PostgreSQL):
gallery_rules- 展位规则表(rule_id, star_id, rule_type, rule_value, ...)- 初始展位数:3
- 抢展位时长:4小时
- 解锁条件:等级/水晶购买价格
启动时加载规则:
// 服务启动时从PostgreSQL加载规则到内存
type GalleryRules struct {
InitialSlotCount int // 初始展位数
GrabSlotDuration int64 // 抢展位时长(秒)
UnlockCostByLevel map[int]int // 按等级解锁成本
}
依赖:
- Asset Service(验证资产是否存在)
- User Service(验证用户权限和粉丝档案)
触发事件:
- 展示完成 → 发布事件 → Task Service(更新任务进度)
2.2.5 Task Service(任务服务)
职责:
- 任务定义管理(从PostgreSQL加载)
- 用户任务进度管理
- 任务奖励发放
- 任务进度更新(接收事件)
- 新手引导状态管理
核心功能:
GET /api/tasks- 获取任务列表GET /api/tasks/{task_id}- 获取任务详情POST /api/tasks/claim- 领取任务奖励POST /api/tasks/progress- 更新任务进度(内部调用/事件触发)GET /api/onboarding/status- 获取新手引导状态POST /api/onboarding/status- 更新新手引导状态
数据库:
user_tasks- 用户任务进度表(id, user_id, star_id, task_id, status, progress, target, ...)
规则表(PostgreSQL):
task_definitions- 任务定义表(task_id, star_id, task_type, title, condition, reward_type, reward_amount, ...)task_conditions- 任务条件表(condition_id, action, count, ...)
启动时加载规则:
// 服务启动时从PostgreSQL加载任务定义到内存
type TaskDefinitions struct {
Tasks map[int64]*TaskDefinition // task_id -> TaskDefinition
Rules map[string]*TaskCondition // action -> TaskCondition
}
事件监听:
- 监听来自其他服务的事件:
user.login→ 更新登录任务进度asset.mint→ 更新铸造任务进度gallery.exhibit→ 更新展示任务进度friend.add→ 更新社交任务进度
依赖:
- User Service(发放奖励时更新粉丝档案的余额、等级)
2.2.6 Recommendation Service(推荐服务)- 可选
职责:
- 广场推荐小屋列表
- TOP 藏品展板(基于点赞数)
- 推荐算法(未来扩展)
核心功能:
GET /api/square/huts- 广场推荐小屋列表GET /api/square/top-assets- TOP藏品展板
数据库:
recommendation_cache- 推荐缓存表(id, type, data, updated_at)
依赖:
- User Service(获取用户信息和粉丝档案)
- Asset Service(获取资产信息)
- Social Service(获取点赞数据)
注意:初期可以放在 Social Service 或 Gallery Service 中,后续按需拆分
方案B:进一步简化拆分(可选,适合更小团队)
如果团队规模较小或初期快速迭代,可以考虑进一步合并:
1. User Service(用户、认证、社交)
2. Asset Service(资产服务)
3. Gallery Service(展馆服务 + 任务服务)
合并理由:
- User + Social:社交功能与用户紧密相关,数据查询频繁,且需要粉丝身份隔离
- Gallery + Task:任务主要是展馆相关行为触发,初期合并减少服务间调用
注意:当前推荐的方案A已经将认证和用户服务合并,足够简化。方案B仅在团队非常小(2-3人)时考虑。
拆分时机:
- 当单个服务负载过高时
- 当功能迭代冲突频繁时
- 当需要独立扩展时
三、服务间通信
3.1 通信方式
同步调用:gRPC(内部服务间) 异步调用:消息队列(RocketMQ/Kafka/RabbitMQ) 对外API:REST API(通过Gateway/BFF层)
3.2 事件驱动架构
事件类型:
user.login // 用户登录
user.identity_switch // 切换身份
asset.mint // 资产铸造
asset.mint_complete // 铸造完成
gallery.exhibit // 展品上架
gallery.remove // 展品下架
friend.add // 添加好友
friend.delete // 删除好友
asset.like // 点赞
task.complete // 任务完成
事件发布者与订阅者:
User Service → user.login → Task Service
User Service → user.identity_switch → Task Service
Asset Service → asset.mint → Task Service
Gallery Service → gallery.exhibit → Task Service
Social Service → friend.add → Task Service
四、数据存储方案
4.1 数据库选择
PostgreSQL(主数据库):
- 用户数据
- 粉丝档案
- 资产数据
- 社交关系
- 展馆展位
- 任务进度
- 规则表(任务规则、展位规则)
Redis(缓存):
- JWT Token 黑名单
- 用户会话缓存
- 热门数据缓存(TOP藏品、推荐列表)
- 分布式锁
MinIO/S3(对象存储):
- 图片资源(藏品封面、用户头像、素材)
区块链(链上存储):
- 资产确权(Token ID、交易哈希)
4.2 规则存储与加载
设计思路:
- 规则存储在PostgreSQL的配置表中
- 服务启动时一次性加载到内存
- 支持热更新(通过配置中心或管理后台触发)
规则表设计:
-- 任务规则表
CREATE TABLE task_definitions (
task_id BIGSERIAL PRIMARY KEY,
star_id BIGINT NOT NULL DEFAULT 0, -- 0=全局任务
task_type INT NOT NULL, -- 1=日常, 2=周常, 3=成就, 4=活动
title VARCHAR(255) NOT NULL,
description TEXT,
trigger_type INT NOT NULL, -- 1=计数, 2=条件, 3=一次性
condition JSONB, -- 完成条件 {"action":"login","count":3}
reward_type INT NOT NULL, -- 1=经验, 2=水晶, 3=游戏币
reward_amount BIGINT NOT NULL,
is_active BOOLEAN DEFAULT true,
start_time BIGINT, -- Unix时间戳毫秒
end_time BIGINT,
created_at BIGINT NOT NULL
);
-- 展位规则表
CREATE TABLE gallery_rules (
rule_id BIGSERIAL PRIMARY KEY,
star_id BIGINT NOT NULL DEFAULT 0, -- 0=全局规则
rule_type VARCHAR(50) NOT NULL, -- 'initial_slot_count', 'grab_duration', 'unlock_cost'
rule_value JSONB NOT NULL, -- 规则值
updated_at BIGINT NOT NULL
);
服务加载示例:
// Task Service 启动时
func (s *TaskService) LoadTaskDefinitions() error {
tasks, err := s.repo.LoadAllActiveTasks()
if err != nil {
return err
}
s.taskCache = make(map[int64]*TaskDefinition)
for _, task := range tasks {
s.taskCache[task.TaskID] = task
}
return nil
}
// Gallery Service 启动时
func (s *GalleryService) LoadGalleryRules() error {
rules, err := s.repo.LoadAllRules()
if err != nil {
return err
}
s.rules = &GalleryRules{
InitialSlotCount: rules.GetInt("initial_slot_count", 3),
GrabSlotDuration: rules.GetInt64("grab_duration", 4*3600),
// ...
}
return nil
}
五、JWT Token 设计(账号+明星ID)
5.1 Token 结构
JWT Claims:
{
"user_id": 10000001,
"star_id": 123,
"iat": 1704067200,
"exp": 1704070800
}
前端使用:
- 直接使用JWT Token,无需拼接格式
- 前端可以直接解析JWT的payload部分(Base64解码)获取star_id等信息
- 请求时在Header中携带:
Authorization: Bearer {jwt_token}
后端验证:
func ValidateToken(tokenString string) (*Claims, error) {
// 解析和验证JWT Token
claims, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil {
return nil, err
}
// Token中已包含user_id和star_id
// claims.UserID
// claims.StarID
// claims.UpdatedAt
return claims, nil
}
5.2 登录响应
{
"code": 200,
"message": "ok",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 604800,
"user": {
"uid": 10000001,
"current_star_id": 123,
"nickname": "爱战战",
"chain_address": "0xabc...",
"starbook_limit": 3,
"assets_num": 2
}
}
}
说明:
access_token:JWT Token,包含user_id、star_id、updated_at等信息- 前端可直接解析Token获取star_id,无需额外字段
六、API Gateway / BFF 层
6.1 职责
- 统一入口:所有外部请求通过Gateway
- 协议转换:REST API → gRPC(内部服务)
- 认证授权:JWT验证(Token中已包含user_id和star_id)
- 请求路由:根据路径路由到对应微服务
- 响应聚合:合并多个服务的数据
- 限流熔断:保护后端服务
6.2 路由规则
/api/auth/* → User Service
/api/users/* → User Service
/api/fan-identities → User Service
/api/me/* → User Service
/api/account/* → User Service
/api/assets/* → Asset Service
/api/friends/* → Social Service
/api/galleries/* → Gallery Service
/api/tasks/* → Task Service
/api/square/* → Recommendation Service (或 Social Service)
七、服务依赖关系图
┌─────────────┐
│ Client │
│ (Mobile) │
└──────┬──────┘
│
│ REST API
▼
┌─────────────┐
│ Gateway │
│ (BFF) │
└──────┬──────┘
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ User Service │ │Asset Service │ │Social Service│
│ (Auth+User) │ └──────┬───────┘ └──────┬───────┘
└──────┬───────┘ │ │
│ │ │
└─────────────────┼──────────────────┘
│
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│Gallery Service│ │Task Service │ │Recommendation│
└──────┬───────┘ └──────┬───────┘ │ Service │
│ │ └──────────────┘
└────────────────┘
│ │
└────────┬────────┘
│
│ Events (MQ)
│
┌────────┴────────┐
│ PostgreSQL │
│ (Rules DB) │
└────────────────┘
八、部署建议
8.1 初期部署(方案A)
- User Service: 2-3实例(认证和用户管理,高频访问)
- Asset Service: 2-3实例(异步任务较多)
- Gallery Service: 2-3实例
- Social Service: 2-3实例
- Task Service: 2实例
8.2 扩展建议
- 水平扩展:根据负载增加实例数
- 数据库读写分离:主从复制,读操作走从库
- 缓存层:Redis缓存热点数据
- CDN:静态资源(图片)使用CDN加速
九、总结
9.1 推荐方案
初期(MVP):使用方案A(核心服务拆分),共5个核心微服务
- User Service(用户与认证服务):合并认证和用户管理,减少服务间调用,保证事务一致性
- Asset Service(资产服务)
- Social Service(社交服务)
- Gallery Service(展馆服务)
- Task Service(任务服务)
- 可选:Recommendation Service(推荐服务)- 初期可放在Social Service中
优势:
- 职责清晰,易于维护
- 可独立扩展
- 服务间耦合度适中
- 认证和用户管理合并后,注册、登录、身份切换等操作在同一服务内完成,保证数据一致性
未来扩展:
- 如果推荐算法复杂 → 拆分 Recommendation Service
- 如果任务系统复杂 → 可保持独立或合并到其他服务
- 如果需要搜索功能 → 新增 Search Service
- 如果认证服务负载过高 → 可考虑将认证独立拆分(但当前阶段不建议)
9.2 关键设计点
- 粉丝身份隔离:使用
user_id + star_id作为联合主键 - JWT Token:Token中包含user_id和star_id,前端直接使用Token
- 规则管理:PostgreSQL存储,启动时加载到内存,支持热更新
- 异步处理:铸造、任务进度等通过消息队列解耦
- 数据一致性:关键操作使用分布式事务或最终一致性
9.3 下一步行动
- 细化每个服务的接口定义(更新proto文件)
- 设计数据库表结构(包括规则表)
- 实现JWT Token生成和验证逻辑(Token中包含user_id和star_id)
- 实现规则加载机制
- 搭建消息队列基础设施