Akke 评论抓取时效 · 深度调查

从一条视频案例挖到全链路根因 · 2026-06-15 · 数据均为当日实查生产库
📊 实时数据快照(每日重算) · 本页是一次性深挖;时延分布 / 空跑率 / pri 队列积压等会随时间变的数字,看自动生成的数据快照页 → scrape-latency 数据快照 (口径同此页,judgment 段仍以本页为准)
一句话结论。 高意向评论从「用户发出」到「进我们库」,慢不在抖音、不在抓取动作本身,而在两段等待:Leg B 等到有人来抓这条视频(冷视频几十分钟到几小时)+ Leg C 活派出去后在队列里排队(中位 ~4.6 分钟)。再往上追,近 4 成高意向评论走 ≥30 分钟慢路,其中 97% 是「冷视频」;而冷视频之所以多,是因为 tier-1 优质号「只升不降」攒到 176 个、其中 74% 是不产高意向的僵尸,挤爆抓取产能、把 1019 个 tier-0 号饿死。最值钱的一刀:给 tier-1 加降级。

导读: 起点案例 · 全链路五段拆解(含机制+成因,最详细)· 拐点实证 · 慢路损失多大 · 总根因(僵尸 tier-1)· 提升点 · 数据快照(含 cron 3→2 复核)· 队列三问(Leg B 入队 / BC 极限 / 快车道 100 条)· ⑨ 2026-06-16 B/C 落地成效 + 真尾巴 + pri 体系(最新)

🍚🍎 看不懂术语?文档里有两张「大白话比方」,配着看:② 段中部「食堂打饭」讲五段各自在哪堵(菜做好→等人端→排队等阿姨打饭);⑨ 段开头「果园摘果」讲机制怎么转(视频=果树/高意向=熟果/快车道=重点照看名单/tick=巡一圈/退避=空手就少去/去重=别每轮重派同一棵)。所有黑话(冷视频 / 单视频快活 / 整号活 / 60min 门槛 / tick / 注入去重 / 退避)都在第一次出现处就地有具体定义

① 起点:从你发来的一条视频挖起

输入是一条抖音视频链接 douyin.com/video/7648553920499141739。反查得到:

账号歆笛的装修日记(知识号)
分层Tier-1 优质号
累计评论 / 高意向184 / 15 (整号 29 条视频累计;非单条视频)
近 7 天高意向11 条(全压在近 7 天,是个正在爆量的号)
高意向触达状态15 条里 13 条还没触达(analyzed)
口径说明(2026-06-16 复核):184 / 15 / 13 是账号「歆笛的装修日记」整号口径(现查 206 / 15 / 13,184→206 是评论自然增长)。链接那条单视频本身只有 108 评论 / 11 高意向。下表 15 条高意向 = 整号 29 条视频的累计,不是单条视频的。

逐条看这 15 条的「发言→抓到」延迟,发现一个反常:同样是 Tier-1,有的 1 分钟抓到,有的 29–48 分钟,还有的拖到 几天。这就是整条调查的起点。

#用户发言抓到延迟评论摘要(意向分)
1大海05-19 07:3205-21 13:382.3 天帮忙发一份吧 (85)
2@~#~?05-19 09:3905-21 13:382.2 天要一份 (85)
3小肥猫05-19 09:4705-21 13:382.2 天我要一份 (85)
4风少05-20 20:5005-21 13:3816.8 时100平15万预算求方案 (93)
5,,,06-09 22:3206-14 07:494.4 天下个月准备装修,真的需要 (85)
6🍒奶黄包06-12 00:2906-14 01:242.0 天我也需要,准备装修 (85)
7英儿06-12 08:3306-14 01:2440.9 时来一套资料 (85)
8安安06-12 11:3506-14 01:2437.8 时258平大概多少钱 (93)
9燕飞狐06-13 11:0506-14 04:3717.5 时最近准备装修,求份资料 (85)
10双子娃娃06-13 23:5206-14 01:241.5 时71平学区房,求资料 (93)
11龍凤呈祥06-14 08:0806-14 08:3729 分一百平小三室,求资料 (100)
12用户508006-14 09:4406-14 10:1430 分下月要装修了 (85)
13古悠然06-14 15:4906-14 15:511 分准备装修,求全套资料 (85)
14信仰 已触达06-14 16:4906-14 16:577 分多少平米的定制 (85)
15二宝妈 已触达06-15 00:3506-15 00:372 分求资料,毛坯房 (85)

汇总:中位 17.5 时 · 最快 1 分 · 最慢 4.4 天。趋势——越往后(6-14 下午起)越快;5 月那几条 2 天级、6-14 凌晨 01:24 那批是「断档恢复一次性补抓」的积压。这个「越来越快」的拐点,③ 坐实。

② 全链路五段拆解(含机制 + 成因,最详细)

一条评论 T0 用户发出 → 进我们库,走完五道关。先看每段实测耗时,再把最关键的 B、C 两段彻底讲透(抓取机制、冷视频成因都在这一节,不用往后翻):

Leg A
抖音侧上架(评论发出 → 抖音 API 能查到) · 不可控
~几秒
Leg B
入队等待(评论可见 → 有人来抓这条视频) · 大头之一
数分钟~数小时
Leg C
队列排队(活派出去 → worker 领走) · 大头之一
≈ 4.6 分
Leg D
执行抓取(领走 → 抓完写库) · 抖音新→旧返回,抓首页即命中、早停,1 个请求
4.9 秒
Leg E
写库
亚秒
B 和 C 都是大头,A/D/E 全是秒级。 哪个主导取决于这视频「热不热」:热视频(已在快车道)→ B 较小、C 的 4.6 分排队主导;冷视频(97% 的慢路属于此)→ B 直接是几十分钟到几小时,C 反而次要。
🍚 嫌五段绕?用「食堂打饭」打个比方(一条评论 = 一份菜,从做好到端你嘴边): (这张比方管"五段各自在哪堵";后面 ⑨ 开头那张「🍎 果园摘果」管"怎么选视频、怎么排队、怎么退避去重"——两张互补,配着看。)

Leg A · 抖音侧上架(~几秒,不可控)

用户点「发送」后,这条评论要先在抖音自己的系统里能被 API 查到。我们管不着,但很快——用最快的端到端样本(1 分钟)倒推,这段只占几秒。

Leg B · 入队等待 =「等到有人来抓这条视频」(大头)

"抓这条视频" = worker(干抓取活的程序)去这条视频底下把评论捞一遍。它什么时候被抓到,完全由我们的抓取机制决定 —— 有两条路,下面讲全。

B-1 · 两条路概览

怎么触发覆盖谁节奏
🐢 整号慢路这条视频所在的「号」被整体抓一遍时,顺带把它主页前 20 条视频都抓了所有号(按 tier 分快慢)tier-1 号 ≥30 分 / tier-0 号 ≥7 时
视频快车道不看号,直接挑「正在冒新评论的 top 100 视频」单独抓够格的热视频每 2 分钟挑一批

B-2 · 号源轮抓机制(整号慢路)= 三个频率别混

号分两层,走两条 cron(cron = 定时任务,到点自动触发的"闹钟")。最容易被绕晕的是「闹钟频率 ≠ 每个号实际多久被抓一遍」:

tier-0 普通号tier-1 优质号
闹钟多久响(cron)每 1 小时(原 4h)每 2 分钟(原 5min→3min→今天 2min)
每次派多少挑 150 个最久没抓的号所有 tier-1(受下面节流)
同一个号多久能再抓无硬闸,靠 150 名额轮≥30 分钟(节流闸,今天从 45 改 30)
队列优先级pri=5 慢道pri=1 快道
每个号实际间隔≥7 小时(1019 个号挤)≥30 分钟(且超产能更长)
"5 分钟 / 1 小时"是老黄历:那是闹钟频率,不是每个号实际节奏。tier-1 早期没节流时确实 5 分钟一轮,但 6-11 那次「tier-1 太勤把 tier-0 全饿死」的 P1 事故后加了「同号 30 分钟内不重抓」的闸——所以现在 tier-1 名义 30 分钟、tier-0 ≥7 小时。一个「整号活」= 去主页捞 ≤20 条视频、逐条抓(同号 2 条并发、30 分钟内抓过的跳过)。

