14 KiB
测试优化分析
说明:这份文档保留作历史分析记录。当前线上执行基线与观察方法,统一以 当前线上最终Runbook.md 为准。
更新时间:2026-04-24 14:00
这份文档是干什么的
这份文档不是讲理想情况,而是把这次已经做过的单机压测结果,和当前现场“根本没真正跑起来”的现状,放在一起说清楚。
目的很直接:
- 先把已经验证过的参数结论留档
- 再把现在为什么看起来线程上限很高、实际只跑了很少线程说清楚
- 给后面继续优化的人一个明确顺序,别再一边主链没跑通,一边继续盲目加并发
一句话结论
早上那轮“只测一台大陆机器”的压测,已经得出过一个单机最优值:
mainland-controller-01单机跑时,当前最优参数是35 进程 / 900 线程
但这不等于项目现在已经能按这个参数稳定跑。
按 2026-04-24 13:22 左右控制面看到的实时状态,这套链路目前更像是:
- 任务还挂着
- 页面也还能显示“运行中”
- 但真正参与执行的只有很少几个桶
- 总体上属于“没有真正跑起来”
所以现在的主矛盾不是“继续把线程调大”,而是“先让主流程真的跑起来”。
这次单机压测是怎么测的
这轮压测不是全链路压测,而是一个故意收缩后的测试环境。
当时做了这几件事:
- 先停掉
121.204.244.248,也就是mainland-worker-01 - 只保留
mainland-controller-01单机承担检测 - 停掉 controller 上的
domaincheck-sync-agent.service - 不再继续额外增加新的 Redis 限制动作
- 直接在 controller 本地数据库里看 60 秒窗口真实完成量和更新量
这么做的目的,不是模拟线上真实规模,而是先排除多机互相干扰,看单机能跑到什么水平。
单机压测结果
压测时间段大致是 2026-04-24 05:14 - 05:28。
当时 controller 本地 60 秒窗口结果如下:
| 参数 | 60 秒完成量 | 60 秒更新量 | Redis 连接数 | 内存已用 | 可用内存 | 实际活跃 worker |
|---|---|---|---|---|---|---|
35/900 |
4092 |
22267 |
751 |
73.6G |
54.3G |
35 |
40/1000 |
1885 |
1544 |
793 |
75.1G |
52.9G |
40 |
45/1100 |
388 |
11347 |
818 |
75.7G |
52.3G |
45 |
50/1200 |
0 |
12118 |
823 |
75.9G |
52.1G |
45 |
压测结论
从这轮结果里,可以直接得出 4 个结论:
1. 单机最优值不是越大越好
当前这套链路下,35/900 明显优于后面的更大参数。
也就是说,继续加进程、加线程,并没有带来更高完成量,反而更差。
2. 当前单机稳定上限大约在 45/1100
45/1100 还能勉强活住。
但它已经不是“跑得更快”,只是“还能挂着不死”。
3. 50/1200 已经没有意义
虽然当时把参数抬到了 50/1200,但最终实际只活成了 45 个 worker,而且完成量已经掉到 0。
这说明不是配置没写进去,而是链路已经先撞到别的瓶颈了。
4. 当时真正的瓶颈已经不是 Redis
从这轮压测看,Redis 连接数有上升,但没有先爆。
更像是外部检测链路本身先撑不住了,尤其是:
- 注册检测
- 代理池质量
- 会话切换抖动
为什么当时测出来 35/900,现在页面却只剩 52 线程
这就是最容易误判的地方。
早上压测结论成立的前提是:
- 只测 controller 单机
mainland-worker-01被停掉sync-agent被停掉- 现场是专门为压测收缩过的
而现在你看到的实时状态,已经不是那个压测场景了。
按 2026-04-24 13:22 左右接口返回的状态,现在的现场是:
detect/job/active里的活动任务还是job_id=1- 这条任务从
2026-04-21 23:30:42就已经是running raw_items_pending=9478raw_items_running=1raw_items_completed=4996raw_items_failed=486
同时,runtime/status 给出的聚合状态是:
参与服务器:4参与进程:4参与线程:52运行中:52线程上限:52 / 2701
这几组数字合起来说明的不是“系统已经高效跑起来”,而是:
- 页面还能看到一些参与桶
- 但真正持续工作的执行面很薄
- 大量任务还躺在队列里,没有被健康地持续消化
当前为什么可以直接判断“根本跑不起来”
不是因为页面数字小,而是因为几条关键事实同时出现了:
1. 活动任务太老
当前活动任务还是 2026-04-21 开出来的老任务。
如果主链真的健康,它不应该拖这么久还挂在 running。
2. 待处理量还很大
当前还剩:
9478条原始 pending3779条 claimed1028条 running backlog
但真正展示出来的活跃线程只有 52。
这个比例说明队列不是空了,而是消化不动。
3. 当前节点自己根本不跑本机 worker
当前 overseas-control-01 的 runtime/status 里明确写着:
worker_online=falseworker_process_count=0worker_runtime_message=inactive/dead
也就是说,现在这个页面看到的“运行中”,本来就不是本机在跑,而是靠远端汇总。
4. 远端参与桶很少,而且口径不稳
现在控制面聚合出的参与节点只有:
mainland-worker-01mainland-controller-01-kmainland-controller-01-amainland-controller-01-s
这和早上单机压测时的 35 个 worker,根本不是一个级别。
所以你现在看到“线程上限 2701”,不要被这个数字迷惑。
它只是汇总上限,不代表这些线程真的都在跑。
现在最像什么问题
如果用人话说,现在最像下面这种情况:
- 任务队列里还有很多活
- 但是执行面只剩很薄一层还在动
- 页面还能看到“运行中”,所以看起来像没完全死
- 可真正吞吐已经低到接近“没跑起来”
所以这不是单纯的参数问题,而是主流程状态已经歪了。
当前最该先做的事
下一步优化顺序建议固定成这样:
第 1 步:先恢复“能持续跑”
先不要继续加进程、加线程。
先确认 4 件事:
- 当前到底是哪几个节点真的在跑
mainland-worker-01是不是还应该继续停着- controller 上当前实际活着多少 worker
- 老任务里这些
claimed/running有没有大量卡死项
第 2 步:把老任务和会话问题理顺
现在这条 2026-04-21 的老任务已经拖太久了。
要优先确认:
- 是不是有很多旧
session_replaced - 是不是有大量任务项一直卡在
claimed/running - 是不是页面显示还在跑,但实际 worker 已经不工作了
第 3 步:确认代理链是不是主瓶颈
早上单机压测已经说明,Redis 不是先撞墙的那个点。
下一步更值得盯的是:
detect_register的真实完成率- 代理池是否经常空
- RDAP 访问是否大量超时
第 4 步:只有主链恢复后,才重新做性能优化
13:48 补充结论
这轮又确认了一件非常关键的事:
mainland-worker-01不是“已经彻底消失”,而是“被标记为停用,但之前还在继续上报运行态”
后来实际做了两步处理:
- 先通过远端
ops job让mainland-worker-01本机执行systemctl stop domaincheck-worker - 再把控制面的状态汇总改成:只要节点在
ops_managed_nodes里是is_enabled=false,就不再算进在线 Worker、参与节点和活跃线程
处理完成后,控制面实时口径已经从“2 台参与节点 / 2 个检测进程 / 2 线程”收到了:
参与节点:1参与进程:1运行中:1- 只剩
mainland-controller-01
这说明前面那种“明明已经准备单机测了,页面还一直把停用节点算进去”的问题,确实是状态口径 bug,不是现场真的还有两台健康执行机一起在跑。
所以从现在开始再看单机测试结果时,要以这条新口径为准:
mainland-worker-01已停用,不再参与单机压测统计- 当前有效执行面只剩
mainland-controller-01
等主流程恢复成“真的能持续吃队列”之后,再拿 35/900 作为第一版基线。
到那时可以按下面顺序再调:
- 先验证
35/900在恢复后的现场还能不能稳定 - 如果稳定,再测
40/1000 - 只有吞吐确实提高了,才继续往上加
这份文档的最终结论
可以把这次结果浓缩成两句话:
第一句:
- 单机压测已经证明,当前代码和链路下,
mainland-controller-01的最佳参数是35 进程 / 900 线程
第二句:
- 但当前线上真正的问题不是“参数不够大”,而是“主流程根本没有持续跑起来”,所以现在继续加线程没有意义
后面再优化时,应该先解决“为什么只剩 52 线程在动”,再谈如何把吞吐重新抬高。
2026-04-24 13:35 补充结论
这份文档写完以后,又继续往下排了一轮,现场有两个非常关键的新结论。
1. 52 线程里有明显口径错配
后来继续核对后发现,页面里那组:
参与服务器:4参与进程:4参与线程:52
并不是来自 detect_job_items 真表本身。
真实数据库里,job_id=1 其实只剩:
1条running
而且这条记录最后更新时间还停在 2026-04-22 15:00:56,本质上已经是老僵死项。
真正把页面抬到 52 的,是一条口径 bug:
- 当前 active job 还是老任务
detect-20260421232649-acfa3d - 但控制面又拿到了别的 sync job 的 runtime overlay
- 两套数据被硬合到了一起
简单说就是:
- 任务表是老 job
- 线程数却借用了别的 job 的运行态
2. 这条口径 bug 已经修掉了
现在代码已经补成:
- 只有 runtime overlay 的
job_code / job_id和当前 active job 对得上时,才允许覆盖queue_health - 对不上时,宁可退回真实任务表,也不再把别的 job 的运行态硬套到当前页面上
修完并重启海外控制面 API 之后,实时口径已经从之前的 52 收回到了:
参与节点:2参与进程:2参与线程:2
当前这 2 个真实信号分别来自:
mainland-controller-01那条老runningmainland-worker-01当前 heartbeat 上报的1条活跃线程
这说明一件事:
- 之前那组
52的确主要是错口径,不是实际吞吐
目前还剩的真实问题
虽然 52 -> 2 这一步已经收准了,但项目还是没有真正恢复健康。
当前还剩 2 个真实问题:
1. mainland-worker-01 明明已停用,却还在持续推运行态
当前控制面日志里还能持续看到:
121.204.244.248往海外控制面打runtime/debug-ingest- 同时也还在打
ops/agent/pull
这说明这台机器不是“旧残影”,而是还真的在线、还真的在报活。
所以“已停用”这件事,目前只是在托管配置层停了,但没有真正把它从 Agent / runtime 上报链里摘干净。
2. job_id=1 这条老任务本身也还没收口
当前老任务依然挂着:
job_id=1job_code=detect-20260421232649-acfa3dstarted_at=2026-04-21 23:30:42
而真实任务表里,它现在已经不是“很多线程在跑”,而是:
- 大部分还在
pending - 只剩 1 条老
running
这说明这条老任务本身也需要后续专门处理,不能继续长期挂在 running。
现在更准确的下一步
到这里为止,下一步就更明确了:
- 先把
mainland-worker-01真的摘掉。 - 再处理
job_id=1这条老任务的遗留running项。 - 等这两件事收完,再重新看当前真实执行面到底还有没有持续吞吐。
也就是说,现在已经不是“继续猜线程参数”的阶段,而是“先把错误执行面和老任务残留清掉”的阶段。
新增一版“单机性能模式”给注册检测
这次为了后面继续压单机吞吐,我已经在代码里补了一版只影响“注册状态检测”的性能模式。
它的目标不是改全局架构,而是先把当前最像瓶颈的那一段链缩短:
- 只改
detect_register - 不碰百度、360、站长、爱站、时光机这些步骤
- 保留当前版的连接复用和失败闭环
- 只把注册检测改得更像老版本那种“先尽快打出去,再说”
这版模式做了什么
打开后,注册检测会变成下面这个思路:
- 即使全局
allow_direct=false,注册检测这一步也允许直连 - 默认先连续直连
2次 - 这两次之间不再等代理补货
- 只有前面的直连没打通,后面才继续走代理兜底
简单说就是:
- 当前默认模式:代理优先,直连兜底
- 单机性能模式:注册检测直连优先,代理兜底
怎么开
这版先做成环境变量开关:
DOMAINCHECK_REGISTER_SINGLE_MACHINE_MODE=1DOMAINCHECK_REGISTER_DIRECT_STREAK_ATTEMPTS=2
当前默认建议先用这组:
进程:35线程:900DOMAINCHECK_REGISTER_SINGLE_MACHINE_MODE=1DOMAINCHECK_REGISTER_DIRECT_STREAK_ATTEMPTS=2
如果后面继续试更激进一点,再考虑把直连连打次数从 2 提到 3,但不建议一上来就抬。
为什么不是直接回退老版本
老版本真正有参考价值的是“链短、切得快”,不是它的实现本身更先进。
所以这次没有回退这几样东西:
- 没回退到
20s * 3的长超时 - 没回退到“注册失败也继续往后跑”
- 没丢掉当前的
Session复用
换句话说,这次是“借老策略”,不是“退老实现”。