Vertex 全自动多盒子刷流经验分享 + 不同盒子刷流效果评估

前几天捐入了 mteam ,有了一个月的 vip,不由自主的沉迷了一小段时间的 pt 刷流,现在我做一些总结水一贴,记录一下闲置盒子多的时候如何无脑全自动刷流吧,顺便简单看看哪家盒子刷流效果好。给大家提供一些参考的同时,如果我有哪里配置有问题或者有更好的方案也麻烦大家告知一下。

TL;DR

本身刷上传量还是挺随机的。vertex 自动刷,加上去找 mteam 成人免费大包手动加入(好像是一周刷新一个的样子,就是成人板块首页打开,包含“活動置頂”描述的免费大包)。这两个一起上。

节点使用一键脚本优化,目前来看 hz cax31 效果最好,我直接开了 5 个一起刷,每秒 200MB/s - 500MB/s,感觉按这个速度不到一周就可以毕业了

上 7 个盒子一起刷,能够几乎不用人参与做到大概一天刷 2T。这其中 netcup 是刷流效果最好的。另外,不知道一些人的盒子怎么做到上传几百兆每秒的,我这里有时候最高的也就单个种子二三十兆每秒,如果里面有什么秘密也请大家告知一下。

用到的盒子介绍与刷流效果对比

我用了多种类型的盒子,后面展示一下不同盒子的流量信息做点锐评。

TLDR: 下面的都不用看了, hz cax31 最好

TLDR:netcup 大法好,digitalocean 也不错。

这里的名字和下面配置的下载器名字对应

  1. buyvm
    1. buyvm las vegas ,加了 1TB
    2. Las Vegas - AMD RYZEN KVM - LV RYZEN KVM 1GB
    3. Las Vegas - Block Storage Slabs - LV Block Storage Slab - 1TB
    4. 似乎无流量限制
    5. 似乎不是 SSD
  2. dio
    1. digitalocean:免费(github 教育包的券)
    2. Basic / 4 GB / 2 vCPUs / 50GB 空间
    3. 4TB 流量
    4. 是 SSD
  3. hkpan
    1. 最近很火的 cnfaster HKL Storage ,1TB 存储
    2. 8TB流量限制
    3. 似乎不是 SSD
  4. hz
    1. CX22 | x86 | 2c/4G/40 GB | eu-central,按小时计费
    2. 虽然说可以自己加 block storage,但是太贵了,所以选择外挂了一个 1TB storage box,用cifs 挂载,算是网络文件系统。 https://www.hetzner.com/storage/storage-box ,按小时收费一个月 4 欧,io 性能算够用
    3. 大家都说 hetzner 刷流很猛,但我却刷不出来,是因为这不是杜甫吗?杜甫太贵了不想用杜甫
    4. 20TB 流量限制
  5. netcup
    1. 经典 1o 鸡
    2. https://www.netcup.com/de/server/vps/vps-piko-g11s-12m
    3. 1c/1G/30GB
    4. 无法扩容
    5. 是 SSD
  6. netcup-g11, netcup-g11-3t
    1. netcup RS 1000 G11 4c/8g/256GB
    2. netcup-g11:在系统盘上开的 qb 下载器
    3. netcup-g11-3t:我另外加了 3T 的空间用来刷大包,在这 3T 的空间上另外又启动了一个 qb 下载器
    4. 所以一个服务器两个下载器,这个服务器也确实对得起这两个下载器,刷流的数据是最猛的。
    5. 是 SSD
  7. netcup-vps-g11
    1. netcup VPS 1000 G11
    2. 4c/8g/256 GB,按小时收费
    3. 是 SSD

实时上传下载速度的话,截了一个 gif 大家可以自行感受。,这里两栏左边是上传右边是下载。这里的累计数据大概是1-2天的量。累计数据来看,netcup-1o 鸡这样一个小盘鸡都能两天刷 160G 的上传,已经超出我预期了,如果有佛系挂机党可以考虑。总体来说,全部盒子加起来差不多能做到稳定每秒 20-60MiB/s 的上传,一天能做到 2T 或更多的上传量。但是这里需要注意到,除了德国的节点几乎无限制,其他节点都是有流量限制的,我打算把流量刷完就关掉。

