本文最后更新于 1 年前,文中所描述的信息可能已发生改变。
问题描述:当使用 qBittorrent 选择下载路径直接设置到 CIFS 挂载的路径中时,如果种子 Torrent 只包含一个文件(比如只包含一个视频文件)时性能符合预期,在种子质量良好时通常可以跑到机器带宽上限(1Gbps+);但只要种子包含的文件数量大于1(比如一个视频文件和一个 20kb 大小的封面图,或一个数 kb 大小的 nfo 元数据),同样在种子质量良好的情况下下载速度只能在 2-6MB/s中来回波动,同时观察统计面板 I/O 缓存写入超负载经常维持在 90% 上下,I/O 延迟也爆增至四位数,很明显的卡 I/O 现象。同时很奇怪的一点是,一个只包含两个文件的电影种子,和一个包含上百个文件的剧集种子文件所表现的 I/O 性能是一致的,下载速度都只能在 2-6MB/s 之间波动,这就非常奇怪了,难道同时下载两个文件和同时下载 200 个文件所占用的 I/O 是一致的?想想都不太可能。
先说结论:
libtorrent2的傻逼问题,更改为libtorrent1.2完美解决。
我是用的docker部署,**linuxserver/qbittorrent**的镜像,只要更改最后的标签latest为libtorrentv1后重新部署即可完美解决。比如原来是lscr.io/linuxserver/qbittorrent:latest
,更换为lscr.io/linuxserver/qbittorrent:libtorrentv1
后重新pull构建即可完美解决。
接下来是讲故事时间 处理问题的过程:
前段时间刚把 buyvm 的存储服务迁移到了 hetzner storage box,较低的价格和良好的性能表现的非常有吸引力,迁移中又遇到了 buyvm 更改支付宝支付货币从加拿大元改成了美元,也相当于是变相涨价了。这样算下来,buyvm 的1TB 存储块的价格来到了惊人的5美金约合35人民币/月,这个价格属实算得上奢侈品了。
Hetzner的 Storage Box 是网络存储,可以使用cifs/smb,webdav,ftp或sftp等方式挂载的任意机器(欧洲内,尤其是和 Storgae box 相同地区会有很不错的网络表现)。但同时 Storgae Box 限制10个网络并发数量,这对于像 webdav,ftp 等每次访问文件都要新开一个网络连接的协议不太友好,而由于 SMB 的特点,同时访问多个文件也只会占用一个网络连接,这样的特性就很适合用于挂载。
问题分析1:CIFS
在最开始刚遇到问题的时候我只以为是 CIFS 挂载导致的性能问题,咨询了多个不同的 AI 后得出结论:CIFS 挂载时在访问多个文件时会有严重的性能问题。并且根据 AI 的建议优化了很多挂载选项,当然除了不能解决问题以外确实能很好的优化挂载性能,下面是挂载指令:
mount -t cifs -o username=abc,password=abc,nostrictsync,rsize=65536,wsize=130048,cache=none //abc.your-storagebox.de/backup /volume
其中:
username=abc,password=abc
:用户名密码rsize=65536,wsize=130048
:此参数来源于 Hetzner 的文档,文档中说明:如果在 Debian 中遇到性能问题,请尝试添加此参数。cache=none
:同样来源于 Hetzner 的文档,文档中说明:如果遇到大于 4GB 文件的写入问题,请尝试关闭缓存。不过我在写入大文件的时候也没遇见有报错,同时对比测试了cache=strict
,cache=loose
,真没感觉性能上有啥太大的区别。。。不过禁用本地缓存。在某些场景下,这可以确保数据的即时性,但可能会影响性能。nostrictsync
:这个选项通常用于提高性能,它告诉系统在写操作时不必严格同步更新到远程设备。
在这种参数的调节下,cifs 的性能已经被完全的榨干了。关于 nostrictsync 参数,以下有一段来自 chatGPT 的回答,不保证准确度,仅供参考:
nostrictsync
选项主要用于优化性能。当启用nostrictsync
:
- 性能提升:系统在处理写请求时更加高效,因为它不需要在每次写操作后立即同步数据到远程服务器。这意味着对于频繁的写操作,系统的响应速度会更快。
- 数据一致性风险:由于写入操作不是严格同步的,如果在数据同步到服务器之前发生系统崩溃或其他故障,可能会导致最近写入的数据丢失或损坏。
通常,在对性能有较高要求且可以容忍一定程度数据丢失风险的环境中使用
nostrictsync
。例如,如果应用主要用于缓存或临时数据,而这些数据的丢失并不会造成重大影响,那么使用nostrictsync
可以提高整体性能。然而,在需要保证数据完整性和一致性的关键应用中,应谨慎使用或避免使用此选项。
问题分析2:qBittorrent 高级设置
在针对 cifs 进行优化配置无果后,中间有段时间一直认为是 BT 下载导致文件碎片过多导致的(虽然也没想明白为什么下载单文件没事,按理说文件碎片的数量是按照文件体积来的),在 qBittorrent 的设置中,有几个选项可以减少文件碎片的产生:
- 为所有文件预分配磁盘空间:啊没错就是这个
- 合并读写(需要 libtorrent < 2.0)
- 启用相连文件块下载模式
- 磁盘 IO 写入模式:连续写入
当然,修改这些配置完全没解决我所遇到的问题,这些选项可以做到以牺牲一些下载速度为代价,尽可能减少文件碎片的产生,并且提高 I/O 效率。
其中有一个很有意思的选项:“磁盘 IO 类型(libtorrent >= 2.0;需要重启)”,其中选项有:“遵循POSIX”和“内存映射文件”。经过网上搜索,默认是内存映射文件,如果更改为 POSIX,可以减少内存的占用,同时会提高 CPU 的占用。
经过尝试,发现更改为 POSIX 后内存占用确实少了一点,但是 qBit 的 WebUI 变卡了好多,同时 CPU 占用也一直很低……(总结,没啥用)
在高级选项中还有一个**“异步 I/O 线程”**数的选项,默认是10,此选项会修改同时写入文件的进程数量,如果磁盘性能不佳可以改为3以下。
总结,修改 qBittorrent 设置屁用没有,该慢还是慢。
在目前这种情况下,我能想到的解决方法也只有使用本机的存储作为缓存,下载后再移动至云端,qBittorrent内置了一个很好的选项:“保存未完成的文件到:” 它可以在文件下载完成后自动移动文件至设置的目录,下载的时候会下载在配置的临时目录里。
这个选项我一直用着,体验还不错,直到有一天,朋友告诉我 他想看柯南…
然后就出现了这个选项最奇葩的逻辑,如果我添加了一个柯南的500G的种子并暂停,进入种子文件列表勾选想要下载的文件后开始,文件就会直接下载到对应目录而不是缓存目录。所以如果想使用缓存目录,就只能添加并开始,并且下载后还不能暂停,只要下载中暂停再开始,qbit 又会直接写入文件到目标目录了。(过于抽象)
最终如何解决问题的?
这个毛病真的太小众了,之前我的搜索关键词一直是诸如:cifs 性能低、storage box 性能低、速度慢等,那时我仍然认为问题出在 cifs 挂载和 Sotrage box 的性能上。
直到有一天,我尝试在互联网搜索:“qbittorrent smb/cifs 速度慢”等关键词,搜到v2ex的一两个案例,同样也是qbittorrent 下载到局域网中NAS的SMB挂载目录上遇见的 IO 问题,但是也都没有找到解决办法。
直到有一次,我尝试只搜索 qbittorrent cifs IO,搜索到了 github issue 中的案例:**Abnormally slow IO performance on CIFS network share。**其中问题提出者和我的情景完全一致,同样都是使用的 Storage Box,不过区别在于 github 上大佬真的很多,很快就有人提到是 libtorrent 对于网络存储的兼容问题,并推荐使用 libtorrent1.2。
从找到正确的方案到解决问题只花费了五分钟不到,回望整个事件,我在寻找问题的原因上花费了大量的时间,在最后的最后才意识到真正的问题出现在 qbittorrent 上,,,真的是奇葩