# 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的并发任务数 - ❓ 账户级别的任务队列限制 **建议测试方案:** ```bash # 逐步压力测试 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 系统参数 ```yaml # 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. 轮询调度器负载 ```java @Scheduled(fixedRateString = "${ai.providers.runninghub.polling-interval:10000}") public void pollRunningHubTasks() { // 查询所有processing状态的RunningHub任务 List 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: 第三次调度触发 ``` **解决方案:** 1. 使用 `@Scheduled(fixedDelay = 10000)` 替代 `fixedRate` 2. 增加线程池,并发查询状态 ### 3.2 数据库连接池耗尽 **当前连接池配置(默认):** HikariCP 默认10个连接 **风险:** ``` 200个并发任务 × 每个任务3次数据库操作(查询+更新+日志) = 600次DB操作/10秒 ``` **解决方案:** ```yaml 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个线程 **解决方案:** ```yaml server: tomcat: threads: max: 500 # 增加最大线程数 min-spare: 50 ``` --- ## 🚀 四、并发优化方案 ### 方案A:保守配置(推荐用于初期) **目标:** 稳定性优先,支持 **100个并发任务** ```yaml 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个并发任务** ```yaml 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 ``` **优化代码(分批轮询):** ```java @Scheduled(fixedDelay = 15000) public void pollRunningHubTasks() { List allTasks = aiTaskMapper.findProcessingTasksByProvider("runninghub"); // 分批处理,每批50个 int batchSize = 50; for (int i = 0; i < allTasks.size(); i += batchSize) { List 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+并发任务** **架构升级:** 1. **Redis消息队列** 替代数据库轮询 2. **独立轮询服务** 部署多个实例 3. **负载均衡** 分散WebSocket连接 4. **限流熔断** 保护RunningHub API ```mermaid 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 客户端限流(防止自身被封) ```java @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故障时) ```java @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测试脚本:** ```xml localhost 8081 /user/ai/tasks/submit POST true 100 10 1 ``` ### 6.2 测试场景 #### 场景1:渐进式压力测试 ```bash # 阶段1:10并发,持续1分钟 # 阶段2:50并发,持续5分钟 # 阶段3:100并发,持续10分钟 # 阶段4:200并发,持续10分钟 ``` **观察指标:** - API响应时间(P50、P95、P99) - 轮询延迟 - 数据库连接池使用率 - CPU/内存使用率 - RunningHub API错误率 #### 场景2:峰值冲击测试 ```bash # 突然提交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 关键指标 ```sql -- 实时并发任务数 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 告警规则 ```yaml alerts: - name: "RunningHub并发过高" condition: running_tasks > 200 action: 发送邮件/短信通知 - name: "RunningHub失败率过高" condition: failure_rate > 10% action: 触发熔断,停止新任务提交 - name: "轮询延迟过高" condition: polling_delay > 30s action: 重启轮询调度器 ``` --- ## 💡 八、最佳实践建议 ### 8.1 初期部署(100并发以内) 1. ✅ 使用**方案A配置** 2. ✅ 轮询间隔设置为 **10秒**(已调整) 3. ✅ 监控RunningHub API响应时间 4. ✅ 每日检查失败任务并分析原因 ### 8.2 业务增长期(100-500并发) 1. ✅ 升级到**方案B配置** 2. ✅ 实施分批轮询优化 3. ✅ 增加数据库连接池和Tomcat线程数 4. ✅ 引入限流和熔断机制 ### 8.3 大规模部署(500+并发) 1. ✅ 采用**方案C架构** 2. ✅ 独立部署轮询服务集群 3. ✅ 使用Redis消息队列 4. ✅ 实施全链路监控和自动告警 --- ## 📝 九、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元/天** **建议:** - 对于高频用户,设置每日任务数量限制 - 引入会员等级,高级会员享受折扣 - 批量购买积分时提供优惠 --- ## ✅ 十、总结与建议 ### 当前配置(已优化) ```yaml polling-interval: 10000 # ✅ 已改为10秒 max-polling-times: 60 # ✅ 已调整为60次 ``` ### 并发能力评估 | 并发任务数 | 系统负载 | 推荐配置 | 风险等级 | |-----------|---------|---------|---------| | 0-100 | 低 | 方案A | ✅ 安全 | | 100-200 | 中 | 方案A | ⚠️ 注意 | | 200-500 | 高 | 方案B | ⚠️ 风险 | | 500+ | 极高 | 方案C | ❌ 需重构 | ### 下一步行动 1. **短期(1周内):** - [ ] 部署当前配置(10秒轮询) - [ ] 监控前100个任务的表现 - [ ] 收集RunningHub API响应时间数据 2. **中期(1个月内):** - [ ] 进行渐进式压力测试 - [ ] 找到RunningHub API的并发阈值 - [ ] 根据实际情况调整轮询间隔 3. **长期(3个月内):** - [ ] 如果并发超过200,实施方案B - [ ] 引入Redis队列和独立轮询服务 - [ ] 建立完善的监控和告警体系 --- **RunningHub并发分析完成!** 🎯 当前配置已优化为10秒轮询,建议从小规模开始,逐步增加并发,实时监控系统表现。