cosmo/ARCHITECTURE_PLAN.md

393 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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. **准备安装脚本**:自动化安装PostgreSQLRedis
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,
)
```