B-3 · 视频快车道机制(快路)

由同事 tuan19960216 在 2026-06-14 11:03 上线(PR #340)。藏在 tier-1 的闹钟里,每 2 分钟独立跑一轮下文把「闹钟响一次 / 跑一轮」叫「1 个 tick」,现 cron */3 = 每 3 分钟一个 tick):

B-4 · 成因:慢路 97% 是「冷视频鸡生蛋」

先把「冷视频」讲具体(本报告操作口径):判定法=一条评论走慢路时,看它所在的那条视频「前 24h 有没有被快车道抓过」——没上过 = 冷视频。通俗说=这条视频不在「快车道高频复扫名单」里,它底下的新评论只能等「整号轮抓」几十分钟~几小时扫一遍才被发现,永远够不上「评论冒出 ≤60min 内被新鲜抓到」的上车门槛(= 鸡生蛋)。
会冷的视频有三类:老视频(发布几天/几周,掉出号主页最近 ≤20 条,整号活也不再抓它);② 不活跃号底下的视频(号本身轮抓间隔长);③ tier-0 号的视频(每小时才轮一次、还常被饿死到 ≥7h)。
反面「热视频」=正在被快车道高频复扫的视频(近 48h 有过「≤60min 新鲜抓到」的评论、在名单上)。

近 2.5 天 274 条走慢路(>30 分)的高/中意向评论,按「评论来时它那条视频前 24h 有没有上过快车道」分类:

成因条数占比
🥶 冷视频鸡生蛋(从没上过快车道)26597%
📉 掉车(上过又没赶上)93%
其中深夜掉车1
死循环(鸡生蛋):一条视频要「被 ≤60 分钟新鲜抓到过一次」才够格进快车道(B-3 的门槛);可冷视频只走慢路、永远赶不上 60 分钟 → 永远进不了快车道 → 它上面的评论第一条几乎必然慢。这些冷视频很分散(262 条散在 133 条不同视频上,top10 仅占 38%),治它得撒广网、不能盯几条。这就是 Leg B 对冷视频长达几十分钟~几小时的根因。

Leg C · 队列排队 = 活派出去后,为什么还要排 4.6 分钟(大头)

就算 Leg B 把活派进了队列,worker 也不是立刻抓。实测中位 276 秒、p99 327 秒。机制如下:

已坐实(2026-06-15 23:00 实查 worker 活体):不是 slot 闲置。/queue/stats 报 pending=2 是假象(只数最近 1000 条窗口),真实 pending=640(pri1 103 / pri5 537);8 槽真忙(claim 78/分、running 常态 8 个无僵尸)。Leg C 的真因 = pri=1 队列常年积压 ~100 条,新活按"同级先到先得"排在后面——实测一个 23:06:53 的 tick 灌的批次,全等到 ~23:11:35 才被领走(285 秒)。排不空因为:① 快车道昼夜不停每 2 分钟灌一批(深夜 313s ≈ 午间 276s,无低峰);② 慢整号活(2+ 分钟)混在同条 pri=1 道占槽;③ 还有 poison 活(一条 38 小时前的 pri1 整号活重试到顶卡死、永远 pending)。

Leg D / E · 抓取 + 写库(秒级)

轮到后,worker 调抖音评论 API:抖音新评论排最前,增量抓只取首页、整页无新即早停,通常 1 个请求 ~5 秒搞定;写库亚秒。所以抓取本身不慢,慢的全在 B、C 两段等待。

③ 拐点实证:歆笛从慢路爬上快车道

B-3 说快车道 6-14 11:03 上线。歆笛这条视频的延迟正好在那之后断崖式变好——这就是 B 两条路切换的铁证:

发言抓到等待走哪条路
06-14 08:0808:3729 分🐢 整号慢路龍凤呈祥 ⭐
06-14 09:4410:1430 分🐢 整号慢路用户508 ⭐
───── 11:07 这视频首次挤上快车道 ↓ ─────
06-14 15:4915:511 分⚡ 快车道古悠然 ⭐
06-14 16:4916:577 分⚡ 快车道信仰 ⭐
06-15 00:3500:372 分⚡ 快车道二宝妈 ⭐
06-14 23:2906-15 14:2514.9 时🐢 掉回慢路🐟ᐝ
这就回答了「Tier-1 说好高频、为什么 48 分钟」:早上还没上快车道,只能走整号慢路(B-2);中午上车后全是 1–7 分钟。但它还会掉车——深夜没新评论就被踢出快车道名单,新评论又回慢路(🐟ᐝ 等了近 15 小时)。

④ 慢路损失有多大

全库高/中意向评论按延迟分桶(口径分三层,避免被历史积压误导):

口径样本中位延迟≤5 分>30 分(走慢路)
全部历史13,8422344 分4.5%86% (陈年积压污染,忽略)
近 7 天2,830261 分13.7%70% (含 6-14 断档尾巴)
近 2 天(真常态)44410 分41%37%
看「近 2 天」:快车道已把理想情况做到分钟级(41% 在 5 分钟内抓到),但仍有 37% 的高/中意向评论走慢路、>30 分钟才抓到,其中 ~22% 拖到 2–24 小时。每 10 条就有近 4 条漏出快车道——而这 4 条里 97% 是 B-4 的冷视频。

⑤ 总根因:只升不降的 tier-1 撑爆了产能 🎯

顺着 B-2/B-4 往上追:冷视频之所以这么多,是因为大量 tier-0 号被饿死、长期不被抓。而 tier-0 被饿死,又是因为 tier-1 太多——

auto-tier1 每天把「近 3 天高意向 ≥5」的活跃号升 tier-1,但系统没有任何降级逻辑——只升不降。于是 tier-1 越攒越多:

活跃不活跃
tier-1 优质号17610
tier-0 普通号10191828

176 个 tier-1 里,74% 是僵尸(近 7 天高意向口径)

近 7 天高意向个数
🟢 仍达标(≥5)46
🟡 不够格(1–4)68
🔴 挂零(0)62
完整根因链:只升不降 → tier-1 攒到 176(其中 130 个僵尸,74%,含一堆同行/工厂号)→ 176 个每 30 分钟要抓一遍 = 需要 ~352 整号活/小时,但 worker 产能才 ~270/小时 → tier-1 自己吃爆产能 → pri=5 的 1019 个 tier-0 被饿死(每号 ≥7 小时)→ tier-0 视频长期是「冷」的 → 评论落上去只能走慢路、又进不了快车道(鸡生蛋)→ 就是 ④ 那 37% 慢路、B-4 那 97% 冷视频的总源头
「总根因」≠「唯一原因」——别误读这节:tier-1 只升不降是上游放大器(决定"冷视频有多少"),但 B、C 的机制本身也各有独立的洞、且今天 #363/#366 改的正是它们:C 队列=慢快混 pri=1 道(#363 分道)+ 空跑洪水(#366 退避);B 抓取=60min 门槛锁死冷视频(#363 破鸡生蛋)+ 老视频覆盖盲区(那条 38% 真尾巴,方案② 待做)。打比方:B/C 是管道本身有堵点(已疏通大半),tier-1 是上游一直往管道灌脏水(量太大)——两头都得治。叫它"总根因"只因它是最大的单一杠杆 / 性价比最高的一刀(P0-a),不是说别处不用改。
「74% 僵尸」要分两个口径看(2026-06-16 复核):上表按「近7天高意向 <5」砍 = 132 个(75%);但这 132 里 ~106 个仍在产中意向或 1–4 条高意向 lead,是「不够 tier-1 的格」、不是「死号」。真正近7天连一条高/中都没产的只有 27 个(15%)降级该砍哪批是策略选择:砍 27(保守,只清真死号)/砍 132(激进,腾产能最多但会误降还在产 mid lead 的号)。6-16 已先砍保守那 27 个(见 ⑦),active tier-1 176→149;要不要进一步砍到 ~46 看 mid lead 价值再定。

⑥ 提升点(按性价比排)

2026-06-16 状态:P0-a/b/c/d 全部落地(详细成效见 ⑨)。P0-a 手动砍 27 + #365 自动降级;P0-b/c = #363 破鸡生蛋 + 快慢分道;#366 空跑退避;P0-d 已清 poison。Leg C 把典型延迟(median)砍了 2/3(全天 −67%)、但极端尾巴(p99)被注入洪水拖坏(见 ⑨-D 全天复核);另端到端 38% 慢尾真因是老视频覆盖盲区,下一刀见 ⑨-F。
原因(为什么要做这刀)现有内容(做了什么 · 状态)
P0-a 断总根因:tier-1 只升不降攒到 176、74% 僵尸,挤爆抓取产能、把 1019 个 tier-0 饿死 → 冷视频多、慢尾多。 ✅ 已落地:6-16 手动砍 27 个真死号(高+中=0)176→149;#365 对称 auto-demote(自动降级、断只升不降)已合并部署。下一步可按 mid lead 价值再砍到 ~46。单这一刀解大半。
P0-b 治 Leg B 冷视频:97% 慢路是「冷视频鸡生蛋」——冷视频赶不上 60min 新鲜门槛、永远进不了快车道(冷视频定义见 B-4)。 ✅ 已落地#363 破鸡生蛋——任一视频近 6h 一冒高/中意向评论,立刻临时拉进快车道(pri=0 插最前),不等它够 60min 门槛。(注入空扫待补「去重」,见 ⑨-D)
P0-c 治 Leg C 排队:慢整号活(23–211s)和快活(5s)挤同一条 pri=1 道 → 排队 4.6 分;且快车道空跑洪水(多数复扫 found=0)白占位。 ✅ 已落地#363 快慢分道把整号活降 pri=3 让快活先走(尾延迟 p90 −61%/p99 −75%);#366 空跑退避(连 3 次 0 新 → 9→18→30 分钟退避)。直接压那 4.6 分钟。
P0-d 清 poison + pri=1 减负:38h 前重试到顶仍卡 pending 的僵尸活白占;慢整号活也还堵在 pri=1 道。 ✅ 已落地:6-16 已删那个 59h poison 墓碑活;并随 P0-c 把慢整号活挪出 pri=1。(「自动清 poison」还可补成常态 job)
P1 怀疑「并发不够、要扩机」。 有效并发实测 ~8–11 槽(非瓶颈),无需盲目扩机;真瓶颈是 pri=1 队列结构(已由 P0-c/d 治)。
不要做 想靠「提 cron 频率」提速(闹钟 2min→1min)。 别做——会让快道空跑翻倍、Leg C 更糟。(#346 已验证 cron 不是瓶颈;甚至 */2→*/3 回退反而更好,见 ⑦)

理论地板:治好 B、C 两段后,整条链可压到 10–30 秒。今天那几条 1 分钟抓到的,就是低峰不拥堵时跑出来的——目标是把「1 分钟内」从偶发变常态。

⑦ 今日已动 + 数据快照

今日改动(PR #346,已上线):scrape-hot 闹钟 */3 → */2 + 源节流 45 → 30 分。但实测发现 cron 不是瓶颈(真瓶颈是 Leg B/C),所以原计划第二步 */1 已取消。

「3 分改 2 分有用吗 / 要不要改回去」(2026-06-16 实测复核)用处很小,可以改回 */3,甚至略有好处。实查近 24h scrape_video 快活 88,455 条,其中 77% 复扫 0 新评论(空跑);快车道每 2 分钟灌 ~67 条(dedup 后)。*/3→*/2 把这股空跑洪水抬高了 50%,而它灌的全是 pri=1 活——正是堵 Leg C 的那条队。所以:改回 */3 反而少 33% 空跑、减轻 pri=1 积压,只换来热视频复扫间隔从 ~2 分变 ~3 分(次要)。真正起作用的是同批的源节流 45→30(让 tier-1 更早可重抓),不是 cron tick。结论:tick 是二阶旋钮,回 */3 没坏处;真问题仍是 P0-a 降级 + P0-c 队列双层优先级。

cron tick=2分 ✓Leg C 中位 276s / p99 327sLeg D 中位 4.9s快车道命中率 18%worker 实测有效并发 ~11 · 总吞吐 ~3000 活/htier-1 149(6-16降27真死号)tier-0 1046慢路 37%(近2天)冷视频 97%

2026-06-16 实测刷新 + 已动刀:① 机器就 2 台(已用 fly status 实查坐实,不是推测)——akke-worker-prod 现 2 台 started、都在东京(nrt),auto_stop=off 常驻不缩,不会因为 pri=1 洪水自动多起第三台(Fly 没有"按负载自动扩容"这回事;早先写「瞬时 >2 台 / deploy token 读不到机器数」是错的,现已实查更正)。要加机器只能手动 fly scale count=N。② "槽"分两层,别混(这就是之前 8 / 11 打架的根源)工位(job slot)= 2 台 × WORKER_CONCURRENCY=3 = 6 个,是"同一时刻最多领几个活"的硬上限;但一个"整号活"内部还能同时拉 2 条视频MAX_VIDEOS_PER_SOURCE_CONCURRENT=2)→ 真正"同时在飞的抓取请求"能到 ~6–12 条。Little's law 反推的 ~11,量的是后者(在飞的请求数),不是工位数;running 行 14 里还含 ~3 个 zombie 虚高。总吞吐 ~3000 活/h。③ 已执行 P0-a 第一刀:把「近7天 高+中意向产出=0」的 27 个真死号降回 tier-0,active tier-1 176→149(回滚清单存盘)。
两台机器怎么配合 · 要不要扩 / 怎么优化(2026-06-16 实查后补)
配合方式 = 不用配合,数据库的"行锁"就是调度员。两台都是一模一样的无状态 poller,各自独立去同一张 scrape_jobs 表抢活(调 claim_pending_scrape_jobs_batch,靠 Postgres FOR UPDATE SKIP LOCKED)。这把锁保证同一条活绝不会被两台同时领——谁手头空了谁去抢下一条,天然就负载均衡,没有主从、不用分工、不会撞车。所以"两台如何配合"的答案是:它们根本不需要互相知道对方存在。
要不要加到三台?暂时不要。 横向 fly scale count=2→3 能线性加工位(每台 +3),但 ⑥-P1 已实测并发不是瓶颈——这 6 个工位有近 9 成时间在空跑(复扫 0 条新评论)。盲目加机器只会让"空跑"跑得更快,治不了 Leg B/C 的结构病。纵向把单台 WORKER_CONCURRENCY 3→5 也不行,会撞 shared-cpu-1x 的 CPU 墙(代码注释明写 5+ hits CPU wall)。
真正的优化 = 让现有这 6 个工位别空转:① 破鸡生蛋补"注入去重"(同一视频别每个 tick 重注一遍)把空跑率从 88% 砍下来,等于免费释放产能;② pri 防饿死,让 tier-0 别被堵 12 小时。这两刀做完,2 台绰绰有余;做不完,加到 3 台也只是"更快地空跑"。

⑧ 队列三问:Leg B 入的什么队 / BC 推到极限 / 快车道 100 条(2026-06-16 补,均查代码 / 生产库坐实)

Q0 · 先澄清「Leg B 入的是什么队」

Leg B 的"入队" = 把这条视频 / 号写成一行 scrape_jobsPostgres 表,不是 Redis / 内存队列)。两类行:

job_type是什么活priority
scrape_source整号活:去主页捞 ≤20 条视频逐条抓tier-0 = 5 / tier-1 = 1
scrape_video单视频快活:快车道增量复扫1
B 和 C 围着同一张 scrape_jobs 表。 worker 的 8 个 slot 各自轮询,调 claim_pending_scrape_jobs_batch RPC(Postgres SKIP LOCKED + ORDER BY priority ASC)领活。Leg B = 等 cron 把活写进表("何时轮到抓它");Leg C = 活已表里、按 priority 排队等某个 slot 领走。

Q1 · BC 推演到极限:能压到多久、怎么做、good/bad

现状极限地板怎么做
Leg B冷视频几十分~几小时≤2 分(常态 1–2 分)P0-b 破鸡生蛋:任一视频一冒高意向评论立刻强行注入快车道,不等它自己够 60min 门槛 → 压到 ≤1 个 tick(2 分)
Leg C≈ 4.6 分亚秒~数秒P0-c 双层优先级(带新评论的活提 pri=0 插队、慢整号活移出 pri=1)+ P0-d 清 poison → 活到达空队列 + 有空 slot 立即领
B+C 合计≈ 10–30 秒= ⑥ 末尾「理论地板」。今天偶发「1 分钟抓到」就是低峰不拥堵时已摸到这个地板
物理墙(压不穿):B 想再往秒级压需要"评论事件触发即扫",但撞 抖音反爬 ~67 req/min/号 红线——这是硬上限,不是代码问题。再快就伤生产号(滑块 / SMS / 封号升级链)。
GOODBAD / 风险
① 高意向触达从分钟~小时 → 1–2 分,抢客户热度窗、转化↑
② tier-0 解放、冷视频减少、漏抓减少
③ 队列不积压、poison 自清、系统更稳
① P0-b 强注入若不 capped 会重蹈 6-13「洪水偷产能饿死 tier-0」——必须配 P0-a 先释放产能 + 集合 capped
② 提扫描频率 / req-min 触发反爬、伤号(硬上限)
③ P0-a 降级可能误杀暂时低产的优质号(需回升机制)
④ 工程复杂度↑、更多队列状态要监控

Q2 · 快车道 100 条过完要多久

实测
受 pri=1 常年积压 ~100 条 + 慢整号活(23–211s)混在同条 pri=1 道占槽拖累。实测一个 23:06:53 灌的批次全等到 23:11:35 才被领走
≈ 5 分钟 / 批
理论地板
独占 slot、纯单视频快活:100 ÷ (并发 / 活长)。按 6-16 实测有效并发 ~11 槽、活时长中位 5.8s 算:100 × 5.8 ÷ 11
≈ 53 秒
治理后
P0-c/d 把慢整号活移出 pri=1、给带新评论的活插队,100 条快活不再被整号活堵
逼近 ~50 秒
口径更新(2026-06-16):原写「8 槽 → 理论 1 分钟」是 6-15 单次快照。6-16 直查生产库(Little's law:吞吐 ~50 活/分 × 活长均值 13.3s)实测有效并发 ~11 槽(running 行 14、约 3 个 zombie 虚高)、总吞吐 ~3000 活/h——比 8 高,故地板从 ~1 分缩到 ~53s。:slot 数只影响"一批 100 条多久跑完"(吞吐),不改单条评论的端到端地板(Q1 的 10–30s 由 tick + Leg D 5s 决定,与槽数无关)。
另两问搬家了:「云电脑 DM/RC 数据如何回传」「PR #360 能否自动回传」「关注流抓 day-0 新视频两探针」属于触达/潜在触达管线、不属于评论抓取时效,已移到 用户旅程 · 潜在触达页journeys-fanny#pt)的「技术机制」区。

⑨ 2026-06-16 实施进展 · 成效复盘 · 新发现的真尾巴(B/C 落地后)

⑥ 列的 P0 提升点今天全部落地(多个 PR 已合并部署)。但实测下来(全天 24h 复核):Leg C 把典型延迟砍了 2/3、但极端尾巴被注入洪水拖坏;Leg B 喜忧参半;而"评论拉取还是很久"的真尾巴另有其因——不是排队、是老视频覆盖盲区。逐项说清。

A0 · 本轮所有改动一览(每个 PR 一句话 + 比喻)

⑨ 段提到的每个 #编号 改动,先在这张表里一句话说清「它是什么 / 治什么病 / 现在什么状态」,下面 B、C 再展开。比喻统一用「果园摘果」:视频 = 果树,评论 = 果子,高意向评论 = 熟透值钱的果(lead),抓评论 = 派人去摘

改动一句话(果园比喻)治什么病状态
#363 · Leg B 破鸡生蛋看到偏远老树刚冒熟果,破例先抱上"重点照看名单"、还排最前,不等它够格冷视频上的高意向评论,第一条几乎必慢已上线 6-16
#363 · Leg C 快慢分道"摘单棵树"的快活和"巡整片园子"的慢活分开排队,让快的先走慢整号活堵在快活前面,快活干等已上线 6-16
#366 · 空跑退避一棵树连去 3 次都空手就少去(间隔 9→18→30 分钟),一冒新果立刻恢复勤去视频被反复复扫却抓 0 新、白占工位已上线 6-16
#365 · tier-1 自动降级不再活跃的优质号自动降回普通档(对称于自动升档)tier-1 只升不降、撑爆产能、饿死 tier-0已上线 6-16
#377 · cold-intent 回扫近 14 天还在冒高意向的老视频,每 20 分钟低频回扫一遍常青老视频上的新高意向,没人定期扫(老视频盲区)已上线 6-16
#381 · 注入去重破鸡生蛋的注入活也纳入退避(去掉原本豁免),别每 tick 重派同一棵树pri=0 注入洪水:同一视频 80 次/6h、100% 抓 0 新、拖坏 p99已上线 6-17
#413 · 早停修复增量抓评论别"一页全老就停",要连续 N 页全老才停(抖音按热度排、新评论埋后面)快道判"空"里 33% 是假空、漏了真评论(含 lead)已部署 6-18 · 当晚预览假空 33%→8%
B 和 C 怎么关联?一前一后两道关:
· Leg B 管"这条视频该不该被抓" —— 把该趁鲜抓的(含冷视频、刚冒高意向的)塞进快车道这个队列。
· Leg C 管"塞进来的活排不排得动" —— 队列里谁先跑(快慢分道)、别反复空扫白占位(退避)。
一句话:B 把活送进队列,C 决定它在队列里跑得顺不顺。B 一旦送太多(如注入洪水),就会把 C 的队列堵了 —— 这正是 #381 要补的接缝。

A · 两块地基:队列里有哪几类「活」+ 它们怎么排队跑

先说清两个容易混的事,免得往下读拧巴:

1)「Leg」是什么?=一条评论从"被发出"到"我们抓进库",中间分好几段路(② 段把它拆成五段)。本段只关心其中相邻两段:

· Leg B = 「派活」那段:评论已经存在了,但系统还没派出一个活去抓它("菜做好了,没人来端")。

· Leg C = 「排队执行」那段:活已经派进队列了,等 worker 领走真正去抓("菜端到打饭窗口,等阿姨打饭")。

2)「地基①②」不等于「Leg B / C」。地基是底盘(系统本来就这么转);Leg B / C 是在底盘上做的改动招式。下面先讲底盘,再讲招式。

