10 KiB
10 KiB
Cosmo 平台架构升级规划
一、现状分析
当前架构
- 前端数据:静态JSON文件(galaxies, constellations, stars, probe-models)
- 后端数据:NASA Horizons API实时查询 + 简单内存缓存
- 资源存储:纹理和3D模型在前端
public/目录 - 缓存策略:内存缓存(进程级别,重启失效)
痛点
- 数据管理分散:前端JSON + 后端代码硬编码
- 缓存不持久:服务重启后需要重新查询NASA API
- 资源管理混乱:纹理、模型路径分散在前后端
- 扩展困难:添加新天体类型需要修改多处代码
- 无历史数据:无法查询天体历史轨迹
- 性能问题:NASA API查询慢(每个天体1-2秒)
未来需求
- 支持更多天体类型(彗星、小行星、系外行星等)
- 用户自定义天体
- 历史轨迹查询和时间旅行
- 性能优化(减少NASA API调用)
- 统一的资源管理
- 可能的多用户支持
二、技术方案
2.1 数据库方案
推荐:PostgreSQL + SQLAlchemy
选择理由:
- 功能强大:支持复杂查询、全文搜索、JSON字段
- PostGIS扩展:专门处理空间数据(未来可能需要)
- 时间序列优化:通过TimescaleDB扩展支持高效时间序列查询
- 成熟生态:Python生态支持好(asyncpg, SQLAlchemy 2.0异步支持)
- 扩展性:支持大规模数据和并发
备选方案:
- SQLite:适合单机部署,但功能和性能有限
- MongoDB:文档型数据库,但对关系查询支持不如PostgreSQL
数据库设计
-- 天体类型枚举
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
- 最终数据源
- 只在缓存未命中时调用
缓存键设计
# 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
文件访问
# 后端提供统一的静态文件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天)
- 安装PostgreSQL和Redis
- 设置SQLAlchemy ORM
- 创建数据库表结构
- 数据迁移脚本:
CELESTIAL_BODIESdict →celestial_bodies表- 前端JSON文件 →
static_data表
阶段2:缓存层升级(1天)
- 集成Redis客户端
- 实现三层缓存逻辑
- NASA API结果持久化到数据库
阶段3:资源管理迁移(1天)
- 迁移纹理文件到
backend/upload/textures/ - 迁移3D模型到
backend/upload/models/ - 建立资源表记录
- 实现静态文件服务API
阶段4:API重构(1-2天)
- 新增数据库查询API
- 前端调整为从后端API获取所有数据
- 移除前端静态JSON文件依赖
阶段5:优化和测试(1天)
- 性能测试
- 缓存命中率监控
- 数据一致性验证
三、技术栈
后端新增依赖
Python包
# 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+
# macOS
brew install postgresql@15
brew services start postgresql@15
# 创建数据库
createdb cosmo_db
Redis 7+
# macOS
brew install redis
brew services start redis
# 验证
redis-cli ping # 应返回 PONG
前端调整
- 移除静态JSON文件依赖
- 所有数据通过API获取
- 静态资源URL指向后端API
四、性能优化
预期改进
- NASA API调用减少90%:通过数据库+Redis缓存
- 首次加载加速:从缓存/数据库读取,无需等待NASA API
- 支持历史查询:数据库存储历史位置数据
- 并发能力提升:Redis支持分布式缓存
监控指标
- 缓存命中率(L1/L2/L3)
- NASA API调用次数
- 数据库查询时间
- API响应时间
五、成本分析
开发成本
- 总工时:约6-7天
- 可分阶段实施,每阶段独立可用
运行成本
- PostgreSQL:~100MB内存(小规模)
- Redis:~50MB内存
- 磁盘:~500MB-1GB(数据+资源文件)
维护成本
- 数据库备份:每日自动备份
- 缓存清理:自动过期,无需人工干预
- 资源管理:统一后端管理,更容易维护
六、风险和备选方案
风险
- PostgreSQL依赖:需要额外安装和维护
- 备选:先用SQLite,后续迁移
- 数据迁移复杂度:现有数据分散
- 缓解:编写完善的迁移脚本和回滚方案
- Redis单点故障:Redis挂了影响性能
- 缓解:Redis只是缓存,挂了仍可从数据库读取
回滚方案
- 保留现有代码分支
- 数据库和缓存作为可选功能
- 降级到内存缓存 + NASA API直连
七、实施建议
推荐方案:完整实施
理由:
- 项目正处于扩展期,早期投入架构收益大
- PostgreSQL+Redis是成熟方案,风险可控
- 支持未来功能扩展(用户系统、自定义天体等)
- 性能提升明显(缓存命中后响应 <50ms)
简化方案(如果资源有限)
-
只用PostgreSQL,不用Redis
- 降级为两层:内存 → 数据库 → NASA API
- 仍可实现持久化和历史查询
- 性能略低但可接受
-
只用Redis,不用PostgreSQL
- 只做缓存,不做持久化
- 适合小规模、不需要历史数据的场景
- 不推荐(失去了数据管理能力)
八、下一步
确认方案后,我将:
- 准备安装脚本:自动化安装PostgreSQL和Redis
- 生成数据库Schema:完整的SQL DDL
- 编写迁移脚本:将现有数据导入数据库
- 实现缓存层:三层缓存逻辑
- 重构API:支持数据库查询
- 迁移静态资源:统一到后端管理
附录:配置示例
PostgreSQL连接配置
# .env
DATABASE_URL=postgresql+asyncpg://cosmo:password@localhost:5432/cosmo_db
Redis连接配置
# .env
REDIS_URL=redis://localhost:6379/0
数据库连接池配置
# app/database.py
engine = create_async_engine(
DATABASE_URL,
pool_size=20,
max_overflow=10,
pool_pre_ping=True,
)