# 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 #### 阶段4:API重构(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, ) ```