1. 混合云任务调度概述
混合云任务调度结合了公有云的弹性资源与私有云的安全控制优势,特别适合需要突发计算能力的场景(如大规模数据分析)。FastAPI的异步特性(基于ASGI标准)使其成为构建高并发任务调度API的理想选择。通过异步操作,我们能在单个节点轻松管理数千个并发任务。
典型架构:
css
[用户请求] → [FastAPI网关] → [任务队列] → [公有云工作节点]
│ → [私有云工作节点]
↓
[状态数据库]
2. 任务调度API设计
核心组件:
- 任务定义模型(Pydantic Schema)
- 异步任务队列(Celery + Redis)
- 混合云路由模块
- 任务状态跟踪
流程图:
graph LR
A[用户提交任务] --> B(FastAPI网关)
B --> C[参数验证]
C --> D{路由决策}
D -->|公有云| E[公有云队列]
D -->|私有云| F[私有云队列]
E --> G[云工作节点]
F --> H[本地工作节点]
G & H --> I[(结果数据库)]
I --> J[状态API反馈]
3. 代码实现
依赖库:
ini
fastapi==0.103.1
pydantic==2.5.0
celery==5.3.1
redis==4.5.5
核心代码:
python
from fastapi import Depends, FastAPI, BackgroundTasks
from pydantic import BaseModel
from celery import Celery
from contextlib import asynccontextmanager
# 配置中心模型
class CloudConfig(BaseModel):
public_cloud_url: str
private_cloud_key: str
# 初始化Redis连接
@asynccontextmanager
async def redis_connection():
import redis
r = redis.Redis(host='localhost', port=6379)
try:
yield r
finally:
r.close()
# 依赖注入配置
def get_cloud_config() -> CloudConfig:
return CloudConfig(
public_cloud_url="https://api.public.cloud/jobs",
private_cloud_key="secret_key_123"
)
# 初始化Celery
celery_app = Celery('tasks', broker='redis://localhost:6379/0')
# 定义任务模型
class JobRequest(BaseModel):
job_type: str
params: dict
target_cloud: str # 'public' 或 'private'
app = FastAPI()
@app.post("/schedule-job")
async def schedule_job(
job: JobRequest,
bg_tasks: BackgroundTasks,
config: CloudConfig = Depends(get_cloud_config),
redis_conn=Depends(redis_connection)
):
# 参数验证通过Pydantic自动完成
# 创建任务记录到数据库
await redis_conn.set(f"job:{job.job_type}", "pending")
# 根据目标云分发任务
if job.target_cloud == "public":
bg_tasks.add_task(execute_public_cloud_job, job, config)
else:
bg_tasks.add_task(execute_private_cloud_job, job, config)
return {"status": "scheduled", "job_id": job.job_type}
# 公有云执行函数
@celery_app.task
def execute_public_cloud_job(job: JobRequest, config: CloudConfig):
import requests
# 实际执行逻辑
response = requests.post(
config.public_cloud_url,
json=job.params,
headers={"Authorization": f"Bearer {config.public_cloud_key}"}
)
return response.json()
# 私有云执行函数
@celery_app.task
def execute_private_cloud_job(job: JobRequest, config: CloudConfig):
# 调用内部API执行任务
return {"status": "completed", "cloud": "private"}
代码解析
-
依赖注入系统
get_cloud_config()
: 提供统一的配置访问入口redis_connection()
: 使用上下文管理器管理资源生命周期BackgroundTasks
: 异步执行耗时操作
-
Pydantic数据验证
JobRequest
模型确保参数正确性- 自动生成API文档验证规则
-
混合云调度策略
- 根据
target_cloud
选择执行路径 - Celery作为任务队列保证可靠性
- 根据
4. 场景案例:视频转码服务
业务需求:
- 普通视频转码 → 私有云节点
- 8K HDR视频转码 → 公有云GPU节点
实现效果:
json
// 提交任务
POST /submit-task
{
"task_type": "8k_transcode",
"data": {"video_id": "1234"},
"priority": 5
}
// 响应
{
"task_id": "550e8400",
"queue": "public_cloud_queue"
}
系统自动将高负荷任务路由到公有云,同时普通任务在本地处理。
课后Quiz
问题:当同时向公有云和私有云提交任务时,如何保证原子性(即所有子任务要么全部成功,要么全部回滚)?
选项:
- 使用数据库事务记录所有任务状态
- 依赖FastAPI的自动错误处理
- 采用SAGA分布式事务模式
- 忽略此问题,云服务自带容错
答案及解析 :
正确答案是选项3(采用SAGA分布式事务模式)。
在分布式系统中无法使用传统ACID事务时,SAGA模式通过一系列本地事务+补偿事务实现最终一致性。具体实现:
- 在Redis中创建事务ID记录所有任务状态
- 每个子任务完成后更新状态
- 若任一任务失败,执行已成功任务的补偿操作
- FastAPI的依赖注入可以统一管理事务上下文
常见报错解决方案
报错:422 Validation Error
场景:
json
POST /schedule-job
{
"job_type": "data_sync",
"params": {"source": "db1"},
"target_cloud": "hybrid" # 非有效值
}
原因:
- Pydantic模型验证失败(
target_cloud
只允许'public'或'private') - 字段类型不匹配
- 缺少必填字段
解决方法:
- 检查API文档确认参数格式
- 使用try-except捕获验证异常:
python
from fastapi import HTTPException
@app.post("/schedule-job")
async def schedule_job(job: JobRequest):
try:
# 业务逻辑
except ValidationError as e:
raise HTTPException(422, detail=str(e))
预防措施:
- 在前端使用自动生成的表单(FastAPI的
/docs
提供) - 编写单元测试覆盖所有参数组合
- 添加自定义验证器:
python
from pydantic import field_validator
class JobRequest(BaseModel):
...
@field_validator('target_cloud')
def check_cloud_type(cls, v):
if v not in ['public', 'private']:
raise ValueError("Invalid cloud type")
return v
报错:503 Service Unavailable
原因:
- Redis或Celery服务不可用
- 云API调用超时
- 资源连接池耗尽
解决方法:
- 添加健康检查端点:
python
@app.get("/health")
def health_check(redis_conn=Depends(redis_connection)):
if redis_conn.ping():
return {"status": "ok"}
raise HTTPException(503)
- 实现弹性重试机制:
python
from tenacity import retry, stop_after_attempt
@retry(stop=stop_after_attempt(3))
def execute_public_cloud_job(...):
# 重试逻辑
预防措施:
- 使用连接池管理数据库连接
- 设置合理的超时参数:
python
# 在依赖项中设置
@asynccontextmanager
async def redis_connection():
r = redis.Redis(
...,
socket_timeout=5,
socket_connect_timeout=2
)
报错:504 Gateway Timeout
原因:
- 后台任务执行超时
- 同步操作阻塞事件循环
- 资源死锁
解决方法:
- 确保长时间任务放入后台队列:
python
bg_tasks.add_task(long_running_job) # 而不是直接调用
- 拆分大任务为小批次:
python
# 在Celery任务中
for chunk in split_data(data, 1000):
process_chunk.delay(chunk)
预防措施:
- 使用性能监控工具(如Prometheus)
- 限制单个任务最大执行时间:
python
@celery_app.task(time_limit=300) # 5分钟超时
def process_data(...):
...
关键准则:永远保持FastAPI的请求/响应循环异步,耗时操作委托给后台任务系统。