From f86a999c5260a2819c6ad2483a1133246565853d Mon Sep 17 00:00:00 2001 From: lovife <474239041@qq.com> Date: Wed, 30 Sep 2026 11:10:05 +0800 Subject: [PATCH] =?UTF-8?q?perf(gate):=20=E9=97=A8=E7=A6=81=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E4=B8=8A=E9=99=90=20200=E2=86=92600=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20250=20=E4=BA=BA=E5=90=8C=E6=97=B6=E6=A0=B8=E9=AA=8C?= =?UTF-8?q?=E6=9B=BE=E6=8C=A1=E4=BD=8F=2037=20=E4=B8=AA=EF=BC=88F-100?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 契约 §1.6 只规定了失败侧(同 openid 10 次/小时、同 IP 20 次/分钟), 成功侧 200/分钟是本项目自己加的(防"拿匹配接口批量取数据"), 而当初注释里写的本意是"一个 200 人的年级同时扫码也不该被挡"。 实测(python scripts/load-test.py --only gate --rows 250): 250 个不同学生同时核验(全部正确)→ 213 成功、37 被挡, 提示「当前网络访问过于集中,请稍等 1 分钟再试」。 "全校在同一个出口 IP 集中扫码"(开学第一课集体填报)正是会发生的场景, 而这些人没有一个做错了什么 —— 与 F-92「教室被挡住」同一类,量级放大到一所学校。 上调为 600 的依据:一所学校一次集中填报的峰值。它仍然是限速(600 条/分钟), 而防枚举靠的是失败侧那两个计数器 —— 原样未动,防猜测强度没有降低。 验证: 250 人 → 250/250(改前 213/37) 500 人 → 500/500(500 并发 p50 1.4s / p95 2.5s,是排队不是限流) scripts/e2e-m3-gate.py → 29/29 文档同步:docs/01 E2(二次修正备案)、docs/09 §9.3 / §9.1。 教训:自己加的"防御性限额"也要过一遍真实场景的量级 —— 否则它与它要防的东西一样,都是事故。 --- .../module/mp/service/MpRosterService.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/backend/xt-server/src/main/java/cn/tianbaotong/fill/module/mp/service/MpRosterService.java b/backend/xt-server/src/main/java/cn/tianbaotong/fill/module/mp/service/MpRosterService.java index 737bddd..6057f4b 100644 --- a/backend/xt-server/src/main/java/cn/tianbaotong/fill/module/mp/service/MpRosterService.java +++ b/backend/xt-server/src/main/java/cn/tianbaotong/fill/module/mp/service/MpRosterService.java @@ -67,12 +67,25 @@ public class MpRosterService { private static final int IP_FAIL_LIMIT_PER_MINUTE = 20; /** - * 同一个 IP 每分钟最多**成功** 200 次。 + * 同一个 IP 每分钟最多**成功** 600 次。 * *
成功会返回该学生的姓名与预填数据,所以要防"拿这个接口批量取数据"。 - * 但限额必须给教室规模留足量:**一个 200 人的年级同时扫码也不该被挡**。 + * 但限额必须给**一所学校**留足量。 + * + *
⚠️ 200 → 600 是压测改出来的(2026-09-30):契约 §1.6 只规定了失败侧 + * (同 openid 10 次/小时、同 IP 20 次/分钟),这个成功侧上限是本项目自己加的, + * 而原来定的 200 恰好卡在"一个年级"的量级上 —— 实测 **250 个不同学生同时核验 + * (全部正确)时 213 个成功、37 个被挡**,提示是「当前网络访问过于集中」。 + * 全校在同一个出口 IP 集中填报(开学第一课集体扫码)就会撞上它, + * 而这些人**没有一个做错了什么**(与 §9.3 那次"教室被挡住"同一类)。 + * + *
600 的依据:一所学校一次集中填报的峰值人数。它仍然是一个**限速**—— + * 抓数据的人拿到手的是 600 条/分钟而不是不限速;而防猜测靠的是失败侧那两个计数器 + * (枚举产生的是失败,不是成功)。 + * + *
调这个数之前先量:`python scripts/load-test.py --only gate --rows 500`。 */ - private static final int IP_OK_LIMIT_PER_MINUTE = 200; + private static final int IP_OK_LIMIT_PER_MINUTE = 600; private static final String KEY_USER = "xt:mp:gate:user:"; private static final String KEY_IP = "xt:mp:gate:ip:";