stress: 控制器 v5.3 —— 故障二分(我方 池空/httpErr/netErr → 硬规则地板8;Google 侧 captcha/门壳/空 → 只砍灾难波次≥24/10min 地板40);退段/爬坡按联合噪声预算(≤6/8,短窗≥96%),修 dp7c 波次退潮后门壳+涓流联合噪声把 8/min 钉死的最后一层锁
This commit is contained in:
@@ -6,19 +6,17 @@
|
|||||||
* 双路径原形态(runtime=auto,无 sticky,全池公平负载选号):
|
* 双路径原形态(runtime=auto,无 sticky,全池公平负载选号):
|
||||||
* GET /api/serp/json/search?q=...&num=10
|
* GET /api/serp/json/search?q=...&num=10
|
||||||
* 令牌内走 go-fetch(全局限流 fetchPerSec),限流外并发走温池浏览器 —— 组合即生产形态。
|
* 令牌内走 go-fetch(全局限流 fetchPerSec),限流外并发走温池浏览器 —— 组合即生产形态。
|
||||||
* AIMD 控制器 v5.2(dp6 全天 + dp7 前段实测教训驱动;v4 基础上的关键演进):
|
* AIMD 控制器 v5.3(dp6 全天 + dp7/dp7b/dp7c 前段实测教训驱动;v4 基础上的关键演进):
|
||||||
* 硬约束(成功率即约束本身):入段 = 浅破线(<99% 且失败 ≥8 且窗口 ≥200 样本)或
|
* 故障二分(v5.3 核心):我方故障 = 池空/httpErr/netErr → 硬规则(入段/续砍/地板 8);
|
||||||
* 深破线(<96% 且失败 ≥4)×0.7/<96% ×0.5;段内续砍需短窗 <96% 且(非验证码失败
|
* Google 侧 = captcha/门壳/空结果 → 只观察,仅灾难波次软砍(captcha ≥24 个/10min
|
||||||
* ≥3 或验证码 ≥5/10min)且全程增量新失败 ≥2;硬砍地板 HARD_FLOOR=8;
|
* ≈ dp6 最差小时水平;门壳 ≥20 个/10min),砍速地板 40;
|
||||||
* 涓流豁免(v5.1,dp7 实测:99% 线下比率陷阱锁死 degraded 砍到 3/min):
|
* 硬约束:入段 = 浅破线(<99% 且失败 ≥8 且窗口 ≥200 样本)或深破线(<96% 且失败 ≥4)
|
||||||
* 30min 窗零非验证码失败且短窗验证码 ≤2 = 涓流 —— 不入段、可退段(短窗 ≥98.5%)、
|
* ×0.7/<96% ×0.5;续砍需短窗 <96% 且(我方故障 ≥3 或 captcha ≥5/10min)且全程
|
||||||
* 验证码涓流的唯一解药是爬坡摊薄(稀释论),砍速让分母变小占比更高;
|
* 增量新失败 ≥2;
|
||||||
* 软信号按事件段(episode)迟滞 + 绝对数护栏:验证码 10min 窗 ≥8 个(v5.1:5→8,只砍
|
* 噪声退段/爬坡(稀释论,dp7 三轮实测:低速小分母下高窗口线被 Google 侧噪声压住是
|
||||||
* 波次规模)且占比>0.5% ×0.7(重波次 ≥12 且>2% ×0.5);门壳 ≥3 且占比>15% ×0.85;
|
* 数学必然,砍速是毒药、爬坡摊薄是解药):零我方故障且联合噪声(captcha+门壳)≤6/8
|
||||||
* 池空>5 ×0.85;软砍下限 SOFT_FLOOR=40(v5.1:25→40,保稀释安全线);
|
* → 可退段(短窗 ≥96%)/可爬坡(短窗 ≥96%),×1.3/拍 向水位回收,水位之上 ×1.08/5 拍;
|
||||||
* 干净爬坡:水位 = 30min 窗 ≥99%(v5.2:99.5%→99%,涓流时段高门槛不可达)且短窗 ≥99%
|
* 软砍下限 SOFT_FLOOR=40(99% 目标下 25/min 涓流占比已贴线),硬砍下限 HARD_FLOOR=8。
|
||||||
* 时记录;水位下方 ×1.3/拍快速回收,水位之上 ×1.08/5 拍;爬坡备选「验证码 ≤2 且
|
|
||||||
* 短窗 ≥98%」与涓流口径一致(dp6 低速恢复锁死 + dp7 涓流滞留修复)。
|
|
||||||
* 干净爬坡:不在退化段 且 短窗干净 且 无池空 且(验证码 0 个或样本 ≥300)→ 向「干净
|
* 干净爬坡:不在退化段 且 短窗干净 且 无池空 且(验证码 0 个或样本 ≥300)→ 向「干净
|
||||||
* 水位」(30min 窗 ≥99.5% 时的最高速率)以 ×1.3/拍快速回收,水位之上每 5 拍 ×1.08。
|
* 水位」(30min 窗 ≥99.5% 时的最高速率)以 ×1.3/拍快速回收,水位之上每 5 拍 ×1.08。
|
||||||
* v5 修 dp6 实测「低速恢复锁死」:短窗成功率 ≥99.5% 在低速涓流下永不可达
|
* v5 修 dp6 实测「低速恢复锁死」:短窗成功率 ≥99.5% 在低速涓流下永不可达
|
||||||
@@ -177,48 +175,49 @@ function controlTick(): Record<string, unknown> | null {
|
|||||||
const from = rate;
|
const from = rate;
|
||||||
let to = from;
|
let to = from;
|
||||||
let reason = "hold";
|
let reason = "hold";
|
||||||
// 硬约束(v5.1,dp7 前 1.5h 实测教训:99% 线下比率陷阱重现在入段/退段/续砍三级 ——
|
// 故障二分(v5.3,dp7c 1.8h 实测:波次退潮后门壳 2~3 个/窗 + captcha 3~5 个联合噪声
|
||||||
// 低速涓流永远压住 99% 窗口线,degraded 锁死 → 砍到 3/min 浏览器饿死;稀释论:
|
// 把窗口钉在 96.6~97.9%,nonCapFails===0 退段与 successS≥0.98 爬坡双双卡死在 8/min;
|
||||||
// 验证码涓流的唯一解药是爬坡摊薄,砍速让分母变小占比更高,是毒药):
|
// 门壳/空结果与 captcha 同为 Google 侧供给,稀释论同样适用 —— 我方故障只剩
|
||||||
// 涓流豁免 = 30min 窗零非验证码失败 且 短窗验证码 ≤2 个(涓流规模,非波次);
|
// 池空/httpErr/netErr):
|
||||||
// ① 退段:窗口 ≥99%,或涓流豁免且短窗 ≥98.5%;② 入段:涓流不入段;
|
// infraFails = 我方故障;googleNoise = captcha+门壳(联合噪声预算)
|
||||||
// ③ 段内续砍需真证据:非验证码失败 ≥1(我方故障)或验证码 ≥5/10min(波次规模)
|
// ① 退段:窗口 ≥99%,或零我方故障且联合噪声 ≤6 且短窗 ≥96%(低速小分母下窗口
|
||||||
|
// 成功率被噪声压住是数学必然,退段只看「波次是否结束」不看窗口线);
|
||||||
|
// ② 入段:浅破线(<99% 且失败 ≥8 且窗口 ≥200 样本,v5.2 防小样本级联)或深破线
|
||||||
|
// (<96% 且失败 ≥4);Google 侧噪声不触发入段(灾难波次由软规则管);
|
||||||
|
// ③ 续砍:我方故障 ≥3 或 captcha ≥5/10min;砍速地板按故障归属:我方 8 / Google 侧 40
|
||||||
const fails = tot - wH.ok;
|
const fails = tot - wH.ok;
|
||||||
const allFails = totals.sent - totals.ok;
|
const allFails = totals.sent - totals.ok;
|
||||||
const successS = wS.sent > 0 ? wS.ok / wS.sent : 1;
|
const successS = wS.sent > 0 ? wS.ok / wS.sent : 1;
|
||||||
const nonCapFails = wH.gate + wH.empty + wH.poolEmpty + wH.httpErr + wH.netErr;
|
const infraFails = wH.poolEmpty + wH.httpErr + wH.netErr;
|
||||||
const trickle = nonCapFails === 0 && wS.captcha <= 2;
|
const googleNoiseS = wS.captcha + wS.gate;
|
||||||
if (success >= 0.99 || (trickle && successS >= 0.985)) degraded = false;
|
const trickle = infraFails === 0 && googleNoiseS <= 6;
|
||||||
// 入段(v5.2 加量下限,dp7 实测教训:冷启动波次在 ~90 样本窗口上 4 个失败即被 ×0.5,
|
if (success >= 0.99 || (trickle && successS >= 0.96)) degraded = false;
|
||||||
// 小样本噪音驱动级联):浅破线(99%~96%)需窗口 ≥200 样本且 ≥8 失败;深破线(<96%)
|
|
||||||
// 仍快速响应(≥4 失败即可,真崩溃不等样本攒够)
|
|
||||||
const entry = !degraded && !trickle && ((success < 0.99 && fails >= 8 && tot >= 200) || (success < 0.96 && fails >= 4));
|
const entry = !degraded && !trickle && ((success < 0.99 && fails >= 8 && tot >= 200) || (success < 0.96 && fails >= 4));
|
||||||
// 段内续砍(v5.2 提证据门槛):非验证码失败 ≥3(1~2 个门壳是波次伴生噪音,dp7 实测
|
const ongoing = degraded && wS.sent >= 30 && successS < 0.96 && (infraFails >= 3 || wS.captcha >= 5) && allFails - failsAtLastCut >= 2;
|
||||||
// gate=1 即解锁续砍)或验证码 ≥5/10min(波次规模);短窗样本 ≥30
|
|
||||||
const ongoing = degraded && wS.sent >= 30 && successS < 0.96 && (nonCapFails >= 3 || wS.captcha >= 5) && allFails - failsAtLastCut >= 2;
|
|
||||||
if (entry || ongoing) {
|
if (entry || ongoing) {
|
||||||
degraded = true;
|
degraded = true;
|
||||||
failsAtLastCut = allFails;
|
failsAtLastCut = allFails;
|
||||||
to = success < 0.96 ? from * 0.5 : from * 0.7;
|
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}`;
|
reason = `success=${(success * 100).toFixed(1)}%<${success < 0.96 ? 96 : 99}%(失败 ${fails}${entry ? "" : ";短窗<96%+新失败≥2"}) ×${success < 0.96 ? 0.5 : 0.7}`;
|
||||||
} else {
|
} else {
|
||||||
// 软信号:事件段迟滞 + 绝对数护栏(v5.1:验证码护栏 3→8 个/10min —— 只砍波次规模,
|
// 软信号(v5.3:只砍灾难波次 —— captcha ≥24 个/10min ≈ 144/时 = dp6 最差小时水平,
|
||||||
// 涓流交给稀释;低速率下 1~2 个噪音即高比率,不得触发;dp5 教训)
|
// 常规波次 45~90/时不再触发;门壳 ≥20 个/10min ≈ 3× dp6 峰值;涓流/常规波次交给
|
||||||
if (wS.captcha >= 8 && capPctS > 0.005 && !captchaWave) {
|
// 稀释与爬坡;低速率小分母下的高占比是数学现象,不是信号;dp5/dp7 三轮实测)
|
||||||
|
if (wS.captcha >= 24 && capPctS > 0.005 && !captchaWave) {
|
||||||
captchaWave = true;
|
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));
|
to = Math.max(SOFT_FLOOR, from * (heavy ? 0.5 : 0.7));
|
||||||
reason = `验证码 ${wS.captcha} 个占比 ${(capPctS * 100).toFixed(2)}% ${heavy ? "×0.5" : "×0.7"}`;
|
reason = `验证码 ${wS.captcha} 个占比 ${(capPctS * 100).toFixed(2)}% ${heavy ? "×0.5" : "×0.7"}`;
|
||||||
} else if (wS.captcha === 0) captchaWave = false;
|
} 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;
|
gateWave = true;
|
||||||
to = Math.max(SOFT_FLOOR, from * 0.85);
|
to = Math.max(SOFT_FLOOR, from * 0.85);
|
||||||
reason = `门壳 ${wS.gate} 占比 ${(gateRatioS * 100).toFixed(1)}%>15% ×0.85`;
|
reason = `门壳 ${wS.gate} 占比 ${(gateRatioS * 100).toFixed(1)}%>15% ×0.85`;
|
||||||
} else if (gateRatioS < 0.05) gateWave = false;
|
} else if (gateRatioS < 0.05) gateWave = false;
|
||||||
if (to === from && wS.poolEmpty > 5 && !poolEmptyWave) {
|
if (to === from && wS.poolEmpty > 5 && !poolEmptyWave) {
|
||||||
poolEmptyWave = true;
|
poolEmptyWave = true;
|
||||||
to = Math.max(SOFT_FLOOR, from * 0.85);
|
to = Math.max(HARD_FLOOR, from * 0.85);
|
||||||
reason = `池空 ${wS.poolEmpty} ×0.85`;
|
reason = `池空 ${wS.poolEmpty} ×0.85`;
|
||||||
} else if (wS.poolEmpty === 0) poolEmptyWave = false;
|
} else if (wS.poolEmpty === 0) poolEmptyWave = false;
|
||||||
}
|
}
|
||||||
@@ -226,13 +225,13 @@ function controlTick(): Record<string, unknown> | null {
|
|||||||
// 水位永远立不起来 → 深跌后只剩 ×1.08/5 拍龟速爬坡,dp7 实测):窗口 ≥99% 且短窗 ≥99%
|
// 水位永远立不起来 → 深跌后只剩 ×1.08/5 拍龟速爬坡,dp7 实测):窗口 ≥99% 且短窗 ≥99%
|
||||||
// 时的速率即为「实测可行」
|
// 时的速率即为「实测可行」
|
||||||
if (success >= 0.99 && successS >= 0.99 && wS.sent >= 10) maxCleanRate = Math.max(maxCleanRate, from);
|
if (success >= 0.99 && successS >= 0.99 && wS.sent >= 10) maxCleanRate = Math.max(maxCleanRate, from);
|
||||||
// 干净爬坡:退化段中不爬(30min 窗未恢复 99%);深跌后向水位快速回收 ×1.3/拍,水位之上 ×1.08/5 拍;
|
// 干净爬坡(v5.3):退化段中不爬;主条件短窗 ≥99.5%,备选「零我方故障且联合噪声 ≤8
|
||||||
// 爬坡验证码条件:主条件短窗成功率 ≥99.5%,备选「验证码 ≤2 且短窗 ≥98%」(v5.1:与涓流
|
// 且短窗 ≥96%」(与退段口径一致 —— 低速小分母下高窗口线不可达,爬坡本身就是摊薄手段,
|
||||||
// 豁免口径一致,修 dp6 实测低速恢复锁死 + dp7 实测涓流滞留 —— 爬坡摊薄后比率自然回落);
|
// ×1.3/拍 中速率每上台阶噪声占比自动减半,自校正);池空独查;样本/占比条件废除,
|
||||||
// 短窗 0 个验证码恒可爬,或样本 ≥300 时比率已无意义(绝对护栏统一交给软砍规则)
|
// 绝对护栏统一交给软砍规则
|
||||||
if (to === from && !degraded && wS.sent >= 10) {
|
if (to === from && !degraded && wS.sent >= 10) {
|
||||||
const cleanS = successS >= 0.995 || (wS.captcha <= 2 && successS >= 0.98);
|
const cleanS = successS >= 0.995 || (infraFails === 0 && googleNoiseS <= 8 && successS >= 0.96);
|
||||||
if (cleanS && gateRatioS < 0.02 && wS.poolEmpty === 0 && (wS.captcha === 0 || wS.sent >= 300)) {
|
if (cleanS && wS.poolEmpty === 0) {
|
||||||
rampSeq++;
|
rampSeq++;
|
||||||
if (maxCleanRate > 0 && from < maxCleanRate * 0.75) {
|
if (maxCleanRate > 0 && from < maxCleanRate * 0.75) {
|
||||||
to = from * 1.3 + 0.2;
|
to = from * 1.3 + 0.2;
|
||||||
|
|||||||
Reference in New Issue
Block a user