cosmo/ARCHITECTURE_PLAN.md

393 lines
10 KiB
Markdown
Raw Normal View History

2025-12-02 13:25:28 +00:00
# Cosmo 平台架构升级规划
## 一、现状分析
### 当前架构
- **前端数据**静态JSON文件galaxies, constellations, stars, probe-models
- **后端数据**NASA Horizons API实时查询 + 简单内存缓存
- **资源存储**纹理和3D模型在前端 `public/` 目录
- **缓存策略**:内存缓存(进程级别,重启失效)
### 痛点
1. **数据管理分散**前端JSON + 后端代码硬编码
2. **缓存不持久**服务重启后需要重新查询NASA API
3. **资源管理混乱**:纹理、模型路径分散在前后端
4. **扩展困难**:添加新天体类型需要修改多处代码
5. **无历史数据**:无法查询天体历史轨迹
6. **性能问题**NASA API查询慢每个天体1-2秒
### 未来需求
- 支持更多天体类型(彗星、小行星、系外行星等)
- 用户自定义天体
- 历史轨迹查询和时间旅行
- 性能优化减少NASA API调用
- 统一的资源管理
- 可能的多用户支持
---
## 二、技术方案
### 2.1 数据库方案
#### 推荐PostgreSQL + SQLAlchemy
**选择理由**
1. **功能强大**支持复杂查询、全文搜索、JSON字段
2. **PostGIS扩展**:专门处理空间数据(未来可能需要)
3. **时间序列优化**通过TimescaleDB扩展支持高效时间序列查询
4. **成熟生态**Python生态支持好asyncpg, SQLAlchemy 2.0异步支持)
5. **扩展性**:支持大规模数据和并发
**备选方案**
- **SQLite**:适合单机部署,但功能和性能有限
- **MongoDB**文档型数据库但对关系查询支持不如PostgreSQL
#### 数据库设计
```sql
-- 天体类型枚举
CREATE TYPE celestial_type AS ENUM ('star', 'planet', 'moon', 'probe', 'comet', 'asteroid', 'galaxy', 'constellation');
-- 天体基本信息表
CREATE TABLE celestial_bodies (
id VARCHAR(50) PRIMARY KEY, -- JPL Horizons ID 或自定义ID
name VARCHAR(200) NOT NULL,
name_zh VARCHAR(200),
type celestial_type NOT NULL,
description TEXT,
metadata JSONB, -- 灵活存储各种元数据launch_date, status等
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 位置历史表(时间序列数据)
CREATE TABLE positions (
id BIGSERIAL PRIMARY KEY,
body_id VARCHAR(50) REFERENCES celestial_bodies(id),
time TIMESTAMP NOT NULL,
x DOUBLE PRECISION NOT NULL, -- AU
y DOUBLE PRECISION NOT NULL,
z DOUBLE PRECISION NOT NULL,
source VARCHAR(50), -- 'nasa_horizons', 'calculated', 'user_defined'
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_positions_body_time ON positions(body_id, time DESC);
-- 资源管理表(纹理、模型等)
CREATE TABLE resources (
id SERIAL PRIMARY KEY,
body_id VARCHAR(50) REFERENCES celestial_bodies(id),
type VARCHAR(50) NOT NULL, -- 'texture', 'model', 'icon'
file_path VARCHAR(500) NOT NULL, -- 相对于upload目录的路径
file_size INTEGER,
mime_type VARCHAR(100),
metadata JSONB, -- 分辨率、格式等信息
created_at TIMESTAMP DEFAULT NOW()
);
-- 静态数据表(星座、星系等不变数据)
CREATE TABLE static_data (
id SERIAL PRIMARY KEY,
category VARCHAR(50) NOT NULL, -- 'constellation', 'galaxy', 'star'
name VARCHAR(200) NOT NULL,
name_zh VARCHAR(200),
data JSONB NOT NULL, -- 完整的静态数据
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- NASA API缓存表持久化缓存
CREATE TABLE nasa_cache (
cache_key VARCHAR(500) PRIMARY KEY,
body_id VARCHAR(50),
start_time TIMESTAMP,
end_time TIMESTAMP,
step VARCHAR(10),
data JSONB NOT NULL,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_nasa_cache_expires ON nasa_cache(expires_at);
```
### 2.2 缓存策略
#### 三层缓存架构
```
请求 → L1 (内存) → L2 (Redis) → L3 (数据库) → L4 (NASA API)
```
**L1: 进程内存缓存**(已有)
- TTL: 10分钟
- 用途:当前时间的天体位置(最热数据)
- 实现Python dict + TTL已有cache.py
**L2: Redis缓存**(新增)
- TTL:
- 当前时间数据1小时
- 历史数据7天
- 静态数据:永久(手动失效)
- 用途:
- NASA API响应缓存
- 会话数据
- 预计算结果
- 好处:
- 进程间共享
- 持久化(重启不丢失)
- 分布式支持
**L3: PostgreSQL数据库**
- 持久化存储
- 历史数据查询
- 复杂查询和统计
**L4: NASA Horizons API**
- 最终数据源
- 只在缓存未命中时调用
#### 缓存键设计
```python
# L1/L2 缓存键格式
"positions:{body_id}:{start}:{end}:{step}"
"static:{category}:{name}"
"texture:{body_id}:{type}"
# 示例
"positions:-31:2025-11-27:2025-11-27:1d"
"static:constellation:orion"
```
### 2.3 文件存储方案
#### 目录结构
```
cosmo/
├── backend/
│ ├── upload/ # 统一上传目录
│ │ ├── textures/
│ │ │ ├── planets/ # 行星纹理
│ │ │ ├── stars/ # 恒星纹理
│ │ │ └── probes/ # 探测器图标
│ │ ├── models/
│ │ │ ├── probes/ # 探测器3D模型
│ │ │ └── spacecraft/
│ │ └── data/ # 数据文件备份
│ └── app/
│ └── api/
│ └── static.py # 静态文件服务API
```
#### 文件访问
```python
# 后端提供统一的静态文件API
GET /api/static/textures/planets/earth.jpg
GET /api/static/models/probes/voyager1.glb
# 数据库记录
{
"body_id": "399",
"type": "texture",
"file_path": "textures/planets/2k_earth_daymap.jpg",
"url": "/api/static/textures/planets/2k_earth_daymap.jpg"
}
```
### 2.4 数据迁移路径
#### 阶段1数据库基础设施1-2天
1. 安装PostgreSQL和Redis
2. 设置SQLAlchemy ORM
3. 创建数据库表结构
4. 数据迁移脚本:
- `CELESTIAL_BODIES` dict → `celestial_bodies`
- 前端JSON文件 → `static_data`
#### 阶段2缓存层升级1天
1. 集成Redis客户端
2. 实现三层缓存逻辑
3. NASA API结果持久化到数据库
#### 阶段3资源管理迁移1天
1. 迁移纹理文件到 `backend/upload/textures/`
2. 迁移3D模型到 `backend/upload/models/`
3. 建立资源表记录
4. 实现静态文件服务API
#### 阶段4API重构1-2天
1. 新增数据库查询API
2. 前端调整为从后端API获取所有数据
3. 移除前端静态JSON文件依赖
#### 阶段5优化和测试1天
1. 性能测试
2. 缓存命中率监控
3. 数据一致性验证
---
## 三、技术栈
### 后端新增依赖
#### Python包
```bash
# ORM和数据库
sqlalchemy>=2.0.0 # ORM框架支持async
asyncpg>=0.29.0 # PostgreSQL异步驱动
alembic>=1.12.0 # 数据库迁移工具
# Redis缓存
redis>=5.0.0 # Redis客户端
aioredis>=2.0.0 # 异步Redis可选redis 5.0+已内置async支持
# 文件处理
python-multipart>=0.0.6 # 文件上传支持
aiofiles>=23.0.0 # 异步文件操作
Pillow>=10.0.0 # 图片处理(缩略图等)
```
#### 系统依赖
**PostgreSQL 15+**
```bash
# macOS
brew install postgresql@15
brew services start postgresql@15
# 创建数据库
createdb cosmo_db
```
**Redis 7+**
```bash
# macOS
brew install redis
brew services start redis
# 验证
redis-cli ping # 应返回 PONG
```
### 前端调整
- 移除静态JSON文件依赖
- 所有数据通过API获取
- 静态资源URL指向后端API
---
## 四、性能优化
### 预期改进
1. **NASA API调用减少90%**:通过数据库+Redis缓存
2. **首次加载加速**:从缓存/数据库读取无需等待NASA API
3. **支持历史查询**:数据库存储历史位置数据
4. **并发能力提升**Redis支持分布式缓存
### 监控指标
- 缓存命中率L1/L2/L3
- NASA API调用次数
- 数据库查询时间
- API响应时间
---
## 五、成本分析
### 开发成本
- 总工时约6-7天
- 可分阶段实施,每阶段独立可用
### 运行成本
- PostgreSQL~100MB内存小规模
- Redis~50MB内存
- 磁盘:~500MB-1GB数据+资源文件)
### 维护成本
- 数据库备份:每日自动备份
- 缓存清理:自动过期,无需人工干预
- 资源管理:统一后端管理,更容易维护
---
## 六、风险和备选方案
### 风险
1. **PostgreSQL依赖**:需要额外安装和维护
- 备选先用SQLite后续迁移
2. **数据迁移复杂度**:现有数据分散
- 缓解:编写完善的迁移脚本和回滚方案
3. **Redis单点故障**Redis挂了影响性能
- 缓解Redis只是缓存挂了仍可从数据库读取
### 回滚方案
- 保留现有代码分支
- 数据库和缓存作为可选功能
- 降级到内存缓存 + NASA API直连
---
## 七、实施建议
### 推荐方案:**完整实施**
理由:
1. 项目正处于扩展期,早期投入架构收益大
2. PostgreSQL+Redis是成熟方案风险可控
3. 支持未来功能扩展(用户系统、自定义天体等)
4. 性能提升明显(缓存命中后响应 <50ms
### 简化方案(如果资源有限)
1. **只用PostgreSQL不用Redis**
- 降级为两层:内存 → 数据库 → NASA API
- 仍可实现持久化和历史查询
- 性能略低但可接受
2. **只用Redis不用PostgreSQL**
- 只做缓存,不做持久化
- 适合小规模、不需要历史数据的场景
- 不推荐(失去了数据管理能力)
---
## 八、下一步
确认方案后,我将:
1. **准备安装脚本**自动化安装PostgreSQL和Redis
2. **生成数据库Schema**完整的SQL DDL
3. **编写迁移脚本**:将现有数据导入数据库
4. **实现缓存层**:三层缓存逻辑
5. **重构API**:支持数据库查询
6. **迁移静态资源**:统一到后端管理
---
## 附录:配置示例
### PostgreSQL连接配置
```python
# .env
DATABASE_URL=postgresql+asyncpg://cosmo:password@localhost:5432/cosmo_db
```
### Redis连接配置
```python
# .env
REDIS_URL=redis://localhost:6379/0
```
### 数据库连接池配置
```python
# app/database.py
engine = create_async_engine(
DATABASE_URL,
pool_size=20,
max_overflow=10,
pool_pre_ping=True,
)
```