13 KiB
13 KiB
性能分析 - 并发数超过20导致WSS连接失败 v3.12.8
版本: v3.12.8
日期: 2025-10-08
类型: 性能分析 / 使用建议
问题描述
用户反馈:
"我发现并发的数量超过20个,就很容易导致WSS链接失败,这是什么原因导致的"
现象:
- 并发数设置为20以下:稳定运行 ✅
- 并发数设置为20-30:偶尔连接失败 ⚠️
- 并发数设置为30+:频繁连接失败 ❌
根本原因分析
1. 浏览器WebSocket连接数限制 ⭐ 主要原因
浏览器限制:
- Chrome/Edge: 每个域名最多约 255-256 个WebSocket连接(理论值)
- 实际安全值: 每个域名建议 10-20 个并发连接
- Firefox: 约 200 个连接
- Safari: 约 100 个连接
为什么实际值远小于理论值?
理论最大值: 256个
实际推荐值: 10-20个
原因:
1. 浏览器资源限制(内存、CPU)
2. 网络带宽限制
3. 操作系统的Socket限制
4. 浏览器的性能保护机制
2. 游戏服务器连接限制
服务器端可能的限制:
1. 同一IP连接数限制
- 防止DDoS攻击
- 限制单个用户的连接数
- 通常限制:10-50个/IP
2. 连接速率限制
- 限制连接建立速度
- 防止批量自动化
- 例如:1秒内最多建立5个连接
3. 资源保护
- 服务器总连接数限制
- 单个用户资源配额
- 防止服务器过载
3. 连接建立速度过快
当前的连接间隔:
const delayMs = connectionIndex * 500 // 每个连接间隔500ms
并发20个时的时间分布:
连接1: 0秒 ← 立即开始
连接2: 0.5秒
连接3: 1.0秒
连接4: 1.5秒
...
连接10: 4.5秒
...
连接20: 9.5秒 ← 最后一个连接在9.5秒后开始
问题:
- 虽然有间隔,但10秒内建立20个连接
- 可能触发服务器的反批量检测
- 服务器可能认为这是自动化攻击
4. 内存和资源占用
单个WebSocket连接的资源消耗:
内存占用: 约 5-10MB / 连接
网络带宽: 约 100KB-1MB / 连接(活跃时)
CPU占用: 约 1-2% / 连接(活跃时)
20个并发连接:
内存: 100-200MB
带宽: 2-20MB
CPU: 20-40%
浏览器性能影响:
并发10个: 流畅 ✅
并发20个: 可接受 ⚠️
并发50个: 卡顿明显 ❌
并发100个: 浏览器可能崩溃 💥
5. 网络质量影响
网络因素:
1. 家庭宽带上行带宽限制
- 下载速度: 100Mbps
- 上传速度: 10-20Mbps ← 瓶颈
- 20个连接可能超过上行带宽
2. 路由器NAT表限制
- 家用路由器通常支持 1000-5000 个并发连接
- 但实际稳定值更低
- 过多连接可能导致路由器不稳定
3. ISP限制
- 运营商可能限制同时连接数
- 防止P2P等高并发应用
技术限制详解
浏览器WebSocket实现
// Chrome的WebSocket实现(简化)
class WebSocket {
constructor(url) {
// 1. 检查连接数
if (activeConnections >= MAX_CONNECTIONS_PER_DOMAIN) {
throw new Error('Too many connections')
}
// 2. 建立TCP连接
// 3. WebSocket握手
// 4. 维护心跳
}
}
// 限制机制
const MAX_CONNECTIONS_PER_DOMAIN = 256 // 理论值
const RECOMMENDED_LIMIT = 10-20 // 实际安全值
操作系统限制
Windows:
默认最大Socket数: 65535(理论)
实际推荐值: 5000-10000
单个进程限制: 2000-5000
macOS/Linux:
默认限制: 1024(ulimit -n)
可调整为: 65535
但实际使用建议: 5000以下
当前实现分析
连接建立流程
// src/stores/batchTaskStore.js
const executeBatchWithConcurrency = async (tokenIds, tasks) => {
const queue = [...tokenIds]
const executing = []
let connectionIndex = 0
while (queue.length > 0 || executing.length > 0) {
// 填充执行队列(最多maxConcurrency个)
while (executing.length < maxConcurrency.value && queue.length > 0) {
const tokenId = queue.shift()
// 错开连接时间
const delayMs = connectionIndex * 500 // 500ms间隔
connectionIndex++
const promise = (async () => {
if (delayMs > 0) {
await new Promise(resolve => setTimeout(resolve, delayMs))
}
// 建立连接并执行任务
return executeTokenTasks(tokenId, tasks)
})()
executing.push(promise)
}
// 等待至少一个完成
if (executing.length > 0) {
await Promise.race(executing)
}
}
}
问题分析
-
累加的延迟时间:
第1个: 0ms 第2个: 500ms 第3个: 1000ms ... 第20个: 9500ms 问题:前面的连接可能已经完成, 但新连接仍在累加延迟 -
并发控制不精确:
虽然限制了executing.length < maxConcurrency 但实际活跃的WebSocket连接数可能更多 因为连接建立和任务执行是异步的 -
没有连接失败重试限制:
连接失败会重试,但可能加剧连接压力
解决方案和建议
方案1:降低推荐并发数 ⭐ 推荐
建议的安全值:
| 网络环境 | 推荐并发数 | 说明 |
|---|---|---|
| 家庭宽带 | 10-15 | 最稳定,适合大多数用户 |
| 高速宽带 | 15-20 | 网络条件好可以尝试 |
| 企业网络 | 20-30 | 专线网络,上行带宽足够 |
| 服务器环境 | 30-50 | 数据中心,网络质量极好 |
实施:
// src/stores/batchTaskStore.js
const maxConcurrency = ref(
parseInt(localStorage.getItem('maxConcurrency') || '10') // 默认改为10
)
// 添加警告提示
const setMaxConcurrency = (count) => {
if (count > 20) {
console.warn(`⚠️ 警告:并发数 ${count} 超过推荐值(20)`)
console.warn(`⚠️ 可能导致WebSocket连接失败、浏览器卡顿等问题`)
console.warn(`⚠️ 建议设置为10-20之间`)
}
maxConcurrency.value = count
localStorage.setItem('maxConcurrency', count.toString())
}
方案2:优化连接间隔策略
当前策略问题:
const delayMs = connectionIndex * 500 // 累加延迟
// 第20个要等9.5秒,但前面的可能已经完成了
优化策略:
// 固定间隔,不累加
const CONNECTION_INTERVAL = 1000 // 每个连接间隔1秒
let lastConnectionTime = 0
while (executing.length < maxConcurrency.value && queue.length > 0) {
const tokenId = queue.shift()
// 计算需要等待的时间
const now = Date.now()
const timeSinceLastConnection = now - lastConnectionTime
const waitTime = Math.max(0, CONNECTION_INTERVAL - timeSinceLastConnection)
if (waitTime > 0) {
await new Promise(resolve => setTimeout(resolve, waitTime))
}
lastConnectionTime = Date.now()
// 建立连接...
}
方案3:添加连接池管理
// 连接池配置
const CONNECTION_POOL_CONFIG = {
maxConnections: 20, // 最大连接数
maxActiveConnections: 10, // 最大活跃连接数
connectionTimeout: 30000, // 连接超时30秒
idleTimeout: 60000, // 空闲超时60秒
connectionInterval: 1000 // 连接间隔1秒
}
// 连接池管理
class WebSocketPool {
constructor(config) {
this.config = config
this.activeConnections = new Map()
this.pendingQueue = []
}
async acquire(tokenId) {
// 等待直到可以建立新连接
while (this.activeConnections.size >= this.config.maxActiveConnections) {
await new Promise(resolve => setTimeout(resolve, 100))
}
// 建立连接
const connection = await this.createConnection(tokenId)
this.activeConnections.set(tokenId, connection)
return connection
}
release(tokenId) {
this.activeConnections.delete(tokenId)
}
}
方案4:分批执行
// 将Token分批执行,每批不超过10个
const BATCH_SIZE = 10
const BATCH_INTERVAL = 5000 // 批次间隔5秒
for (let i = 0; i < tokenIds.length; i += BATCH_SIZE) {
const batch = tokenIds.slice(i, i + BATCH_SIZE)
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
console.log(`🔄 执行第 ${Math.floor(i / BATCH_SIZE) + 1} 批`)
console.log(`📊 本批数量: ${batch.length}`)
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`)
// 执行这一批
await executeBatch(batch, tasks)
// 批次间隔
if (i + BATCH_SIZE < tokenIds.length) {
console.log(`⏸️ 等待${BATCH_INTERVAL/1000}秒后执行下一批...`)
await new Promise(resolve => setTimeout(resolve, BATCH_INTERVAL))
}
}
用户使用建议
1. 根据Token数量选择并发数
Token总数 推荐并发数 预计时间
--------------------------------------
1-10个 5-7 2-3分钟
10-50个 7-10 5-8分钟
50-100个 10-15 8-12分钟
100-500个 10-15 20-60分钟
500-1000个 10-15 60-120分钟
2. 网络环境优化
家庭网络:
1. 使用有线连接(比WiFi更稳定)
2. 关闭其他占用带宽的应用
3. 避免高峰时段(晚上8-10点)
4. 重启路由器清理NAT表
5. 并发数设置为10-12
移动热点:
1. 4G/5G热点通常上行带宽较低
2. 建议并发数: 5-8
3. 避免流量不足时执行
4. 注意流量消耗
企业/学校网络:
1. 可能有防火墙限制
2. 可能禁止WebSocket
3. 建议先小规模测试
4. 并发数: 10-15
3. 分时段执行
// 方案A:深夜执行(服务器压力小)
定时时间: 凌晨2:00-5:00
并发数: 可以设置高一些 (15-20)
稳定性: ⭐⭐⭐⭐⭐
// 方案B:白天执行
定时时间: 上午10:00-下午4:00
并发数: 中等 (10-12)
稳定性: ⭐⭐⭐⭐
// 方案C:高峰时段(不推荐)
定时时间: 晚上8:00-10:00
并发数: 低 (5-8)
稳定性: ⭐⭐
4. 监控和调整
观察指标:
1. WebSocket连接成功率
- >95%: 并发数合适 ✅
- 90-95%: 可以接受 ⚠️
- <90%: 降低并发数 ❌
2. 任务执行失败率
- <5%: 正常 ✅
- 5-10%: 注意观察 ⚠️
- >10%: 需要优化 ❌
3. 浏览器响应速度
- 流畅: 合适 ✅
- 偶尔卡顿: 可接受 ⚠️
- 频繁卡顿: 降低并发 ❌
调整策略:
步骤1: 从10开始测试
步骤2: 观察连接成功率和失败率
步骤3: 如果稳定,可以逐步增加到12、15
步骤4: 如果出现问题,立即降低
步骤5: 找到最佳值后固定使用
错误排查
常见错误和解决方法
错误1:连接超时
错误信息: WebSocket connection timeout
原因: 服务器响应慢或网络不稳定
解决:
1. 降低并发数到10
2. 增加连接间隔到1000ms
3. 检查网络连接
错误2:连接被拒绝
错误信息: WebSocket connection refused
原因: 服务器限制连接数或IP被封
解决:
1. 立即停止批量任务
2. 等待5-10分钟
3. 降低并发数到5-8
4. 增加连接间隔到2000ms
错误3:浏览器卡死
现象: 浏览器无响应,CPU 100%
原因: 并发数过高,资源耗尽
解决:
1. 强制刷新页面 (Ctrl+F5)
2. 清除浏览器缓存
3. 下次使用时降低并发数到5-10
错误4:部分Token连接失败
现象: 100个Token中20-30个连接失败
原因: 超过服务器或浏览器限制
解决:
1. 降低并发数
2. 使用"重试失败"功能
3. 分批执行
最佳实践总结
稳定运行配置
// 推荐配置
{
maxConcurrency: 10, // 并发数
connectionInterval: 1000, // 连接间隔1秒
requestTimeout: 5000, // 请求超时5秒
maxRetries: 3, // 最大重试3次
retryDelay: 3000 // 重试延迟3秒
}
性能vs稳定性权衡
高性能模式(不推荐):
- 并发数: 30-50
- 连接间隔: 500ms
- 风险: 高
- 稳定性: ⭐⭐
- 速度: ⭐⭐⭐⭐⭐
平衡模式(推荐):
- 并发数: 10-15
- 连接间隔: 1000ms
- 风险: 低
- 稳定性: ⭐⭐⭐⭐
- 速度: ⭐⭐⭐⭐
稳定模式:
- 并发数: 5-8
- 连接间隔: 2000ms
- 风险: 极低
- 稳定性: ⭐⭐⭐⭐⭐
- 速度: ⭐⭐⭐
技术限制对照表
| 限制类型 | 限制值 | 影响 | 建议 |
|---|---|---|---|
| 浏览器连接数 | 10-20/域名 | 超过会连接失败 | 并发≤15 |
| 服务器限制 | 10-50/IP | 超过可能被封 | 并发≤20 |
| 上行带宽 | 10-20Mbps | 影响连接速度 | 并发≤15 |
| 浏览器内存 | 100-200MB | 影响性能 | 并发≤20 |
| 路由器NAT | 1000-5000 | 连接不稳定 | 并发≤15 |
总结
问题根源:
- 🔍 浏览器WebSocket连接数限制(10-20个)
- 🔍 游戏服务器连接数限制
- 🔍 网络带宽限制(特别是上行)
- 🔍 系统资源限制(内存、CPU)
推荐配置:
- ✅ 并发数: 10-15(最佳平衡点)
- ✅ 连接间隔: 1000ms
- ✅ 网络环境: 有线连接优先
- ✅ 执行时段: 避开高峰期
关键建议:
- 💡 不要盲目追求高并发,稳定性更重要
- 💡 从10开始测试,逐步找到最佳值
- 💡 关注连接成功率,<95%就降低并发
- 💡 使用进度保存,连接失败可以继续
- 💡 分时段执行,深夜/凌晨最稳定
状态: ✅ 已分析
版本: v3.12.8
推荐并发数: 10-15