stress: 控制器 v5.4 —— Google 侧零砍速(四轮实测:灾难波次下砍速在任何速率都是毒药,宁骑不砍)+ poolEmpty 仅低速计入我方故障 + workers 12→24(页内 fetch 后天花板瓶颈)
This commit is contained in:
@@ -6,17 +6,16 @@
|
||||
* 双路径原形态(runtime=auto,无 sticky,全池公平负载选号):
|
||||
* GET /api/serp/json/search?q=...&num=10
|
||||
* 令牌内走 go-fetch(全局限流 fetchPerSec),限流外并发走温池浏览器 —— 组合即生产形态。
|
||||
* 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。
|
||||
* AIMD 控制器 v5.4(dp6 全天 + dp7/dp7b/dp7c/dp7d 四轮前段实测定稿;核心=故障二分):
|
||||
* Google 侧(captcha/门壳/空)→ 零砍速,波次骑行:四轮实测一致证明砍速在任何速率下
|
||||
* 都让占比恶化(8/min 时 148/时波次占比 10.5% 窗口 88%;117/min 4.2%;300/min 1.6%
|
||||
* 窗口 98.4%)—— 唯一出路是分母,宁骑不砍;
|
||||
* 我方故障(httpErr/netErr;poolEmpty 仅低速 <60/min 计入,高速期池空是需求伴生现象)
|
||||
* → AIMD:入段(浅破线 <99% 失败 ≥8 且窗口 ≥200 样本 / 深破线 <96% 失败 ≥4)×0.7/
|
||||
* ×0.5,续砍需短窗 <96% 且增量新失败 ≥2,地板 HARD_FLOOR=8,低速池空软砍 ×0.85;
|
||||
* 噪声预算退段/爬坡(稀释论):零我方故障且联合噪声(captcha+门壳)≤6 → 退段(短窗
|
||||
* ≥96%)/≤8 → 可爬坡(短窗 ≥96%),水位下 ×1.3/拍,之上 ×1.08/5 拍;
|
||||
* workers 默认 24(页内 fetch 1.1~2s/请求,12 worker 天花板 ~135/min 是波次稀释瓶颈)。
|
||||
* 干净爬坡:不在退化段 且 短窗干净 且 无池空 且(验证码 0 个或样本 ≥300)→ 向「干净
|
||||
* 水位」(30min 窗 ≥99.5% 时的最高速率)以 ×1.3/拍快速回收,水位之上每 5 拍 ×1.08。
|
||||
* v5 修 dp6 实测「低速恢复锁死」:短窗成功率 ≥99.5% 在低速涓流下永不可达
|
||||
@@ -45,8 +44,9 @@ const RATE0 = Number(argOf("--rate0", "15"));
|
||||
/** # 成员变量 速率下限/上限(req/min) **/
|
||||
const RATE_MIN = Number(argOf("--min", "3"));
|
||||
const RATE_MAX = Number(argOf("--max", "400"));
|
||||
/** # 成员变量 并发 worker 数 **/
|
||||
const WORKERS = Number(argOf("--workers", "12"));
|
||||
/** # 成员变量 并发 worker 数(v5.4:默认 12→24 —— 页内 fetch 后浏览器单请求 1.1~2s,
|
||||
* 12 worker 的吞吐天花板(~135/min 实测)成了灾难波次稀释(需 ≥250/min)的瓶颈) **/
|
||||
const WORKERS = Number(argOf("--workers", "24"));
|
||||
/** # 成员变量 控制器窗口(分钟)与加速步间隔(分钟) **/
|
||||
const WINDOW_MIN = 30;
|
||||
const RAMP_EVERY_MIN = 5;
|
||||
@@ -175,49 +175,38 @@ function controlTick(): Record<string, unknown> | null {
|
||||
const from = rate;
|
||||
let to = from;
|
||||
let reason = "hold";
|
||||
// 故障二分(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
|
||||
// 故障二分(v5.4,dp7d 实测定稿:148/时灾难波次下,poolEmpty 3~4 个(高需求伴生)误判
|
||||
// 我方故障解锁硬地板 8 → 砸到 8/min 窗口 88%(captcha 占比 10.5%);而同一波次在
|
||||
// 117/min 为 95.8%、300/min 为 98.4% —— Google 侧事件引发砍速在任何速率下都是毒药):
|
||||
// infraFails = 纯我方故障(httpErr/netErr;poolEmpty 仅低速 <60/min 时计入 —— 高速期
|
||||
// 池空是需求压力的伴生现象,温池自补,砍速只会加重浏览器饿死);
|
||||
// Google 侧(captcha/门壳/空)→ 零砍速,波次骑行:当前速率下占比已是最优解,
|
||||
// 砍速减分母提占比、提速摊薄降占比,唯一出路在分母;
|
||||
// ① 退段:窗口 ≥99%,或零我方故障且联合噪声 ≤6 且短窗 ≥96%;
|
||||
// ② 入段/续砍:仅我方故障 ≥3 且(浅破线 <99% 失败 ≥8 窗口 ≥200 样本 / 深破线 <96%
|
||||
// 失败 ≥4 / 短窗 <96% 增量新失败 ≥2),地板 8;
|
||||
// ③ 爬坡:零我方故障且联合噪声 ≤8 且短窗 ≥96%(水位下 ×1.3/拍,之上 ×1.08/5 拍)
|
||||
const fails = tot - wH.ok;
|
||||
const allFails = totals.sent - totals.ok;
|
||||
const successS = wS.sent > 0 ? wS.ok / wS.sent : 1;
|
||||
const infraFails = wH.poolEmpty + wH.httpErr + wH.netErr;
|
||||
const infraFails = wH.httpErr + wH.netErr + (from < 60 ? wH.poolEmpty : 0);
|
||||
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));
|
||||
const ongoing = degraded && wS.sent >= 30 && successS < 0.96 && (infraFails >= 3 || wS.captcha >= 5) && allFails - failsAtLastCut >= 2;
|
||||
const entry = !degraded && !trickle && infraFails >= 3 && ((success < 0.99 && fails >= 8 && tot >= 200) || (success < 0.96 && fails >= 4));
|
||||
const ongoing = degraded && wS.sent >= 30 && successS < 0.96 && infraFails >= 3 && allFails - failsAtLastCut >= 2;
|
||||
if (entry || ongoing) {
|
||||
degraded = true;
|
||||
failsAtLastCut = allFails;
|
||||
to = success < 0.96 ? from * 0.5 : from * 0.7;
|
||||
to = Math.max(infraFails >= 3 ? HARD_FLOOR : SOFT_FLOOR, to);
|
||||
to = Math.max(HARD_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.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 >= 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 >= 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) {
|
||||
// 软信号(v5.4:仅剩池空,且仅低速期 —— 高速期池空是需求伴生现象,温池自补,
|
||||
// 砍速只会加重浏览器饿死;captcha/门壳软砍废除,灾难波次骑行,dp7 四轮实测)
|
||||
if (from < 100 && wS.poolEmpty > 5 && !poolEmptyWave) {
|
||||
poolEmptyWave = true;
|
||||
to = Math.max(HARD_FLOOR, from * 0.85);
|
||||
to = Math.max(SOFT_FLOOR, from * 0.85);
|
||||
reason = `池空 ${wS.poolEmpty} ×0.85`;
|
||||
} else if (wS.poolEmpty === 0) poolEmptyWave = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user