以下「地基」是纯现状(系统现在怎么转,不含本轮改动);改动一律见上方 A0 一览表。

🍎 嫌底下黑话多?先用「果园摘果」一个比方把整套 B/C 讲通,后面的词都能对上号(这张讲"机制怎么转";想看"五段各自在哪堵"翻 ② 段「🍚 食堂打饭」,两张互补):

地基① · 队列里就三类「活」(下面反复提到)

活的类型抓什么快慢
单视频快活
scrape_video
只抓一条具体视频(快车道按规则点名的那条,job 里带它的 url——通常是「正在冒新评论的热视频」或「近 6h 冒过高意向的视频」)底下的评论,且是增量(只取比上次新的)快 · ~5 秒/条
慢整号活
scrape_source
不点名具体视频,给的是一个号:去它主页捞最近 ≤20 条视频,再逐条把每条的评论都抓一遍(抓哪几条由号当下决定)慢 · 中位 23 秒、最慢 211 秒
高意向注入活本质也是单视频快活,但因「这视频近期冒过高意向」被特批插队(近期 = 近 6 小时,为什么是 6h 见 B 段;机制见 B)快 · ~5 秒/条
📐 本段【地基】= 纯"现状·系统现在怎么转",不带改动编号。上面三类活、下面 pri 排队,都是当下事实。「这些插队/降档分别是哪个措施加的(#363 / #366 / #381 时间线)」全部挪到下方 B、C 段讲——读地基时先别管编号,只看"现在怎么转"。
跟一下两个最容易绕的点:
1. "指定视频"到底怎么指定?=按抖音给每条视频的唯一编号 aweme_id 点名抓那一条。谁来点名 = 快车道 / 高意向注入 / UI「抓这条」,它们把一个 aweme_id 写成一行 scrape_video 活。所以"单视频快活"永远只盯一条视频,不碰这个号底下别的视频。
2. tier-0 / tier-1 是"号"的分层,不是"活"的分层。单视频快活、高意向注入活都不分 tier(它们只认一条视频);只有"慢整号活"才看 tier——这个是 tier-1(优质、抓得勤)还是 tier-0(普通、抓得稀)。tier-1 是怎么来的?auto-tier1 cron 每天把"近 3 天高意向 ≥5 条"的活跃号自动升上来(对称的自动降级见下方 ⑤/⑦ #365);tier-0 是默认档、绝大多数号都在这。

地基② · 这些活怎么排队跑(pri 优先级 = 号码牌)

每个活贴一张「号码牌」priority,worker 严格从小号往大号领,同号牌内先到先得。越急、越快、越该趁鲜的,贴越小号:

号码牌谁贴这号(入队来源)含义
0高意向注入 · vip-rescan · UI「抓这条」(运营在后台仪表盘上手动点「立即抓取这条」的按钮)最优先,最该趁鲜抢
1常规单视频快活(fresh-catch 快车道)快,先放走
3tier-1 慢整号活 · rescan-recent慢,让到快活后面
5tier-0 每小时轮抓 · lead 资料(给某个潜在客户建档时顺带触发的抓取,scrape_lead_profile,没指定 pri 就吃默认 5)最次,量大不急
这四档落到"实际多久轮到"(具体快慢时间):
· pri=0 高意向注入:插最前,空队列时秒级 ~ 1 个 tick(2–3 分)就被领走。
· pri=1 常规快车道单视频:执行~5 秒/条;排队中位 0、尾巴(p90) ~2 分。
· pri=3 tier-1 慢整号:执行中位 23 秒、最慢 211 秒/个;让到快活后面,实测 pending 最老 ~9 分。
· pri=5 tier-0 每小时 + lead 资料:只在上面三档全空时才轮到 → 实测能积压到 12 小时没人抓(就是 ⑤ 总根因里被饿死那批)。
("lead 资料" = 上表 scrape_lead_profile:识别出一个潜在客户后,系统顺手排一条活去抓这个用户的主页/视频补全画像,它没单独设优先级,就吃了默认 pri=5。)
这套 pri 是 6-16 改动前就有的吗?—— 机制本就有,但 #363 动了两处(这就是 Leg B / C 落在 pri 上的地方):
号码牌6-16 改动前现在(#363 后)
0vip-rescan、UI 手动+ 高意向注入 ← 新增
1常规快活 + tier-1 整号活(挤同一道)只剩常规快活
3基本空着tier-1 整号活(从 1 降来)、rescan-recent
5tier-0 轮抓、lead 资料不变

就两处变化:tier-1 整号活:pri 1 → 3(原来和快活挤 pri=1 同一道、堵快活,这就是 Leg C 快慢分道);② 新增 pri=0 高意向注入(原来没有,这就是 Leg B 破鸡生蛋)。其余不变。

📊 pri 排队泳道(worker 严格按号码牌从小到大领,号越小越先被抓)
pri=0 注入
秒级被领
pri=1 快活
~5 秒
pri=3 整号
让到快活后
pri=5 tier-0
饿死·积压 12h

↑ worker 永远先把 pri=0 领光、再 1、再 3,上面三档全空了才轮到 pri=5 → tier-0 被饿死(⑤ 总根因的机制)。

怎么定的 / 怎么跑的:没有配置表、运营不可调——priority 是散在 7 个入队点的硬编码(列 DEFAULT 5),要改得改代码走 PR。worker(~30s/轮)调认领 RPC,核心 = WHERE pending AND scheduled_at≤now AND attempts<3 ORDER BY priority ASC, scheduled_at ASC FOR UPDATE SKIP LOCKED(严格 pri 小→大、同级先到先得、并发安全)。领到即开抓;卡死(>8min)被扫回重排;attempts 到 3 被排除=永久 pending 墓碑(P0-d 清的就是它)。
⚠️ 关键副作用:纯抢占、pri 之间没有防饿死——pri=5 只在 0/1/3 全空时才轮到 → 能积压 12 小时;tier-1 一胀大就把低 pri 饿死(这是 ⑤ 总根因的机制)。

B · Leg B 破鸡生蛋(#363):治「冷视频上的高意向评论,第一条几乎必慢」

先回顾:Leg B = 「派活」那段路 —— 评论已经存在了,但系统迟迟没派出一个活去抓它。本段治的就是冷视频上这个"迟迟没人派活"。

【问题】一条视频要先进「快车道」才会被频繁单独复扫;而进快车道的门槛是——它的评论得在 60 分钟内被我们新鲜抓到过一次。可冷视频(老视频 / 不活跃号底下的)只能等慢整号活几十分钟~几小时扫一遍,永远赶不上 60 分钟 → 永远进不了快车道 → 它上面新冒的高意向评论第一条几乎必慢。死循环:要被快抓得先进快车道,要进快车道得先被快抓(「鸡生蛋」)

↑ 拗口的词跟一下:「快车道」=每 2~3 分钟挑一批「正在冒新评论的 top 100 视频」单独复扫的机制(详见 B-3);「60 分钟门槛」=只有被我们在评论冒出 1 小时内抓到过的视频才算"够格"上这条快车道。

【改动】不再死等门槛。只要一条视频近 6 小时内冒过高/中意向评论,就直接把它塞进快车道、还插在最前面(pri=0)优先抓——「破鸡生蛋」= 直接抱它上车,不等它自己够 60 分钟的格。

这个「6 小时」是怎么定的、要不要改?

6h 的由来:注入要圈"刚冒过高/中意向的视频",6h 是个"近期"窗口——够宽,半夜冒的意向到白天还能补上。

实测发现它的毛病是"太长":高意向视频天生是老·常青视频(实查"曾产高意向、还活着"的视频全部 >4 天龄)。一条视频 6h 内只要有过一条高意向评论,就被每个 tick 重选注入一次 → 6h ≈ 120–180 个 tick → 同一条被反复抓 80 次、100% 抓 0 新。

但核心病不在 6h 长短,在"每个 tick 都重注一遍"。缩到 2h 只是按比例砍空跑(治标);根治靠"注入去重"(同一视频注入过就别每 tick 重派)——这已由 #381 落地(A0 清单里那条)。所以 6h 维持不动。

去重会不会把我们关注的视频也抓慢?不会——退避是"自适应",不是"抓一次就停"。退避按【每条视频】记账(empty_streak):连抓 3 次都 0 新才开始拉长间隔(9→18→30 分钟),一冒新评论立刻清零、恢复每 tick 勤抓。所以真在不断冒评论的活跃视频永远不空手、永不退避、频率不降;被降频的只有"冒过一波后安静下来"的(实测那反复 80 次正是这批,100% 空手)——对它们降频一条 lead 不少抓、只省白跑。后续旋钮:可给高意向视频设更短的退避上限(如封顶 10 分钟)。
▸ 工程精确版(改了哪个文件 / 参数 / 阈值)

C · Leg C 快慢分道 + 空跑退避(#363 + #366):治「活派进队列后排太久 + 反复空扫」

先回顾:Leg C = 「排队执行」那段路 —— 活已经派进队列了,等 worker 领走真正去抓。本段治的就是这个排队:别让慢活堵快活、别反复空扫白占位。

【问题①·排队】活派进队列后 worker 一个个领。原来慢整号活(23~211 秒)和单视频快活(5 秒)挤在同一条号牌道(都 pri=1——前面卡一个慢整号,后面快活全得干等,实测排队中位 ~4.6 分钟。

【改动① · #363 快慢分道】把慢整号活降一档(pri 1→3,让 5 秒的快活先走、别被慢活堵。实测典型延迟 median −67%(见 D);但极端尾巴 p99 反被注入洪水拖坏 → 已由 #381「注入去重」补上(见下方改动③)。

【问题②·空扫】很多视频被反复复扫却抓不到新评论(实测近 24h 复扫 88,455 条、77% 抓 0 新),白占 pri=1 的位置、加重排队。

「空扫」到底算 Leg B 还是 Leg C 的问题?—— 两个来源,分开治:
· 来源一(C 自己的):常规快道把"早冒过评论、现在安静了"的视频反复复扫 → 抓 0 新。这是本段 #366 退避治的。
· 来源二(B 制造的):破鸡生蛋的注入洪水每 tick 重派同一批视频(见 D + A0 #381)→ 也是空扫,但根在 Leg B。
所以"空扫"是症状、根有两个:C 的常规复扫(#366 治)+ B 的注入重复(#381 治)。

【改动② · #366 空跑退避】一条视频连抓 3 次都 0 条新评论,就把它下次复扫往后推(9→18→30 分钟封顶);一旦又冒新评论立刻清零、恢复勤抓

↑ 拗口的词跟一下:「退避」=越扫越没货就越少去扫它、省得空跑;靠 videos 表新加两列记账:empty_streak=连续抓 0 新几次、next_fast_lane_at=推到几点才允许再进快车道。
9→18→30 这三个数怎么来的?= 指数退避(exponential backoff,标准重试算法)。每多空手一次、间隔翻一倍(9×2ⁿ:9→18→30,第三步本该 36 被 30 封顶)。
· 9 分钟起步:比 3 个 tick(≈9 分)略长——给视频留点时间真冒出新评论再去,不浪费。
· 30 分钟封顶:再久就交给"巡整片园子"的全量轮兜底,快道不必死磕一棵安静的树。
⚠️ 诚实说:指数退避是标准模式,但 9 / 30 这俩具体值是工程"按 tick 节奏 + 全量轮兜底周期"拍的默认值,不是理论推导的最优解(env 可调 FAST_LANE_BACKOFF_BASE_MIN=9 / _CAP_MIN=30,嫌慢调小、嫌费调大)。
▸ 工程精确版(文件 / 参数 / 阈值)

改动③ · #381 注入去重(2026-06-17):把 pri=0 高意向注入也纳入退避 —— 治 D 段那座「注入洪水」

【为什么要补】#366 退避当初故意豁免 pri=0 注入(怕压住破鸡生蛋该抢的活)。全天复核坐实这豁免错了——注入洪水(80 次/6h、0 新、把 p99 拖到 80 分钟)的实测拆解见上方 D 段,此处不重复。结论:豁免要去掉。

【改动】去掉那条豁免,让高意向注入跟普通快活一样退避——注意是「自适应」,不是粗暴的「摘过一次就再也不去」。

↑ 果园比方接上 B 段:原来"这棵树冒过高意向果"就每 3 分钟去摘一趟、不管摘不摘得到;现在它跟普通树同一个规矩——连去 3 趟都空手才拉长间隔(9→18→30 分钟封顶),一旦又结新果立刻清零、恢复勤摘。关键:退避记在每棵树上videos.empty_streak),任何一条路摘到这树的新果都清零 → 真在不断结果的好树永不空手、永不退避、频率一点不降;被拉长的只有"冒过一波后安静下来"的树(注入空跑的正是这批)。所以它不会把"我们关注的活跃视频"抓慢

📊 数据依据 · 上线后头 25 分钟时间线(部署 2026-06-17 11:48 北京时间,直查 scrape_jobs / videos

下表时间都是 2026-06-17 当天;Z = UTC(0 时区),+8 小时 = 北京时间,已在每行标出北京时间。

测量方法 · 诚实说明:下面是上线即时的 leading indicator(注入创建率 + worker 槽占用 + tier-0 积压),不是 D 段那种全天 24h 的 p99 终判——p99 是 24h 滚动尾巴指标,25 分钟动不了,要等下一个完整全天窗口再复核。(自查纠错:首测因分页查询没加稳定排序,一度误读成"创建率瞬间归零";给查询加 .order 重测后修正为下面的渐进衰减——这条曲线才和"连 3 次空扫才起退避≈9 分钟"的机制自洽。)
时刻pri=0 注入创建率(每 10min)worker 运行槽(瞬时)tier-0(pri=5)积压
部署前 · 11:43 (03:43Z)~180(≈18/min 持续灌,对得上全天 26995)pri=0 霸占 6/11 槽353 个 · 最老 13.0h
+12min · 12:00 (04:00Z)65(−64%)352 · 12.8h
+22min · 12:10 (04:10Z)~22(−87%,仍在降)pri=0 = 0;pri=5 拿 10/16 槽(62%)350 · 12.7h
📊 #381 前后一眼对比(部署 03:48Z → +22min)
红 = 前(坏)绿 = 后(好);每项都附一句"为什么这是坏 / 好"。
注入创建率(每 10min)· −87%
180
22
tier-0 最老积压 · −60%
13.0h
5.2h
pri=0 注入活占了多少 worker 工位 · 清零
6/11 槽
为什么坏:这 6 个工位全在跑「100% 空跑」的注入活 = 一多半产能空转,把别的活(尤其 tier-0)饿死。
0/16 槽
为什么好:注入洪水没了,腾出的工位给了之前被饿死的 tier-0,它终于能排积压(这也是 tier-0 积压从 13h 降到 5.2h 的原因)。
⚠️ 这是上线即时先行指标,非 p99 终判(p99 要等下个全天窗口)。明细见下表 + 诚实边界。
大白话读这张表:① 注入洪水正按设计退潮——创建率从 ~180/10min 渐进降到 ~22(−87%)、还在往下(每棵高意向树陆续连摘 3 次空手后进退避)。② worker 产能腾出来了——部署前 pri=0 霸占 6/11 个运行槽全耗在空扫上,现在 pri=0 清零、被饿的 tier-0(pri=5)拿到 10/16 槽(62%)。③ 注入也退避坐实——退避中视频从 +12min 的 425 涨到 +25min 的 438,新增的正是高意向视频(empty_streak=3/4 那两档在涨)。
诚实边界 · 别过度解读tier-0 积压"深度"还没排空(仍 350 个、最老 12.7h)——这是存量在被啃(最老龄 13.0→12.7h 已掉头往下),不是 25 分钟能清的;它现在拿到多数 worker 槽,预计未来几小时积压曲线才看得出降p99 改善要等下一个全天窗口复核。这一步只证明机制按设计在转、方向对,没证明 p99 已修好。
🔬 上线后追加验证(06-17):「判空」里有 33% 是假的,漏了真评论(含中意向)

起因:运营反馈中高 leads 变少。循线去查——"快道判 0 新的视频,后来全量轮有没有补到、抓那一刻就已经存在的评论"。

结果(近 12h 抽 120 个判空视频):

· 67% 是真空:确实没新评论可抓(结论不变)。

· 33% 是假空:抓时评论已存在、却被快道漏掉,晚 50~553 分钟才由最慢的全量轮补到,漏的里含中意向 lead

根因:快道增量抓取「整页全老就停 + 只看前 50 条」,假设抖音按时间倒序返回;但抖音 web 评论接口默认按热度排,新评论被埋在后面够不到。

要更正前文一处口径:退避省的是浪费没错,但"0 新 = 纯空跑、不丢 lead"只对那 67%;剩下 33% 的真评论被推给最慢的全量轮 —— 这才是"中高 leads 变少/变慢"的直接根因

退避只是治标,这个早停 bug 要单独修 —— 就是 A0 清单里的 #413(PR 待合;修好后这些视频抓得到东西、empty_streak 清零、自然不再退避)。验证脚本 _verify-fastlane-earlystop-bug.ts

↑「真空 / 假空」大白话啥意思:快道抓完报"0 条新评论"就判这视频"空"。判空有两种真相——
· 真空=真没新评论可抓(早抓过了 / 压根没人新评论),说"空"是对的、不亏 lead。
· 假空=其实有新评论、抓的那一刻就在树上,但快道只扫了"最显眼的前几枝 + 前 50 条"(抖音默认按热度排),没绕到后面那枝新结的,就误报"空"——果子在的、被漏了,过 50~553 分钟才由"绕整棵树的全量队"补摘走,里面有中意向客户
怎么分辨的:对每个判空视频查——有没有评论满足「发表时间早于快道这次抓取(抓时已在)」且「入库时间晚于快道抓取(却是后来别的扫补的)」。有=假空(当时够得着却漏了),没有=真空。
📊 判空真假占比(近 12h 抽 120 个判空视频)
真空 67%
假空 33%
漏真评论·含 lead
部署锚点:squash 16bcfc233 / Fly worker v306(已 /health 探活)。改动:scrape-hot/route.ts(hiIds 纳入 next_fast_lane_at 退避过滤)+ worker/queue.py(去掉 high_intent 豁免)。无 migration。急停开关 HOT_FAST_LANE_BACKOFF=0(全关退避)。

D · 成效实测(全天 24h 对比:部署前 06-15 04:00→06-16 04:00 vs 部署后 06-16 04:00→06-17 04:00)

⚠️ 口径已升级:从"8.5h 低峰窗口"换成"全天 24h"——更诚实,但结论也跟着变了。原先用 04:00–12:25 那 8.5 小时对比,毛病是那段正好是低峰(北京下午),把前后都美化成"median 0 秒、p90/p99 全绿"。换成完整 24h(含高峰)后:median 改善依旧实锤,但尾巴 p90/p99 的故事翻了。两边各 24h、都按 scheduled_at 落在窗口内、started_at 非空(已认领)统计。
先看懂这三个数(median / p90 / p99 怎么读):把所有活的等待时间从快到慢排成一队——
· median(中位数)=站正中间那个,一半比他快、一半比他慢 =「典型情况」。
· p90=排在 90% 位置那个,只有最慢的 10% 比他还慢 =「尾巴(较差)」。
· p99=排在 99% 位置,只有最惨的 1% 比他更慢 =「极端最差」。
为啥不用平均?平均会被个别超长的极值拉偏;分位数才看得清真实分布。

Leg C 快慢分道:中位大赢、尾巴没赢(全天口径下的翻车点)

scrape_video 入队→被认领等待medianp90(最慢 10%)p99(最惨 1%)
① 06-15 部署前 (n=26544)233.7s454s1151s
② 06-16 注入洪水峰·#381 前 (n=51170)75.5s486s4596s
③ 06-17→18 #381 后 ~21h (n=27269)57.8s1138s2191s
大白话读这张表典型情况(median)从 3.8 分压到 1.2 分(−67%)——快慢分道确实让大多数快活先走了。优先级分布坐实:部署前有 6355 个整号活混在 pri=1 跟快视频抢道,部署后整号活搬到 pri=3(3160)、pri=1 里的整号只剩 112但 p90 基本没动、p99 反而从 20 分钟炸到 80 分钟。为啥?看同一份数据的另一个数:pri=0 高意向注入活从全天 905 个暴涨到 26995 个(30 倍)——破鸡生蛋的注入洪水(每 tick 重注,见下)在 pri=1 前面又垒了一座 pri=0 大山,典型活照样快,但挤在洪水里的那 1% 倒霉蛋等得比以前更久。
(注:p99 里可能掺了少量 zombie 活被重排、started_at 取最后一次认领造成的虚高;但方向——"尾巴没改善、注入洪水是主因"——跟全部其它证据一致。)
三窗连看(含 #381 后的全天复核,诚实版)

· ①→②(#363 快慢分道):median −67%(典型大赢);但注入洪水把 p99 从 ~19 分钟炸到 ~77 分钟(尾巴翻车)。

· ②→③(#381 注入去重,6-17 上线):洪水退了(活数 51170→27269)、median 史上最好(57.8s)、p99 从洪水峰 4596 砍到 2191(−52%)、高+中 leads 回到 446(占比 8.3%)。

⚠️ 但尾巴还没回到基线:p99 仍 ~2× 基线(2191 vs 1151)、p90 反而 454→1138 变差。最可能的残余原因 = 早停 bug——#381 退避更狠了,而那 33%「假空」(真评论被漏,见下方 🔬)被退避推给最慢的全量轮、拖长了尾巴。

→ #413 早停修复已于 2026-06-18 合并部署,正是治这条尾巴;效果待下一个全天窗口复核(届时再更新本表 ③ 上方的 p90/p99)。

🌗 #413 上线当晚·方向性预览(2026-06-18,非终判)

先界定这次只看了什么:只复测了上面 🔬 那个「假空率」指标(抓时已有评论却被早停漏掉的比例),没看 p90/p99 尾巴——尾巴要等满 24h 全天窗口才不被低峰美化(同 8.5h 假赢教训)。

结果:假空率 33% → 8%(post-fix 全程 10h 窗口、11044 个快道完成活、抽 120 个判空视频复验)。早停这半明显起效——单页全老就停导致的漏抓基本治住。

残留 8% 长什么样(埋给终判的线索,非定论):样本里还在漏的多是「评论已存在 3~6 天、被热度排序埋到前 50 名之外」那种——这不是早停能治的,是 max_comments=50 截断(另一半 B 方案的靶子)。所以残留偏向「截断型」而非「早停型」。

下一步:明天北京 12:00 后 ④ 全天窗口闭合,复核 p90/p99 是否回基线(454/1151)、并据残留性质定 B 方案(前 50→150)做不做。届时更新本表。

这座注入洪水到底是什么(部署后 8.5h 切片实测,06-16 04:00–12:25)

这段窗口里,pri=0 高意向注入活跑完 9039 个(= scrape_jobs 表中 priority=0、标 high_intent、在此窗口完成的单视频活条数;全天口径为 26995 个)。但这 9039 个活只摊在 112 个不同视频上 —— 平均每条被重复抓 80.7 次9039 ÷ 112 ≈ 80.7)。三点说清这洪水的性质:

定性:这不是 #366 退避坏了(#366 按设计放过 pri=0),而是 Leg B 破鸡生蛋自己制造的新空跑 —— 它把"延迟问题"换成了"空跑问题"解药 = #381 注入去重(已上线 6-17;机制 + 上线 25 分钟实测见上方 C 段「改动③」,此处不重复)。

📥 机制前后 · 实际拉到的高/中意向评论数(全天 24h 对比)

窗口入库评论总数高意向中意向高+中高+中占比
① 06-15 全天 (部署前)4080742653398.3%
② 06-16 全天 (#381前)5291932803737.0%
③ 06-17 全天 (#381后)5361973494468.3%
①→③ 变化+31%+31%+32%+32%8.3%→8.3%
诚实边界(全天口径更冷静):高+中从 339→373(+10%)、高意向 74→93(+26%)。但当天入库评论总量本身涨了 30%,而高+中占比反而从 8.3% 掉到 7.0%——说明这 +10% 基本是"评论盘子变大"顺带带上来的,机制本身没把"高意向命中率"提上去。⚠️ 这同时修正了原版的过度解读:原先 8.5h 窗口看到"高意向 +89%、近翻倍",全天一摊只剩 +26% 且占比下降——那个"翻倍"是低峰小样本的噪声、不成立。要看 B/C 机制真效果,得多日累积 + 剔除评论总量波动。
更新(③ 06-17 / #381 后):高+中 回到 446、占比也回到 8.3%(vs 基线 +32%)——06-16 占比掉到 7.0% 是注入洪水期的暂时现象,#381 退潮后就回来了。但仍需多日看稳态。

E · 新发现:评论拉取还是很久的真尾巴 —— 不是排队,是「老视频覆盖盲区」

端到端「高意向评论 comment_time → 入库」实测(近 36h,n=124):median 34 分(典型还行),但 >1h 占 47%、>6h 占 42%、>12h 占 38%——这条重尾就是日报里那批标 expired_at_claim 被跳过没触达的 lead。按 source tier 拆开,真因和直觉相反

source tiern>6h 慢尾占比median 时延
tier-0(pri=5 每小时)617%4 分 ← 居然最快
tier-1(pri≤3 快车道)11042%34 分
无源(孤儿视频)863%99 时
样本量诚实说明:这是「近 36h」滑动窗口快照(隔几小时重测会 ±2分/±2% 自然漂移,结构稳定)。⚠️ tier-0(n=6)、无源(n=8) 样本太小,那两行的百分比只能当方向参考、别当硬结论;统计上扎实的只有 tier-1(n=110) 的 40–42% >6h 慢尾。即「慢尾主要压在 tier-1 老视频」这个结论可靠,但「tier-0 比 tier-1 快」需更大样本再坐实(方向上成立)。
慢尾压根不在 pri=5 那条 12h 积压道上(tier-0 中位才 4 分)。42% 的慢尾全在 tier-1 的老视频(龄 6–11 天、时延 6h~7 天)。根因:tier-1 整号活只重扫该号最近 ≤20 条视频,一条视频过几天就被挤出"最近 20"、从此不再被定期重扫;但它底下还在冒新评论,这些评论进不了任何快车道(快车道要求"该视频 48h 内已有评论入库",老视频没有)→ 鸡生蛋升级版。直到某次慢节奏重扫终于扫到,增量一次性把积压几小时~几天的评论全捞回。漏洞在"过去那段没扫",不在排队、也不在窗口往回看多久。

F · 解决方案:4 条路,现在各跑到哪了

E 段那条"38% 老视频慢尾"怎么治?验证过 4 个方向,下面逐个说人话、再标现在的真实状态(不是计划、是查过库的实况):

把快车道的 48 小时窗口拉大到 72 / 96 小时  →  不做(已否决)

什么意思:快车道只盯"近 48 小时内冒过新评论"的视频。直觉会想:那把 48 拉到 96,不就把老视频也圈进来了?
为什么不做:模拟过——窗口拉到 96h,候选池涨 46%,但多出来的全是已经冷下去的老视频(大半还被退避挡在外面),真正救回的慢尾只有 0–1 条。窗口管的是"往回看多久",可这些视频的病是"过去那段压根没人去扫",看得再远也没用。方向错,不做。

给"老的高意向视频"单开一条低频回扫  →  ✅ 已上线在跑,最对症

什么意思:专门挑那些"以前出过高/中意向、但现在掉出了 48h 快车道"的老视频(数量不多,是 Pareto 钓点),单独给它们排一条慢班车——每条视频最多 2 小时扫一次,把"几小时~7 天才被扫到"的盲区压成"保底 2 小时一扫"。
现在跑得怎么样:已上线(PR #377,cron /api/cron/cold-intent-rescan,每 20 分钟一轮,走 pri=3)。6-17 首份快照实测:它的空跑率 65%,是所有回扫通道里最低的——反过来说 35% 的轮次真抓到了新评论,是 4 条通道里唯一"打中"的,对症。代价:它走 pri=3,把 pri3 积压从 96 顶到了 384(所以下面 ④ 变急)。

修"孤儿视频"  →  暂没单独做(② 可能已顺手覆盖)

什么意思:库里有一批视频认不出是谁发的source_account_id 是空的),任何"按号抓"的活都覆盖不到它们,只能烂在那——E 段那 8 个孤儿视频中位慢到 99 小时就是这种。
现在状态:没单独动手。因为 ② 是"按视频"撒网、不按号,孤儿视频天然就被 ② 网进去了 → 先看 ② 跑一段够不够,不够再单独按作者把来源回填上。

pri 防饿死(治另一个病:tier-0 被饿死、积压 12 小时)  →  没做 · 已变急,该上了

什么意思:worker 严格"小号牌先领",pri=5 的 tier-0 活只在前面全空时才轮到 → 能积压 12 小时没人碰。两个治法:aging(一个活等太久就自动升号牌往前插)或配额(每批留 X% 名额给 pri≥5,不让它彻底饿死)。
为什么变急:② 那条 cold-intent 走 pri=3 上线后,又往 tier-0 头上压了一层——6-17 快照实锤 pri3 积压 96→384、tier-0 最老活仍卡 12 小时。所以 ④ 从"以后再说"提到了"该上了";要是 ④ 一时上不了,就得先把 ② 的 COLD_INTENT_RESCAN_MAX 调小、给 tier-0 泄压。

一句话推进结论:Leg C 把典型延迟砍了 2/3(median −67%)、但极端尾巴(p99)被破鸡生蛋注入洪水拖坏 → 头号补丁是注入去重;真尾巴的下一刀 = ② 已上线在跑(65% 空跑率、最对症)+ ④ pri 防饿死该提上来,而不是去改那个 48h 窗口。
方法注记:所有数字为 2026-06-15 当日直查生产库(comments / scrape_jobs / source_accounts)+ worker 活体 /queue/stats + Lark 采集快照卡。诚实边界:① 每日 tier 数变化库里无历史表、不可严格重建,本页用当前快照近似;② Leg C 的「8 槽悖论」已于 23:00 实查坐实=不是闲置,是 pri=1 队列常年积压 ~100 条 + 慢整号活占槽 + poison 活(见 Leg C);fly machines API 因 deploy token 无读权限未取到机器数,但 running 常态 8 + 78/分吞吐,有效并发 ~8;③ 僵尸判定用 7 天 / 高意向≥5(对齐升级线)。
Akke 内部调查 · Claude Code 协助 · 2026-06-15