This commit is contained in:
cjw
2026-02-11 22:40:35 +08:00
parent 96000f3f11
commit 7b09eb3d89
1094 changed files with 242874 additions and 1 deletions
+465
View File
@@ -0,0 +1,465 @@
# RustFS 对象存储集成说明
## 架构概述
本项目采用 **RustFS** 作为对象存储和 **PostgreSQL** 作为元数据存储的双层存储架构。
```
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (FastAPI) │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────┴──────────────┐
│ │
┌───────▼────────┐ ┌─────────▼─────────┐
│ PostgreSQL │ │ RustFS │
│ (元数据) │ │ (对象存储) │
│ │ │ │
│ - users │ │ - stp-files │
│ - stp_files │ │ - geometry │
│ - geometry_data│ │ - mold-cavities │
│ - mold_cavity │ │ - html-files │
│ - features │ │ - user-files │
│ - logs │ │ │
└────────────────┘ └──────────────────┘
```
## RustFS API 端点
假设 RustFS 运行在 `http://localhost:8080`,需要实现以下 REST API:
### 1. 健康检查
```
GET /health
返回: 200 OK
```
### 2. 初始化上传
```
POST /api/v1/upload/init
Content-Type: application/json
Authorization: Bearer <api_key>
请求体:
{
"namespace": "moldinsight/stp-files",
"key": "stp-files/abc123.stp",
"file_size": 1234567,
"file_hash": "sha256_hash",
"metadata": {
"original_filename": "model.stp",
"user_id": "1"
}
}
响应:
{
"upload_id": "unique-upload-id",
"upload_url": "https://rustfs/upload/xyz",
"expires_at": "2024-01-01T00:00:00Z"
}
```
### 3. 上传文件内容
```
PUT <upload_url>
Content-Type: application/octet-stream
Content-Length: 1234567
X-File-Hash: sha256_hash
请求体: <文件二进制数据>
响应: 201 Created
```
### 4. 完成上传
```
POST /api/v1/upload/complete
Content-Type: application/json
Authorization: Bearer <api_key>
请求体:
{
"upload_id": "unique-upload-id",
"namespace": "moldinsight/stp-files",
"key": "stp-files/abc123.stp"
}
响应:
{
"object_key": "moldinsight/stp-files/abc123.stp",
"etag": "d41d8cd98f00b204e9800998ecf8427e",
"created_at": "2024-01-01T00:00:00Z"
}
```
### 5. 上传 JSON(小文件,直接上传)
```
PUT /api/v1/objects/<namespace>/<key>
Content-Type: application/json
Authorization: Bearer <api_key>
X-File-Hash: sha256_hash
请求体: <JSON字符串>
响应: 201 Created
{
"object_key": "moldinsight/geometry/abc123.json",
"etag": "d41d8cd98f00b204e9800998ecf8427e",
"created_at": "2024-01-01T00:00:00Z"
}
```
### 6. 下载文件
```
GET /api/v1/objects/<namespace>/<key>
Authorization: Bearer <api_key>
响应: <文件二进制数据>
Content-Type: <原上传时的内容类型>
Content-Length: <文件大小>
ETag: <文件etag>
```
### 7. 获取文件信息
```
GET /api/v1/objects/<namespace>/<key>/info
Authorization: Bearer <api_key>
响应:
{
"object_key": "moldinsight/stp-files/abc123.stp",
"namespace": "moldinsight/stp-files",
"file_size": 1234567,
"file_hash": "sha256_hash",
"content_type": "application/octet-stream",
"created_at": "2024-01-01T00:00:00Z",
"last_modified": "2024-01-01T00:00:00Z",
"metadata": {
"original_filename": "model.stp",
"user_id": "1"
}
}
```
### 8. 删除文件
```
DELETE /api/v1/objects/<namespace>/<key>
Authorization: Bearer <api_key>
响应: 204 No Content
```
### 9. 列出文件
```
GET /api/v1/buckets/<namespace>/objects?prefix=stp-files
Authorization: Bearer <api_key>
响应:
{
"namespace": "moldinsight/stp-files",
"prefix": "stp-files",
"objects": [
{
"object_key": "moldinsight/stp-files/abc123.stp",
"file_size": 1234567,
"file_hash": "sha256_hash",
"created_at": "2024-01-01T00:00:00Z"
},
...
],
"is_truncated": false,
"next_marker": null
}
```
### 10. 生成预签名 URL
```
POST /api/v1/presigned-url
Content-Type: application/json
Authorization: Bearer <api_key>
请求体:
{
"namespace": "moldinsight/stp-files",
"key": "stp-files/abc123.stp",
"expires": 3600,
"method": "GET"
}
响应:
{
"url": "https://rustfs/objects/moldinsight/stp-files/abc123.stp?signature=xyz&expires=123",
"expires_at": "2024-01-01T01:00:00Z"
}
```
### 11. 存储统计
```
GET /api/v1/stats
Authorization: Bearer <api_key>
响应:
{
"total_objects": 1234,
"total_size": 1234567890,
"namespace_stats": {
"moldinsight/stp-files": {
"object_count": 100,
"total_size": 123456789
},
"moldinsight/geometry": {
"object_count": 200,
"total_size": 234567890
},
...
}
}
```
## 存储桶(命名空间)
| 命名空间 | 用途 | 存储内容 |
|---------|------|---------|
| `moldinsight/stp-files` | STP/STEP文件 | 用户上传的原始3D模型文件 |
| `moldinsight/geometry` | 几何数据 | 几何分析结果的JSON数据 |
| `moldinsight/mold-cavities` | 模具型腔数据 | 模具设计的详细JSON数据 |
| `moldinsight/html` | HTML文件 | 生成的HTML报告文件 |
| `moldinsight/user-files` | 用户文件 | 其他用户上传的文件 |
## 快速开始
### 1. 配置环境变量
```bash
# 复制示例配置
cp .env.example .env
# 编辑 .env 文件
nano .env
```
设置 RustFS 相关配置:
```env
RUSTFS_ENDPOINT=http://localhost:8080
RUSTFS_API_KEY=your-rustfs-api-key
RUSTFS_TIMEOUT=30
RUSTFS_PRESIGNED_URL_EXPIRES=3600
```
### 2. 启动 RustFS 服务
假设你已经有 RustFS 服务,如果没有,可以按照以下方式启动:
```bash
# 使用 Docker(如果提供了 Docker 镜像)
docker run -d \
--name rustfs \
-p 8080:8080 \
-e RUSTFS_API_KEY=your-rustfs-api-key \
-e RUSTFS_STORAGE_PATH=/data \
-v rustfs_data:/data \
your-registry/rustfs:latest
# 或直接运行编译好的二进制文件
./rustfs-server --port 8080 --api-key your-rustfs-api-key --storage-path ./rustfs-data
```
### 3. 初始化存储
```bash
# 初始化 RustFS 连接
python src/storage/init_storage.py
```
### 4. 使用存储集成服务
```python
from services.storage_integration_rustfs import storage_integration
from database.database import db_manager
async def upload_file(file_path: str):
async with db_manager.get_session() as session:
stp_file = await storage_integration.save_stp_file(
session=session,
file_path=Path(file_path),
original_filename="model.stp",
user_id=1
)
print(f"文件已保存到 RustFS,ID: {stp_file.id}")
```
## Python 客户端使用
### 上传文件
```python
from storage.rustfs_storage import rustfs_manager
from pathlib import Path
# 先连接
await rustfs_manager.connect(
endpoint="http://localhost:8080",
api_key="your-api-key"
)
# 上传 STP 文件
result = await rustfs_manager.upload_file(
bucket_type='stp_files',
file_path=Path('model.stp'),
original_filename='model.stp'
)
print(f"上传成功: {result['object_key']}")
```
### 上传 JSON 数据
```python
geometry_data = {
"volume": 5061079.99,
"surface_area": 640037.28,
"bounding_box": {...}
}
result = await rustfs_manager.upload_json_data(
bucket_type='geometry_data',
json_data=geometry_data,
file_hash='sha256-hash'
)
print(f"JSON 上传成功: {result['object_key']}")
```
### 下载文件
```python
data = await rustfs_manager.download_file(
bucket_type='geometry_data',
object_key='geometry_data/abc123.json'
)
json_data = json.loads(data.decode('utf-8'))
print(json_data)
```
### 生成预签名 URL
```python
url = await rustfs_manager.generate_presigned_url(
bucket_type='stp_files',
object_key='stp-files/abc123.stp',
expires=3600 # 1小时
)
print(f"临时访问链接: {url}")
```
### 列出文件
```python
files = await rustfs_manager.list_files(
bucket_type='stp_files',
prefix='stp-files'
)
for f in files:
print(f"{f['object_key']}: {f['file_size']} bytes")
```
## RustFS 服务端实现参考
如果你需要实现 RustFS 服务端,以下是一个简单的 Rust 实现框架:
```rust
use actix_web::{web, App, HttpServer};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Deserialize)]
struct UploadInitRequest {
namespace: String,
key: String,
file_size: u64,
file_hash: String,
metadata: Option<serde_json::Value>,
}
#[derive(Serialize)]
struct UploadInitResponse {
upload_id: String,
upload_url: String,
expires_at: String,
}
async fn upload_init(
req: web::Json<UploadInitRequest>,
path: web::Data<PathBuf>
) -> impl web::Responder {
// 验证 API Key
// 生成 upload_id
// 返回上传 URL
web::Json(UploadInitResponse { ... })
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/health", web::get().to(health_check))
.route("/api/v1/upload/init", web::post().to(upload_init))
// ... 其他路由
})
.bind("0.0.0.0:8080")?
.run()
.await
}
```
## 故障排除
### 连接 RustFS 失败
```
错误: RustFS 连接失败
解决:
1. 检查 RUSTFS_ENDPOINT 是否正确
2. 检查 RustFS 服务是否运行
3. 检查网络连接
4. 验证 API Key
```
### 文件上传失败
```
错误: RustFS 上传失败
解决:
1. 检查磁盘空间
2. 检查网络连接
3. 检查文件大小限制
4. 查看服务端日志
```
### 预签名 URL 失败
```
错误: RustFS 生成预签名URL失败
解决:
1. 检查 expires 参数是否有效
2. 确认服务端支持预签名 URL
3. 检查权限配置
```
## 性能优化建议
### 客户端
- 使用连接池(aiohttp 默认支持)
- 实现上传重试机制
- 对大文件使用分片上传
- 并行上传多个小文件
### 服务端
- 实现缓存层
- 支持范围请求(断点续传)
- 压缩存储
- CDN 分发静态文件
## 安全建议
1. **更改默认 API Key**:生产环境必须使用强密钥
2. **启用 HTTPS**:生产环境使用 TLS
3. **访问控制**:配置命名空间权限
4. **数据加密**:敏感数据加密存储
5. **日志监控**:记录所有访问和操作
+255
View File
@@ -0,0 +1,255 @@
# 存储架构说明
## 架构概述
本项目采用 **MinIO (S3兼容)** 作为对象存储和 **PostgreSQL** 作为元数据存储的双层存储架构。
```
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (FastAPI) │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────┴──────────────┐
│ │
┌───────▼────────┐ ┌─────────▼─────────┐
│ PostgreSQL │ │ MinIO/S3 │
│ (元数据) │ │ (对象存储) │
│ │ │ │
│ - users │ │ - stp-files │
│ - stp_files │ │ - geometry │
│ - geometry_data│ │ - mold-cavities │
│ - mold_cavity │ │ - html-files │
│ - features │ │ - user-files │
│ - logs │ │ │
└────────────────┘ └──────────────────┘
```
## PostgreSQL 数据表
### 用户管理
- `users` - 用户信息(用户名、邮箱、密码等)
### 文件管理
- `stp_files` - STP文件元数据(文件名、哈希、大小、状态等)
- `html_files` - HTML报告文件元数据
### 几何数据
- `geometry_data` - 几何分析数据(体积、表面积、边界框等)
- `mold_cavity_data` - 模具型腔数据(工艺参数、质量评估等)
- `feature_detections` - 特征检测结果(壁厚、拔模角等)
- `design_recommendations` - 设计建议(优先级、参数等)
### 任务和日志
- `processing_tasks` - 处理任务记录
- `user_activities` - 用户活动日志
- `system_logs` - 系统日志
## MinIO 存储桶
| 存储桶名称 | 用途 | 存储内容 |
|-------------|------|---------|
| `moldinsight-stp-files` | STP/STEP文件 | 用户上传的原始3D模型文件 |
| `moldinsight-geometry` | 几何数据 | 几何分析结果的JSON数据 |
| `moldinsight-mold-cavities` | 模具型腔数据 | 模具设计的详细JSON数据 |
| `moldinsight-html` | HTML文件 | 生成的HTML报告文件 |
| `moldinsight-user-files` | 用户文件 | 其他用户上传的文件 |
## 快速开始
### 1. 安装依赖
```bash
pip install -r requirements.txt
```
### 2. 启动 PostgreSQL
使用 Docker Compose(推荐):
```bash
docker-compose up -d postgres
```
或手动启动:
```bash
# 创建数据库
createdb moldinsight
# 运行数据库容器
docker run -d \
--name postgres \
-e POSTGRES_DB=moldinsight \
-e POSTGRES_USER=moldinsight_user \
-e POSTGRES_PASSWORD=your_password \
-p 5432:5432 \
postgres:15
```
### 3. 启动 MinIO
使用 Docker Compose(推荐):
```bash
docker-compose up -d minio
```
或手动启动:
```bash
docker run -d \
--name minio \
-p 9000:9000 \
-p 9001:9001 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
minio/minio server /data --console-address ":9001"
```
### 4. 配置环境变量
```bash
# 复制示例配置
cp .env.example .env
# 编辑 .env 文件,修改数据库和MinIO配置
nano .env
```
### 5. 初始化数据库和存储
```bash
# 初始化数据库
python src/database/init_db.py
# 初始化MinIO存储
python src/storage/init_storage.py
```
### 6. 启动服务
```bash
python src/main.py
```
## 使用示例
### 保存STP文件
```python
from services.storage_integration import storage_integration
from database.database import db_manager
async def upload_file(file_path: str):
async with db_manager.get_session() as session:
stp_file = await storage_integration.save_stp_file(
session=session,
file_path=Path(file_path),
original_filename="model.stp",
user_id=1
)
print(f"文件已保存,ID: {stp_file.id}")
```
### 保存几何数据
```python
async def save_geometry(stp_file_id: int, geometry_data: dict):
async with db_manager.get_session() as session:
geo_data = await storage_integration.save_geometry_data(
session=session,
stp_file_id=stp_file_id,
geometry_json=geometry_data,
analysis_method="pythonocc"
)
print(f"几何数据已保存,ID: {geo_data.id}")
```
### 获取文件数据
```python
async def get_file_data(stp_file_id: int):
async with db_manager.get_session() as session:
data = await storage_integration.get_stp_file_with_data(
session=session,
stp_file_id=stp_file_id
)
# 访问几何数据
geometry = data['geometry_data']
print(f"体积: {geometry['volume']}")
print(f"表面积: {geometry['surface_area']}")
# 访问模具型腔数据
cavity = data['mold_cavity_data']
print(f"模具材料: {cavity['mold_material']}")
# 访问特征和建议
for feature in data['features']:
print(f"特征: {feature['feature_type']}")
```
## 数据清理策略
### MinIO 对象存储
- 设置生命周期策略自动删除旧文件
- 示例:删除30天前的临时文件
### PostgreSQL
- 定期清理已删除用户的记录
- 归档超过6个月的日志数据
## 监控和维护
### 检查存储使用情况
```bash
# MinIO控制台
# http://localhost:9001
# 用户名: minioadmin
# 密码: minioadmin
```
### 数据库备份
```bash
# 备份数据库
pg_dump -h localhost -U moldinsight_user moldinsight > backup.sql
# 恢复数据库
psql -h localhost -U moldinsight_user moldinsight < backup.sql
```
## 性能优化
### PostgreSQL
- 创建适当的索引(已在模型中定义)
- 定期运行 VACUUM 和 ANALYZE
- 考虑使用连接池(已配置)
### MinIO
- 启用缓存层
- 配置CDN分发静态文件
- 使用多区域复制
## 安全建议
1. **更改默认密码**:生产环境必须更改所有默认密码
2. **启用TLS**:生产环境启用 HTTPS
3. **访问控制**:配置适当的用户权限
4. **数据加密**:敏感数据加密存储
5. **定期备份**:设置自动备份策略
## 故障排除
### 连接MinIO失败
```
错误: 对象存储连接失败
解决: 检查 MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY 配置
```
### 数据库连接失败
```
错误: 数据库连接失败
解决: 检查 DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD 配置
```
### 文件上传失败
```
错误: STP文件上传失败
解决: 检查磁盘空间、网络连接、MinIO权限
```