15 KiB
15 KiB
RunningHub 并发能力分析与优化方案
版本: v2.1.0
更新时间: 2025-10-20
分析人员: AI架构团队
📊 一、RunningHub API并发能力评估
1.1 API架构分析
RunningHub采用异步任务处理模式,这种架构天然支持高并发:
客户端请求 → 提交任务(秒级响应) → 返回TaskID → 客户端轮询 → 获取结果
优势:
- ✅ 提交接口无需等待任务完成,可快速响应
- ✅ 任务在后台队列中处理,不占用HTTP连接
- ✅ 理论上可同时提交大量任务
1.2 并发限制因素
A. API Key限制(未知,需测试)
RunningHub未公开以下限制:
- ❓ 每秒最大请求数(QPS)
- ❓ 每分钟最大请求数(QPM)
- ❓ 单个API Key的并发任务数
- ❓ 账户级别的任务队列限制
建议测试方案:
# 逐步压力测试
1. 同时提交10个任务 → 观察响应
2. 同时提交50个任务 → 观察是否限流
3. 同时提交100个任务 → 找到阈值
B. 任务处理能力
根据API文档分析:
- 文生视频(10秒): 预计处理时间 2-5分钟
- 图生视频(10秒): 预计处理时间 2-5分钟
- 高清视频: 预计处理时间 5-10分钟
并发处理能力估算: 假设RunningHub后台有100个GPU实例,平均处理时间3分钟:
理论最大并发 = 100个GPU × (60秒 / 3分钟) = 约2000个任务/小时
C. 网络带宽限制
-
请求体大小:
- 文生视频:~2KB(prompt + 配置)
- 图生视频:~10KB-500KB(包含图片URL或Base64)
-
响应体大小:
- 提交响应:~500B
- 状态查询:~300B
- 结果获取:~1KB(只返回URL)
预计带宽需求(100并发):
上传:100 × 500KB = 50MB
下载(轮询10次/任务):100 × 10 × 1KB = 1MB
总计:~51MB(一次性峰值)
🔧 二、当前系统并发配置
2.1 系统参数
# application.yml
ai:
providers:
runninghub:
polling-interval: 10000 # 轮询间隔 10秒(已优化)
max-polling-times: 60 # 最大轮询60次 = 10分钟
queue:
max-concurrent: 50 # 每个模型最大并发50个
2.2 并发能力计算
A. 系统级并发
RunningHub模型数量: 12个
rh_sora2_text_portrait (文生视频-竖屏)
rh_sora2_text_landscape (文生视频-横屏)
rh_sora2_text_portrait_hd (文生视频-高清竖屏)
rh_sora2_text_landscape_hd (文生视频-高清横屏)
rh_sora2_text_portrait_15s (文生视频-竖屏15秒)
rh_sora2_text_landscape_15s (文生视频-横屏15秒)
rh_sora2_img_portrait (图生视频-竖屏)
rh_sora2_img_landscape (图生视频-横屏)
rh_sora2_img_portrait_hd (图生视频-高清竖屏)
rh_sora2_img_landscape_hd (图生视频-高清横屏)
rh_sora2_img_portrait_15s (图生视频-竖屏15秒)
rh_sora2_img_landscape_15s (图生视频-横屏15秒)
理论最大并发:
12个模型 × 50个/模型 = 600个并发任务
但实际上:
- RunningHub任务不走我们的队列系统(直接提交)
- 只受RunningHub API限制,不受我们的max-concurrent限制
实际并发能力: 无限制(取决于RunningHub服务端)
B. 轮询调度器负载
@Scheduled(fixedRateString = "${ai.providers.runninghub.polling-interval:10000}")
public void pollRunningHubTasks() {
// 查询所有processing状态的RunningHub任务
List<AiTask> processingTasks = aiTaskMapper.findProcessingTasksByProvider("runninghub");
// 每10秒轮询一次
for (AiTask task : processingTasks) {
// 查询状态 → 更新数据库 → 发送WebSocket通知
}
}
轮询负载分析(10秒间隔):
| 并发任务数 | 每次轮询耗时 | CPU使用率 | 网络流量/分钟 |
|---|---|---|---|
| 10 | ~1秒 | <5% | ~180KB |
| 50 | ~5秒 | ~10% | ~900KB |
| 100 | ~10秒 | ~20% | ~1.8MB |
| 200 | ~20秒 | ~40% | ~3.6MB |
| 500 | ~50秒 | ~80% | ~9MB |
安全阈值: 建议不超过200个并发任务,否则轮询调度器可能积压
⚠️ 三、潜在风险与瓶颈
3.1 轮询调度器阻塞
问题: 如果并发任务过多,单次轮询时间超过10秒,会导致任务堆积。
示例:
T0: 开始轮询200个任务(预计20秒)
T10: 第二次调度触发,但上一次还没结束 → 跳过或阻塞
T20: 第一次轮询完成
T30: 第三次调度触发
解决方案:
- 使用
@Scheduled(fixedDelay = 10000)替代fixedRate - 增加线程池,并发查询状态
3.2 数据库连接池耗尽
当前连接池配置(默认): HikariCP 默认10个连接
风险:
200个并发任务 × 每个任务3次数据库操作(查询+更新+日志) = 600次DB操作/10秒
解决方案:
spring:
datasource:
hikari:
maximum-pool-size: 50 # 增加连接池大小
minimum-idle: 10
connection-timeout: 30000
3.3 WebSocket连接数
问题: 每个在线用户需要一个WebSocket连接来接收实时通知。
并发用户数 vs WebSocket连接:
100个并发用户 = 100个WebSocket连接
500个并发用户 = 500个WebSocket连接
Tomcat默认限制: 200个线程
解决方案:
server:
tomcat:
threads:
max: 500 # 增加最大线程数
min-spare: 50
🚀 四、并发优化方案
方案A:保守配置(推荐用于初期)
目标: 稳定性优先,支持 100个并发任务
ai:
providers:
runninghub:
polling-interval: 10000 # 10秒轮询
max-polling-times: 60
spring:
datasource:
hikari:
maximum-pool-size: 30
minimum-idle: 10
server:
tomcat:
threads:
max: 300
min-spare: 50
预期性能:
- ✅ 轮询时间:~10秒/轮
- ✅ CPU使用率:<20%
- ✅ 内存占用:<2GB
- ✅ 网络带宽:~2MB/分钟
方案B:高并发配置(成熟期)
目标: 性能优先,支持 500个并发任务
ai:
providers:
runninghub:
polling-interval: 15000 # 15秒轮询(减少频率)
max-polling-times: 40 # 最大轮询40次 = 10分钟
batch-size: 50 # 分批查询,每批50个
spring:
datasource:
hikari:
maximum-pool-size: 100
minimum-idle: 20
server:
tomcat:
threads:
max: 1000
min-spare: 100
# 异步线程池配置
task:
execution:
pool:
core-size: 50
max-size: 200
queue-capacity: 500
优化代码(分批轮询):
@Scheduled(fixedDelay = 15000)
public void pollRunningHubTasks() {
List<AiTask> allTasks = aiTaskMapper.findProcessingTasksByProvider("runninghub");
// 分批处理,每批50个
int batchSize = 50;
for (int i = 0; i < allTasks.size(); i += batchSize) {
List<AiTask> batch = allTasks.subList(i, Math.min(i + batchSize, allTasks.size()));
// 并发查询这批任务
batch.parallelStream().forEach(task -> {
try {
pollSingleTask(task);
} catch (Exception e) {
log.error("轮询任务失败: {}", task.getTaskNo(), e);
}
});
}
}
预期性能:
- ✅ 轮询时间:~15秒/轮(分批并发)
- ✅ CPU使用率:<50%
- ✅ 内存占用:<4GB
- ✅ 网络带宽:~10MB/分钟
方案C:极致优化(企业级)
目标: 支持 2000+并发任务
架构升级:
- Redis消息队列 替代数据库轮询
- 独立轮询服务 部署多个实例
- 负载均衡 分散WebSocket连接
- 限流熔断 保护RunningHub API
graph LR
A[用户请求] --> B[API网关]
B --> C[业务服务集群]
C --> D[Redis队列]
D --> E1[轮询服务1]
D --> E2[轮询服务2]
D --> E3[轮询服务3]
E1 --> F[RunningHub API]
E2 --> F
E3 --> F
F --> G[MySQL主从]
C --> H[WebSocket集群]
📈 五、RunningHub API限流策略
5.1 客户端限流(防止自身被封)
@Component
public class RunningHubRateLimiter {
private final RateLimiter submitLimiter = RateLimiter.create(10.0); // 每秒10个提交
private final RateLimiter queryLimiter = RateLimiter.create(50.0); // 每秒50个查询
public void beforeSubmit() {
submitLimiter.acquire(); // 阻塞直到获得许可
}
public void beforeQuery() {
queryLimiter.acquire();
}
}
5.2 熔断降级(RunningHub故障时)
@Service
public class RunningHubProviderImpl implements AIProvider {
@HystrixCommand(
fallbackMethod = "submitTaskFallback",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "10000"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
}
)
public ProviderTaskResponse submitTask(ProviderTaskRequest request) {
// 正常提交逻辑
}
public ProviderTaskResponse submitTaskFallback(ProviderTaskRequest request) {
log.error("RunningHub服务降级,任务提交失败");
return ProviderTaskResponse.builder()
.status(TaskSubmitStatus.FAILED)
.errorMessage("RunningHub服务暂时不可用,请稍后重试")
.build();
}
}
🧪 六、压力测试方案
6.1 测试工具
JMeter测试脚本:
<HTTPSamplerProxy>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">8081</stringProp>
<stringProp name="HTTPSampler.path">/user/ai/tasks/submit</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<ThreadGroup>
<intProp name="ThreadGroup.num_threads">100</intProp>
<intProp name="ThreadGroup.ramp_time">10</intProp>
<intProp name="LoopController.loops">1</intProp>
</ThreadGroup>
</HTTPSamplerProxy>
6.2 测试场景
场景1:渐进式压力测试
# 阶段1:10并发,持续1分钟
# 阶段2:50并发,持续5分钟
# 阶段3:100并发,持续10分钟
# 阶段4:200并发,持续10分钟
观察指标:
- API响应时间(P50、P95、P99)
- 轮询延迟
- 数据库连接池使用率
- CPU/内存使用率
- RunningHub API错误率
场景2:峰值冲击测试
# 突然提交500个任务,观察系统恢复能力
ab -n 500 -c 100 -T 'application/json' \
-H "Authorization: Bearer TEST_TOKEN" \
-p task_payload.json \
http://localhost:8081/user/ai/tasks/submit
📊 七、监控与告警
7.1 关键指标
-- 实时并发任务数
SELECT COUNT(*) as running_tasks
FROM ai_task
WHERE provider_type = 'runninghub'
AND status = 'processing';
-- 平均处理时间
SELECT AVG(TIMESTAMPDIFF(SECOND, start_time, complete_time)) as avg_seconds
FROM ai_task
WHERE provider_type = 'runninghub'
AND status = 'completed'
AND complete_time > DATE_SUB(NOW(), INTERVAL 1 HOUR);
-- 失败率
SELECT
COUNT(CASE WHEN status = 'failed' THEN 1 END) * 100.0 / COUNT(*) as failure_rate
FROM ai_task
WHERE provider_type = 'runninghub'
AND create_time > DATE_SUB(NOW(), INTERVAL 1 HOUR);
7.2 告警规则
alerts:
- name: "RunningHub并发过高"
condition: running_tasks > 200
action: 发送邮件/短信通知
- name: "RunningHub失败率过高"
condition: failure_rate > 10%
action: 触发熔断,停止新任务提交
- name: "轮询延迟过高"
condition: polling_delay > 30s
action: 重启轮询调度器
💡 八、最佳实践建议
8.1 初期部署(100并发以内)
- ✅ 使用方案A配置
- ✅ 轮询间隔设置为 10秒(已调整)
- ✅ 监控RunningHub API响应时间
- ✅ 每日检查失败任务并分析原因
8.2 业务增长期(100-500并发)
- ✅ 升级到方案B配置
- ✅ 实施分批轮询优化
- ✅ 增加数据库连接池和Tomcat线程数
- ✅ 引入限流和熔断机制
8.3 大规模部署(500+并发)
- ✅ 采用方案C架构
- ✅ 独立部署轮询服务集群
- ✅ 使用Redis消息队列
- ✅ 实施全链路监控和自动告警
📝 九、RunningHub API费用估算
9.1 任务成本分析
根据 V5__add_provider_support.sql 中的积分配置:
| 模型类型 | 积分消耗 | 实际成本(假设1元=100积分) |
|---|---|---|
| 文生视频(10秒,普通) | 160 | 1.6元 |
| 文生视频(10秒,高清) | 420 | 4.2元 |
| 图生视频(10秒,普通) | 180 | 1.8元 |
| 图生视频(10秒,高清) | 480 | 4.8元 |
9.2 并发成本估算
场景:100个并发任务/小时
假设任务分布:
- 60% 文生视频(普通):60 × 1.6元 = 96元
- 20% 文生视频(高清):20 × 4.2元 = 84元
- 15% 图生视频(普通):15 × 1.8元 = 27元
- 5% 图生视频(高清):5 × 4.8元 = 24元
总计:231元/小时 或 5544元/天
建议:
- 对于高频用户,设置每日任务数量限制
- 引入会员等级,高级会员享受折扣
- 批量购买积分时提供优惠
✅ 十、总结与建议
当前配置(已优化)
polling-interval: 10000 # ✅ 已改为10秒
max-polling-times: 60 # ✅ 已调整为60次
并发能力评估
| 并发任务数 | 系统负载 | 推荐配置 | 风险等级 |
|---|---|---|---|
| 0-100 | 低 | 方案A | ✅ 安全 |
| 100-200 | 中 | 方案A | ⚠️ 注意 |
| 200-500 | 高 | 方案B | ⚠️ 风险 |
| 500+ | 极高 | 方案C | ❌ 需重构 |
下一步行动
-
短期(1周内):
- 部署当前配置(10秒轮询)
- 监控前100个任务的表现
- 收集RunningHub API响应时间数据
-
中期(1个月内):
- 进行渐进式压力测试
- 找到RunningHub API的并发阈值
- 根据实际情况调整轮询间隔
-
长期(3个月内):
- 如果并发超过200,实施方案B
- 引入Redis队列和独立轮询服务
- 建立完善的监控和告警体系
RunningHub并发分析完成! 🎯
当前配置已优化为10秒轮询,建议从小规模开始,逐步增加并发,实时监控系统表现。