From 91eb61a1a855a30821a6622bd3d313228baf5eea Mon Sep 17 00:00:00 2001 From: bigcode Date: Mon, 2 Nov 2026 15:37:45 +0800 Subject: [PATCH] =?UTF-8?q?stress:=20=E6=8E=A7=E5=88=B6=E5=99=A8=20v5.3=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E6=95=85=E9=9A=9C=E4=BA=8C=E5=88=86(?= =?UTF-8?q?=E6=88=91=E6=96=B9=20=E6=B1=A0=E7=A9=BA/httpErr/netErr=20?= =?UTF-8?q?=E2=86=92=20=E7=A1=AC=E8=A7=84=E5=88=99=E5=9C=B0=E6=9D=BF8;Goog?= =?UTF-8?q?le=20=E4=BE=A7=20captcha/=E9=97=A8=E5=A3=B3/=E7=A9=BA=20?= =?UTF-8?q?=E2=86=92=20=E5=8F=AA=E7=A0=8D=E7=81=BE=E9=9A=BE=E6=B3=A2?= =?UTF-8?q?=E6=AC=A1=E2=89=A524/10min=20=E5=9C=B0=E6=9D=BF40);=E9=80=80?= =?UTF-8?q?=E6=AE=B5/=E7=88=AC=E5=9D=A1=E6=8C=89=E8=81=94=E5=90=88?= =?UTF-8?q?=E5=99=AA=E5=A3=B0=E9=A2=84=E7=AE=97(=E2=89=A46/8,=E7=9F=AD?= =?UTF-8?q?=E7=AA=97=E2=89=A596%),=E4=BF=AE=20dp7c=20=E6=B3=A2=E6=AC=A1?= =?UTF-8?q?=E9=80=80=E6=BD=AE=E5=90=8E=E9=97=A8=E5=A3=B3+=E6=B6=93?= =?UTF-8?q?=E6=B5=81=E8=81=94=E5=90=88=E5=99=AA=E5=A3=B0=E6=8A=8A=208/min?= =?UTF-8?q?=20=E9=92=89=E6=AD=BB=E7=9A=84=E6=9C=80=E5=90=8E=E4=B8=80?= =?UTF-8?q?=E5=B1=82=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stress/serp-dualpath-optimize.ts | 81 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/stress/serp-dualpath-optimize.ts b/stress/serp-dualpath-optimize.ts index 68454d2..c54c523 100644 --- a/stress/serp-dualpath-optimize.ts +++ b/stress/serp-dualpath-optimize.ts @@ -6,19 +6,17 @@ * 双路径原形态(runtime=auto,无 sticky,全池公平负载选号): * GET /api/serp/json/search?q=...&num=10 * 令牌内走 go-fetch(全局限流 fetchPerSec),限流外并发走温池浏览器 —— 组合即生产形态。 - * AIMD 控制器 v5.2(dp6 全天 + dp7 前段实测教训驱动;v4 基础上的关键演进): - * 硬约束(成功率即约束本身):入段 = 浅破线(<99% 且失败 ≥8 且窗口 ≥200 样本)或 - * 深破线(<96% 且失败 ≥4)×0.7/<96% ×0.5;段内续砍需短窗 <96% 且(非验证码失败 - * ≥3 或验证码 ≥5/10min)且全程增量新失败 ≥2;硬砍地板 HARD_FLOOR=8; - * 涓流豁免(v5.1,dp7 实测:99% 线下比率陷阱锁死 degraded 砍到 3/min): - * 30min 窗零非验证码失败且短窗验证码 ≤2 = 涓流 —— 不入段、可退段(短窗 ≥98.5%)、 - * 验证码涓流的唯一解药是爬坡摊薄(稀释论),砍速让分母变小占比更高; - * 软信号按事件段(episode)迟滞 + 绝对数护栏:验证码 10min 窗 ≥8 个(v5.1:5→8,只砍 - * 波次规模)且占比>0.5% ×0.7(重波次 ≥12 且>2% ×0.5);门壳 ≥3 且占比>15% ×0.85; - * 池空>5 ×0.85;软砍下限 SOFT_FLOOR=40(v5.1:25→40,保稀释安全线); - * 干净爬坡:水位 = 30min 窗 ≥99%(v5.2:99.5%→99%,涓流时段高门槛不可达)且短窗 ≥99% - * 时记录;水位下方 ×1.3/拍快速回收,水位之上 ×1.08/5 拍;爬坡备选「验证码 ≤2 且 - * 短窗 ≥98%」与涓流口径一致(dp6 低速恢复锁死 + dp7 涓流滞留修复)。 + * AIMD 控制器 v5.3(dp6 全天 + dp7/dp7b/dp7c 前段实测教训驱动;v4 基础上的关键演进): + * 故障二分(v5.3 核心):我方故障 = 池空/httpErr/netErr → 硬规则(入段/续砍/地板 8); + * Google 侧 = captcha/门壳/空结果 → 只观察,仅灾难波次软砍(captcha ≥24 个/10min + * ≈ dp6 最差小时水平;门壳 ≥20 个/10min),砍速地板 40; + * 硬约束:入段 = 浅破线(<99% 且失败 ≥8 且窗口 ≥200 样本)或深破线(<96% 且失败 ≥4) + * ×0.7/<96% ×0.5;续砍需短窗 <96% 且(我方故障 ≥3 或 captcha ≥5/10min)且全程 + * 增量新失败 ≥2; + * 噪声退段/爬坡(稀释论,dp7 三轮实测:低速小分母下高窗口线被 Google 侧噪声压住是 + * 数学必然,砍速是毒药、爬坡摊薄是解药):零我方故障且联合噪声(captcha+门壳)≤6/8 + * → 可退段(短窗 ≥96%)/可爬坡(短窗 ≥96%),×1.3/拍 向水位回收,水位之上 ×1.08/5 拍; + * 软砍下限 SOFT_FLOOR=40(99% 目标下 25/min 涓流占比已贴线),硬砍下限 HARD_FLOOR=8。 * 干净爬坡:不在退化段 且 短窗干净 且 无池空 且(验证码 0 个或样本 ≥300)→ 向「干净 * 水位」(30min 窗 ≥99.5% 时的最高速率)以 ×1.3/拍快速回收,水位之上每 5 拍 ×1.08。 * v5 修 dp6 实测「低速恢复锁死」:短窗成功率 ≥99.5% 在低速涓流下永不可达 @@ -177,48 +175,49 @@ function controlTick(): Record | null { const from = rate; let to = from; let reason = "hold"; - // 硬约束(v5.1,dp7 前 1.5h 实测教训:99% 线下比率陷阱重现在入段/退段/续砍三级 —— - // 低速涓流永远压住 99% 窗口线,degraded 锁死 → 砍到 3/min 浏览器饿死;稀释论: - // 验证码涓流的唯一解药是爬坡摊薄,砍速让分母变小占比更高,是毒药): - // 涓流豁免 = 30min 窗零非验证码失败 且 短窗验证码 ≤2 个(涓流规模,非波次); - // ① 退段:窗口 ≥99%,或涓流豁免且短窗 ≥98.5%;② 入段:涓流不入段; - // ③ 段内续砍需真证据:非验证码失败 ≥1(我方故障)或验证码 ≥5/10min(波次规模) + // 故障二分(v5.3,dp7c 1.8h 实测:波次退潮后门壳 2~3 个/窗 + captcha 3~5 个联合噪声 + // 把窗口钉在 96.6~97.9%,nonCapFails===0 退段与 successS≥0.98 爬坡双双卡死在 8/min; + // 门壳/空结果与 captcha 同为 Google 侧供给,稀释论同样适用 —— 我方故障只剩 + // 池空/httpErr/netErr): + // infraFails = 我方故障;googleNoise = captcha+门壳(联合噪声预算) + // ① 退段:窗口 ≥99%,或零我方故障且联合噪声 ≤6 且短窗 ≥96%(低速小分母下窗口 + // 成功率被噪声压住是数学必然,退段只看「波次是否结束」不看窗口线); + // ② 入段:浅破线(<99% 且失败 ≥8 且窗口 ≥200 样本,v5.2 防小样本级联)或深破线 + // (<96% 且失败 ≥4);Google 侧噪声不触发入段(灾难波次由软规则管); + // ③ 续砍:我方故障 ≥3 或 captcha ≥5/10min;砍速地板按故障归属:我方 8 / Google 侧 40 const fails = tot - wH.ok; const allFails = totals.sent - totals.ok; const successS = wS.sent > 0 ? wS.ok / wS.sent : 1; - const nonCapFails = wH.gate + wH.empty + wH.poolEmpty + wH.httpErr + wH.netErr; - const trickle = nonCapFails === 0 && wS.captcha <= 2; - if (success >= 0.99 || (trickle && successS >= 0.985)) degraded = false; - // 入段(v5.2 加量下限,dp7 实测教训:冷启动波次在 ~90 样本窗口上 4 个失败即被 ×0.5, - // 小样本噪音驱动级联):浅破线(99%~96%)需窗口 ≥200 样本且 ≥8 失败;深破线(<96%) - // 仍快速响应(≥4 失败即可,真崩溃不等样本攒够) + const infraFails = wH.poolEmpty + wH.httpErr + wH.netErr; + const googleNoiseS = wS.captcha + wS.gate; + const trickle = infraFails === 0 && googleNoiseS <= 6; + if (success >= 0.99 || (trickle && successS >= 0.96)) degraded = false; const entry = !degraded && !trickle && ((success < 0.99 && fails >= 8 && tot >= 200) || (success < 0.96 && fails >= 4)); - // 段内续砍(v5.2 提证据门槛):非验证码失败 ≥3(1~2 个门壳是波次伴生噪音,dp7 实测 - // gate=1 即解锁续砍)或验证码 ≥5/10min(波次规模);短窗样本 ≥30 - const ongoing = degraded && wS.sent >= 30 && successS < 0.96 && (nonCapFails >= 3 || wS.captcha >= 5) && allFails - failsAtLastCut >= 2; + const ongoing = degraded && wS.sent >= 30 && successS < 0.96 && (infraFails >= 3 || wS.captcha >= 5) && allFails - failsAtLastCut >= 2; if (entry || ongoing) { degraded = true; failsAtLastCut = allFails; to = success < 0.96 ? from * 0.5 : from * 0.7; - to = Math.max(HARD_FLOOR, to); + to = Math.max(infraFails >= 3 ? HARD_FLOOR : SOFT_FLOOR, to); reason = `success=${(success * 100).toFixed(1)}%<${success < 0.96 ? 96 : 99}%(失败 ${fails}${entry ? "" : ";短窗<96%+新失败≥2"}) ×${success < 0.96 ? 0.5 : 0.7}`; } else { - // 软信号:事件段迟滞 + 绝对数护栏(v5.1:验证码护栏 3→8 个/10min —— 只砍波次规模, - // 涓流交给稀释;低速率下 1~2 个噪音即高比率,不得触发;dp5 教训) - if (wS.captcha >= 8 && capPctS > 0.005 && !captchaWave) { + // 软信号(v5.3:只砍灾难波次 —— captcha ≥24 个/10min ≈ 144/时 = dp6 最差小时水平, + // 常规波次 45~90/时不再触发;门壳 ≥20 个/10min ≈ 3× dp6 峰值;涓流/常规波次交给 + // 稀释与爬坡;低速率小分母下的高占比是数学现象,不是信号;dp5/dp7 三轮实测) + if (wS.captcha >= 24 && capPctS > 0.005 && !captchaWave) { captchaWave = true; - const heavy = wS.captcha >= 12 && capPctS > 0.02; + const heavy = wS.captcha >= 40 && capPctS > 0.02; to = Math.max(SOFT_FLOOR, from * (heavy ? 0.5 : 0.7)); reason = `验证码 ${wS.captcha} 个占比 ${(capPctS * 100).toFixed(2)}% ${heavy ? "×0.5" : "×0.7"}`; } else if (wS.captcha === 0) captchaWave = false; - if (to === from && wS.gate >= 3 && gateRatioS > 0.15 && !gateWave) { + if (to === from && wS.gate >= 20 && gateRatioS > 0.15 && !gateWave) { gateWave = true; to = Math.max(SOFT_FLOOR, from * 0.85); reason = `门壳 ${wS.gate} 占比 ${(gateRatioS * 100).toFixed(1)}%>15% ×0.85`; } else if (gateRatioS < 0.05) gateWave = false; if (to === from && wS.poolEmpty > 5 && !poolEmptyWave) { poolEmptyWave = true; - to = Math.max(SOFT_FLOOR, from * 0.85); + to = Math.max(HARD_FLOOR, from * 0.85); reason = `池空 ${wS.poolEmpty} ×0.85`; } else if (wS.poolEmpty === 0) poolEmptyWave = false; } @@ -226,13 +225,13 @@ function controlTick(): Record | null { // 水位永远立不起来 → 深跌后只剩 ×1.08/5 拍龟速爬坡,dp7 实测):窗口 ≥99% 且短窗 ≥99% // 时的速率即为「实测可行」 if (success >= 0.99 && successS >= 0.99 && wS.sent >= 10) maxCleanRate = Math.max(maxCleanRate, from); - // 干净爬坡:退化段中不爬(30min 窗未恢复 99%);深跌后向水位快速回收 ×1.3/拍,水位之上 ×1.08/5 拍; - // 爬坡验证码条件:主条件短窗成功率 ≥99.5%,备选「验证码 ≤2 且短窗 ≥98%」(v5.1:与涓流 - // 豁免口径一致,修 dp6 实测低速恢复锁死 + dp7 实测涓流滞留 —— 爬坡摊薄后比率自然回落); - // 短窗 0 个验证码恒可爬,或样本 ≥300 时比率已无意义(绝对护栏统一交给软砍规则) + // 干净爬坡(v5.3):退化段中不爬;主条件短窗 ≥99.5%,备选「零我方故障且联合噪声 ≤8 + // 且短窗 ≥96%」(与退段口径一致 —— 低速小分母下高窗口线不可达,爬坡本身就是摊薄手段, + // ×1.3/拍 中速率每上台阶噪声占比自动减半,自校正);池空独查;样本/占比条件废除, + // 绝对护栏统一交给软砍规则 if (to === from && !degraded && wS.sent >= 10) { - const cleanS = successS >= 0.995 || (wS.captcha <= 2 && successS >= 0.98); - if (cleanS && gateRatioS < 0.02 && wS.poolEmpty === 0 && (wS.captcha === 0 || wS.sent >= 300)) { + const cleanS = successS >= 0.995 || (infraFails === 0 && googleNoiseS <= 8 && successS >= 0.96); + if (cleanS && wS.poolEmpty === 0) { rampSeq++; if (maxCleanRate > 0 && from < maxCleanRate * 0.75) { to = from * 1.3 + 0.2;