目前判断是存储是否是 SSD 对于刷流的效果有很大影响。

gif 仅代表瞬间状态,个人觉得看右侧的累计数据更靠谱(左边是上传量右边是下载量),用“上传量和下载量的比例”更能判断节点刷流质量。目前这些数据只是刷了大概 1-3 天的情况,过几周再看看。

qbittorrent

直接用这个脚本安装(https://github.com/jerry048/Dedicated-Seedbox) 之后,速度惊人,感谢大家提醒。

这比 apt install qbittorrent-nox 的快多了,以我的经历提醒大家,想要刷流,还是要尽可能利用这些脚本的优化效果。

qbittorrent 相关(废弃)

我没有用一键脚本,开机之后直接就是简单的 apt install qbittorrent-nox ,弄好下载器了。

除了一些基本的安全性的配置,如果考虑上传速度的话,个人感觉最重要的是上传连接数量,其他的优化也不知道有啥效果,或者效果不明显。

vertex 配置

我尝试过一段时间 ptool去刷流,不过在盒子很多的情况下,vertex 应该是更好的,很灵活,有很多规则可以设置,比较方便实现“已经在下载的种子不要在其他盒子重复推送‘的需求。

https://github.com/vertex-app/vertex

所以,在整个系统配置起来,加入好站点和下载器之后,配置上的细节就主要是在 rss 规则的设置和删种逻辑的设置了。

这里备份一下我的设置:

整体逻辑是:

  1. 在 rss 规则中,通过 rss 定期扫描把最新的种子推送到下载器下载,
    1. 加入一些 rss 规则主要保证下载种子不会撑爆硬盘,以及控制未完成任务的数量
    2. 每一个下载器一个独立的 rss 规则,vertex 会按照某种顺序一个个匹配,控制了未完成数量后就会在有很多任务需要下载的时候能分摊到不同的下载器中。
    3. rss 规则中会计算可用容量,如果不够就会拒绝种子,一个服务器拒绝了那就换到另一个下载器的 rss 规则去尝试匹配。
    4. 一旦遇到新种子,马上下载
    5. 在这一步已经确保几乎不会出现撑爆硬盘的情况,所以后面的删种规则就不需要考虑容量问题了。
  2. 通过删种逻辑,把没有上传速度的种子删掉
    1. 无条件-30min低于 30kib
    2. 下载后 1h- 10min 低于 50kib
    3. 下载后 12h - 5min 低于 100kib
    4. 再另外搭配一些错误删除,stall 删除之类的,就很够用了

关于删种逻辑,可以让vertex 跑一段时间回来看看有没有啥要删除的种子,有的话手动删除或者再加点删种规则,这一块其实有些基本的删种逻辑就行了,刚开始配可以先不弄删种,先把盘填满再说,删种逻辑可以慢慢加。

vip 不需要考虑下载量所以随便刷,如果没有 vip 的话,我的这些规则可能就不太适用了。mteam 还是有个 vip 方便点,这一块大家就是根据自己需求来就好。

rss 规则

每个节点都设置一个自己的 rss 规则,这里拿其中一个 rss 规则作为例子,其他节点就是拷贝相同的规则,修改一下前面的 config 部分就行。这是我基于其他人的javascript改进而来,主要是加入了“未完成任务数量”的约束。避免 vertex 把所有种子全堆到某一个下载器的情况,适用于盒子比较多的时候,只需要改前面配置部分即可,后面的代码不用改。

一般来说,需要根据节点的情况调节这些config:保种体积(避免爆硬盘),未完成任务数(避免下载数过多跟不上车),种子大小限制(小盘鸡下小种子大盘鸡下大种子)

(torrent) => {
  // 配置部分:这些部分可以自定义
  const config = {
    downloaderId: '708f58c4',             // 下载器ID,指定适用的下载器ID
    enableLogging: false,                  // 是否启用日志记录
    enableSeedingVolumeLimit: true,        // 是否启用保种体积限制
    seedingVolumeLimit: 3 * 1024 * 1024 * 1024 * 1024, // 保种体积限制(单位:字节),例如14GB
    enableTaskCountLimit: true,            // 是否启用下载器任务数量限制
    taskCountLimit: 50,                    // 下载器任务数量限制,设置最大任务数
    enalbeDownloadCountLimit: true,        // 是否启用下载器中的同时下载任务数量限制
    downloadCountLimit: 8,                 // 正在下载的任务数量限制
    enableSizeLimit: true,                 // 是否启用种子大小限制
    sizeLimitRange: [2 * 1024 * 1024 * 1024, 2 * 1024 * 1024 * 1024 * 1024],  // 种子大小范围(单位:字节)
    enableFileNameMatchLimit: false,        // 是否启用文件名匹配限制
    fileNameRegex: /sample|test/i          // 文件名正则匹配,支持正则表达式
  };
 
  const fs = require('fs');
  const path = require('path');
 
  // 获取本地时间字符串
  function getLocalTimeString() {
    return new Date().toLocaleString('zh-CN', { hour12: false });
  }
 
  // 辅助函数:向 /vertex/log22/log.txt 中追加日志信息
  function logFailure(message) {
    if (!config.enableLogging) return; // 如果未启用日志记录,直接返回
    const logFilePath = '/vertex/log22/log.txt';
    const logDir = path.dirname(logFilePath);
    if (!fs.existsSync(logDir)) {
      fs.mkdirSync(logDir, { recursive: true });
    }
    const now = getLocalTimeString();
    fs.appendFileSync(logFilePath, `[${now}] ${message}
`);
  }
 
  // 获取下载器ID和下载器对象
  const downloaderId = config.downloaderId; // 当前下载器ID
  const client = global.runningClient[downloaderId];
  if (!client) {
    logFailure(`未找到下载器 ${downloaderId}`);
    return false;
  }

  // 2. 保种体积限制:先检查 /vertex/${downloaderId}/size.txt 中存储的时间和累计体积
  if (config.enableSeedingVolumeLimit) {
    const sizeFilePath = `/vertex/${downloaderId}/size.txt`;
    const sizeDir = path.dirname(sizeFilePath);
    if (!fs.existsSync(sizeDir)) {
      fs.mkdirSync(sizeDir, { recursive: true });
    }
    let currentCumulative = 0;  // 当前累计体积(字节)
    let fileTimestamp = 0;      // 文件中记录的时间(秒)
    const now = Math.floor(Date.now() / 1000); // 当前时间,单位:秒
 
    // 尝试读取文件,如果存在则解析内容(格式:timestamp,cumulativeSize)
    if (fs.existsSync(sizeFilePath)) {
      try {
        const data = fs.readFileSync(sizeFilePath, 'utf8').trim();
        if (data) {
          const parts = data.split(',');
          if (parts.length === 2) {
            fileTimestamp = Number(parts[0]);
            currentCumulative = Number(parts[1]);
          }
        }
      } catch (err) {
        logFailure(`读取 size.txt 失败: ${err}`);
      }
    } else {
      // 如果文件不存在,则计算累计体积并创建文件
      client.maindata.torrents.forEach(t => {
        currentCumulative  = Number(t.size || 0);
      });
      fileTimestamp = now;
      try {
        fs.writeFileSync(sizeFilePath, `${fileTimestamp},${currentCumulative}`);
      } catch (err) {
        logFailure(`写入 size.txt 失败: ${err}`);
      }
    }
 
    // 如果下载器中没有任务,则重置累计体积为 0
    if (!client.maindata.torrents || client.maindata.torrents.length === 0) {
      currentCumulative = 0;
      fileTimestamp = now;
      try {
        fs.writeFileSync(sizeFilePath, `${fileTimestamp},${currentCumulative}`);
      } catch (err) {
        logFailure(`重置 size.txt 失败: ${err}`);
      }
    }
    // 如果文件中的时间超过2分钟,则重新计算累计体积
    else if (now - fileTimestamp > 120) {
      currentCumulative = 0;
      client.maindata.torrents.forEach(t => {
        currentCumulative  = Number(t.size || 0);
      });
      fileTimestamp = now;
      try {
        fs.writeFileSync(sizeFilePath, `${fileTimestamp},${currentCumulative}`);
      } catch (err) {
        logFailure(`更新 size.txt 失败: ${err}`);
      }
    }
 
    // 确保 torrent.size 为数值
    const torrentSize = Number(torrent.size);
 
    // 将累计体积加上当前种子的大小,与保种体积限制比较
    if ((currentCumulative   torrentSize) >= config.seedingVolumeLimit) {
      logFailure(`保种体积限制不通过:累计体积 ${currentCumulative}   当前种子 ${torrentSize} 超过限制 ${config.seedingVolumeLimit}`);
      return false;
    }
  }
 
  // 3. 下载器任务数量限制:检查下载器当前任务数量
  if (config.enableTaskCountLimit) {
    if (client.maindata.torrents.length >= config.taskCountLimit) {
      logFailure(`任务数量限制不通过:当前任务数量 ${client.maindata.torrents.length} 超过限制 ${config.taskCountLimit}`);
      return false;
    }
  }

// 3.2 限制同时下载的任务数量
if (config.enalbeDownloadCountLimit) {

  if (client.maindata.torrents.filter(torrent => torrent.completed = config.downloadCountLimit) {
    logFailure(`未完成数量限制不通过:当前任务数量 ${client.maindata.torrents.filter(torrent => torrent.completed  torrent.downloadSpeed > 0).length >= config.downloadCountLimit) {
    logFailure(`下载任务数量限制不通过:当前任务数量 ${client.maindata.torrents.filter(torrent => torrent.downloadSpeed > 0).length} 超过限制 ${config.downloadCountLimit}`);
    return false;
  }

}

  // 4. 种子大小限制:检查种子的大小是否在规定范围内
  if (config.enableSizeLimit) {
    const size = Number(torrent.size);
    if (size  config.sizeLimitRange[1]) {
      logFailure(`种子大小限制不通过:种子大小 ${size} 不在范围 ${config.sizeLimitRange[0]} - ${config.sizeLimitRange[1]}`);
      return false;
    }
  }
 
  // 5. 文件名匹配限制:检查文件名是否符合正则匹配
  if (config.enableFileNameMatchLimit) {
    const fileName = torrent.name;
    if (!fileName.match(config.fileNameRegex)) {
      logFailure(`文件名匹配限制不通过:种子名称 "${fileName}" 未匹配正则 ${config.fileNameRegex}`);
      return false;
    }
  }
 
  // 如果所有条件都满足,则表示添加该种子。
  // 在返回 true 前,如果启用了保种体积限制,则更新 /vertex/${downloaderId}/size.txt
  if (config.enableSeedingVolumeLimit) {
    const sizeFilePath = `/vertex/${downloaderId}/size.txt`;
    let cumulative = 0;
    let fileTimestamp = 0;
    if (fs.existsSync(sizeFilePath)) {
      try {
        const data = fs.readFileSync(sizeFilePath, 'utf8').trim();
        if (data) {
          const parts = data.split(',');
          if (parts.length === 2) {
            fileTimestamp = Number(parts[0]);
            cumulative = Number(parts[1]);
          }
        }
      } catch (err) {
        logFailure(`读取 size.txt 更新部分失败: ${err}`);
      }
    }
    cumulative  = Number(torrent.size);
    try {
      fs.writeFileSync(sizeFilePath, `${fileTimestamp},${cumulative}`);
    } catch (err) {
      logFailure(`更新 size.txt 失败: ${err}`);
    }
  }
 
  return true;
};

在配置 rss 任务的时候,我弄了两个 rss 链接,一个是所有分类前 60 个,另一个成分分类前 30 个,感觉成人分类的似乎容易刷?这里需要注意,mteam 的免费大包因为往往是旧的种子,所以不会出现在 rss 里面,这一块需要自己手动加,如果需要还可以加入到 keep 分类避免被删掉。

删种规则

删种规则就顾名思义就好。之前看到过一些 javascript 类的删种规则,觉得我不需要那么复杂的,也容易做出不符合预期的行为(比如有一回在我的时候把我下到一般的成人大包给删掉了),把一段时间上传速度低的删掉就行了。

举个例子:

点赞
  1. Vivi不懂说道:

  2. 仙丝暮成雪说道:

    我们都用内部专用一键1PB版qb,你用apt install,难怪你上传堵车

  3. 香香猪说道:

    我们都用内部专用一键1PB版qb,你用apt install,难怪你上传堵车

发表回复

电子邮件地址不会被公开。必填项已用 * 标注

×
订阅图标按钮