关于公网分流任务使用 qBittorrent + libtorrent 内存泄漏的一些想法

出现的问题是,在 Linux qb 挂了 400+ 公网种子的情况下,使用 libtorrent 1.1 作为后端,在运行三至四天以后就会内存使用量不断增加,直到占用了几乎所有的可用内存,系统崩溃为止。

在 qb 的这个 Issue 中(https://github.com/qbittorrent/qBittorrent/issues/8630),有人在 Windows 上观察到了一样的现象,报告在 Enable OS cache 的情况下最终会导致内存泄漏。

在 https://github.com/qbittorrent/qBittorrent/issues/8295 和 https://github.com/arvidn/libtorrent/issues/1997 这两个 Issue 中,有人提到是 libtorrent 本身的 IO 和缓存实现存在问题,导致磁盘 IO 效率过低。但是这两个问题也都是在 Windows 上观察得出的,目前提供的方法是关闭 OS Cache,打开 libtorrent 的 coalesce reads & writes 选项,以在 Windows 上达到较好的 IO 性能表现(这个选项在 Linux 上是不必要的,因为 Linux 有 pwritev() 的实现,不需要通过 pwrite() 进行模拟——arvidn)。

但是在 Linux 上,这个问题仍然没有任何解决的迹象。在我看来,假定 libtorrent 自身的内存管理不存在问题,没有内存泄漏的情况,那么内存占用应该存在于两个方面:一是在 libtorrent 1.1 解决了 IO 性能问题以后引入的新 bug,即 lt 可以同时打开大量的 File Descriptor 且不陷入死锁,那么由于使用 buffered IO 的问题,在系统内核层面上消耗了大量的内存;另一个可能性是 TCP Socket buffer,libtorrent 1.1 相比 1.0 修正了大量 TCP Socket 连接卡死的问题(甚至出现了 too many open files 的情况,参见之前的文章,这个现象在 lt 1.0 从未出现过),大量 peer 和 tracker 连接使用的 TCP Socket 在内核层面占用了大量的内存,进而出现内存占用高的问题。

目前先禁用 OS Cache 进行下一步测试,观察是否还会出现内存占用过高。如果有,那么应该是 TCP 造成的问题了。(在看了 IBM 关于 Linux Direct IO 的这篇文章后,我对 IO Buffer 这个方向不报太大希望,因为无论怎么看 Buffered IO 的实现也不像会把自己噎死的样子)

红米 5A 刷欧洲版 MIUI 记录

老年人的第一次刷机。

最近把红米备机拿出来用了,升到了 ADUI 10,感觉还不错,但是广告实在太多。想起来当年被卡 15 天解 BL 锁的限制早过了很久了,就想着把这破系统刷了吧。

查了一圈发现 MIUI EU 版是相对干净的系统,可以在这里取得。

准备工作

解锁 Bootloader
MIUI EU 版刷机包
Android Debug Bridge
第三方 Recovery TWRP
Root 包 Magisk

刷机步骤

  1. 解锁 Bootloader
    1. 进入“设置 -> 开发者选项 -> 设备解锁状态”中绑定账号和设备;
    2. 手动进入 Fastboot 模式(关机后,同时按住开机键和音量下键);
    3. 通过USB连接手机,点击 “解锁”按钮;
  2. 刷入 TWRP
    1. 在 Bootloader 模式下,运行 fastboot flash recovery <twrp_image>刷入 TWRP
    2. fastboot reboot 重启设备,注意此时需要立即按下音量上 + 电源以进入 Recovery 模式,否则 MIUI 会覆盖刷入的自定义 Revocery
  3. Recovery 成功刷入设备后,将手机关机,在关机状态下按住电源键和音量上键,进入 Recovery 模式,滑动 Swipe to Allow Modifications 进入主菜单。点击 Wipe,点击 Format Data,输入 yes 完成格式化,返回上一菜单,点击 Advanced Wipe,选择 Dalvik,Cache,System,Data 和 Internal Storage 分区,并滑动 Swipe to Wipe 进行擦除,然后返回 Recovery 主菜单
    1. 注意可能在 Wipe /data 分区时可能会出现错误:TWRP Unable to mount '/data',如果出现该错误,在 Fastboot 模式下运行 fastboot format userdata清理 /data 分区之后再进行操作
  4. 在电脑磁盘列表中找到手机,复制 ROM 至手机,复制完成后在 Recovery主菜单中,点击 Install,点击 ROM 包,滑动 Swipe to confirm Flash 进行刷入,重启设备
    1. 任意方法刷入 ROM 后,命令窗口中结束 adb 服务adb kill-server
  5. 重启进入 Recovery 模式,按照刷 ROM 的方式刷入 root 包

然后大功告成

参考资料

https://www.zhihu.com/question/50231539/answer/530627637
https://www.reddit.com/r/Nexus6P/comments/3qnzz0/twrp_unable_to_mount_data/

 

优化 wine 的字体显示

有时候总有一些不得不在 Linux 下跑一些 Windows 程序的需求,所以我们会用到 wine,但是 wine 默认并不是给中文用户设计的,因此我们需要一些办法来解决中文显示乱码和效果差的问题。

中文乱码,主要表现是非 ASCII 字符全部都显示为方框,这个是没有字体造成的,需要在 ~/.wine/drive_c/windows/Fonts 下面安装中文字体,一般来说,装好宋体、黑体和微软雅黑这些常用的就能用了,如果想装点别的,自然也可以。这里提供了一些打包好的基础字体下载:

cd ~/.wine/drive_c/windows/Fonts
wget https://down.gloriousdays.pw/Fonts/wine_fonts.tar.xz
tar cJvf wine_fonts.tar.xz
rm wine_fonts.tar.xz

搞定了字体以后,很快就会发现这些字体的显示效果十分差,完全没有做 AA 的意思,我们用 winetricks 解决这个问题:

apt install winetricks
winetricks settings fontsmooth=rgb

重新打开 exe 程序即可

使用 zram 进行内存压缩

对于像 KS-3 这样只有 4GB 内存的小内存服务器,如果想在上面跑一些比较复杂的服务,经常会遇到内存不足的问题。一般说到内存不足,第一反应都是加 swap 空间,但是对于机械硬盘的场景,添加盲目添加 swap 空间并不是一个好的选择,因为这样会显著增加系统整体的 latency。这个时候 zram 就可以派上用场了。

zram 是在 Linux Kernel 3.2 加入的一个模块,其功能是在内存中开辟一块空间,用来存储压缩后的内存数据,这样可以在牺牲一定的 CPU Cycle 的情况下,在内存中存储尽量多的数据而不需要写入到磁盘。

对于 Ubuntu 系统,开启 zram 的方法很简单,只需要安装 zram-config 这个包之后重启即可。zram 默认会将系统内存的一半作为 zram,然后根据 CPU 核心数平均分配到每个 zram 设备。比如在我的 KS-3 上,通过 zramctl 查看 zram 的情况,是这样的:

# zramctl
NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram3 lz4           491M   4K   63B    4K       4 [SWAP]
/dev/zram2 lz4           491M   4K   63B    4K       4 [SWAP]
/dev/zram1 lz4           491M   4K   63B    4K       4 [SWAP]
/dev/zram0 lz4           491M   4K   63B    4K       4 [SWAP]

注意到这里的压缩算法,有两种算法 lzo 和 lz4 可选,默认是 lzo。根据 Benchmark,lz4 的压缩和解压性能在压缩率和 lzo 持平的情况下显著高于后者,因此我们应该采用 lz4 而非 lzo 以获得更高的系统效率。

虽然 zramctl 可以帮助调整 zram 的情况,但是我们还是应该在系统启动时就将这些东西配置好。zram-config 安装好后会默认添加 zram-config.service,这个 service 是运行 /usr/bin/init-zram-swapping 这个脚本以配置对应的 zram 设备,默认情况下,其配置设备的内容应该是这样:

#!/bin/sh

# load dependency modules
NRDEVICES=$(grep -c ^processor /proc/cpuinfo | sed 's/^0$/1/')
if modinfo zram | grep -q ' zram_num_devices:' 2>/dev/null; then
  MODPROBE_ARGS="zram_num_devices=${NRDEVICES}"
elif modinfo zram | grep -q ' num_devices:' 2>/dev/null; then
  MODPROBE_ARGS="num_devices=${NRDEVICES}"
else
  exit 1
fi
modprobe zram $MODPROBE_ARGS

# Calculate memory to use for zram (1/2 of ram)
totalmem=`LC_ALL=C free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/  *.*//'`
mem=$(((totalmem / 2 / ${NRDEVICES}) * 1024))

# initialize the devices
for i in $(seq ${NRDEVICES}); do
  DEVNUMBER=$((i - 1))
  echo $mem > /sys/block/zram${DEVNUMBER}/disksize
  mkswap /dev/zram${DEVNUMBER}
  swapon -p 5 /dev/zram${DEVNUMBER}
done

如果我们要默认使用 lz4 算法,那么应该将最后一段改成这样:

# initialize the devices
for i in $(seq ${NRDEVICES}); do
  DEVNUMBER=$((i - 1))
  echo lz4 > /sys/block/zram${DEVNUMBER}/comp_algorithm
  echo $mem > /sys/block/zram${DEVNUMBER}/disksize
  mkswap /dev/zram${DEVNUMBER}
  swapon -p 5 /dev/zram${DEVNUMBER}
done

注意算法设置一定要在配置空间大小之前,否则不能正确修改。

修改过后,运行 systemctl restart zram-config 就可以载入新的配置。

参考资料:

https://askubuntu.com/questions/1044976/make-zram-use-lz4-compression-algorithm
https://github.com/lz4/lz4
https://sites.google.com/site/easylinuxtipsproject/speed#TOC-Only-768-MB-RAM-or-less:-enable-zRam
http://tuxdiary.com/2015/07/28/zram/
https://wiki.archlinux.org/index.php/improving_performance#Zram_or_zswap

 

修改 Linux 默认的 IO Scheduler

RHEL 系我不知道怎么弄,我也没有机器是这个

在 /etc/default/grub 中,找到 GRUB_CMDLINE_LINUX_DEFAULT="" 这行,可能原来后面双引号中间有参数,这个各个机器不同,如果要修改默认的 CFQ Scheduler,那么在这里加上 elevator=noop 这样的内容,且和之前的旧内容有一空格。之后 update-grub2 重启即可。

之后 cat /sys/block/sda/queue/scheduler 就可以看到当前使用的调度器

IO Scheduler 有三个选择 cfq noop 和 deadline

参考资料:

https://www.ibm.com/developerworks/cn/linux/l-lo-io-scheduler-optimize-performance/index.html
https://askubuntu.com/questions/78682/how-do-i-change-to-the-noop-scheduler
Red_Hat_Enterprise_Linux-6-Performance_Tuning_Guide-en-US
Red_Hat_Enterprise_Linux-7-Performance_Tuning_Guide-en-US

iKoula 盒子的一些记录

之前听人整天听人吹 iKoula 网络好,但是因为性价比太低一直没买,这次黑五总算有性价比还行的型号,就买了台,真香

我这台是 109 段的 G 管,首先要配置一下 IPv6,运行这样一个脚本:

serveripv4=$( ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:" )
interface=$( ifconfig -a | grep -B 1 $serveripv4 | head -n1 | awk '{print $1}' | sed "s/:$//" )
AAA=$( echo $serveripv4 | awk -F '.' '{print $1}' )
BBB=$( echo $serveripv4 | awk -F '.' '{print $2}' )
CCC=$( echo $serveripv4 | awk -F '.' '{print $3}' )
DDD=$( echo $serveripv4 | awk -F '.' '{print $4}' )

cat>>/etc/network/interfaces<<EOF
iface $interface inet6 static
address 2a00:c70:1:$AAA:$BBB:$CCC:$DDD:1
netmask 96
gateway 2a00:c70:1:$AAA:$BBB:$CCC::1
EOF

然后 systemctl restart networking.service 就行了。

如果你像我一样运气不好,拿到了一块 WD 绿盘,IntelliPower 这种垃圾技术的盘,那么还得想办法拯救一下。绿盘默认 8 秒会把磁头停到启停区,这时候如果去读盘,就会卡一下,我们通过 idle3ctl 关闭这个功能:

sudo apt-get install idle3-tools
sudo apt-get install idle3-tools # Show current idle3 value
sudo idle3ctl -s 138 /dev/sda # setting to 300 seconds
# The man page for idle3ctl states that values between 1 and 128 add 0.1 seconds, values between 129 and 256 add 30s: 128 * 0.1 + (138 - 128) * 30 = 312.8 seconds
sudo idle3ctl -d /dev/sda # Disable parking, recommended

之后就是网卡,iKoula 的桌面主板用的是 RTL8168 这块开 BBR 会掉速 4MB 的螃蟹卡,我们需要更新驱动

由于 Realtek 的官网不太好使,我备份了驱动到自己的站点

apt update && apt install build-essential libelf-dev linux-headers-$(uname -r)
wget https://down.gloriousdays.pw/Tools/0012-r8168-8.046.00.tar.bz2
tar xjvf 0012-r8168-8.046.00.tar.bz2
cd r8168-8.046.00
./autorun.sh || modprobe r8169

这样就会安装上 R8168 的驱动了,之间会断网 3-5 分钟,之后重连即可,不需要 screen,但是如果一定要用也行。

如果 10 分钟还连不上,去后台手动重启。

参考资料:

https://wdullaer.com/blog/2015/04/05/hack-your-wd-greens/

 

关于 BT 客户端 Too many open files 的问题

感谢星菊对这个问题提供的帮助

换用 libtorrent 1.1 以后,由于 arvidn 改善了 IO 线程的问题,因此总是出现 too many open files 错误,在多方询问以后,终于解决了这个问题。

如果去查这个问题,通常会建议修改 limits.conf,修改 ulimit -n 参数,在 sysctl.conf 中添加 fs.file-max 参数等等,然而都不能解决这个问题。

实际上,目前以 systemd 作为启动工具的发行版,都存在两套限制体系,一个是 limits.conf,负责限制命令行模式启动的程序,另一个是 /etc/systemd/system.conf,限制以 systemd service 方式启动的程序。因此如果要解决这个问题,需要所有的地方都进行修改。

在 /etc/systemd/system.conf 中,加上:

DefaultLimitNOFILE=999998
DefaultLimitNPROC=999998

在 /etc/sysctl.conf 中,加上:

fs.file-max = 2097152
fs.nr_open = 2097152

在 /etc/security/limits.conf 中,加上:

*         hard    nofile      999999 
*         soft    nofile      999999 
root      hard    nofile      999999 
root      soft    nofile      999999 

然后就可以解决问题了。

 

如何查看 HBA 卡下的硬盘的 SMART 信息

盒子的盘挂了,但是这个盒子不是 SWR 的所以不太方便直接查看 SMART 信息。emm, 实际上还是很方便的。

我这个盒子是的 HWR 实际上通过一张 HBA 卡完成,信息是这样的:

root@dedi-par-28324:~# lspci|grep LSI
01:00.0 Serial Attached SCSI controller: LSI Logic / Symbios Logic SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon] (rev 03)

通过查看 SCSI 的信息,我们能看到卡下面连接的两块硬盘:

root@dedi-par-28324:~# cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 01 Id: 00 Lun: 00
  Vendor: Dell     Model: Virtual Disk     Rev: 1028
  Type:   Direct-Access                    ANSI  SCSI revision: 06
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: WDC WD2003FYYS-1 Rev: 1D02
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi0 Channel: 00 Id: 01 Lun: 00
  Vendor: ATA      Model: WDC WD2003FYYS-1 Rev: 1D02
  Type:   Direct-Access                    ANSI  SCSI revision: 05

如果要看 SMART 信息的话,只需要加载 sg 这个驱动就可以了(sg 为 Linux SCSI Generic driver 的缩写)

modprobe sg
echo sg >> /etc/modules

然后盘会挂在 sg1 sg2 这样的位置下面,用 # smartctl -a /dev/sg1 这样的命令就能看到 SMART 信息了。

在 $HOME 目录安装 Deluge 客户端

注意:这个教程是在 PulsedMedia 盒子上安装 Deluge 的实践,存在大量 platform-specific 的内容,在其他商家的盒子上尝试时要加以修改。

PulsedMedia 盒子的宿主机是 Ubuntu 14.04,所有自带的软件也是基于该发行版,自带的 Python 为 2.7.9,且缺乏大量的库。如果我们要安装 Deluge,需要从头解决一系列依赖问题。

在 User Space 编译安装的方法

比较清真的做法是创建 $HOME/.local 目录,然后在下面创建对应的 bin, lib 和 include 目录,然后再创建 usr 目录,并创建另一套 bin, lib 和 include。

在完成文件夹创建以后,在 .bashrc 中修改自己的 $PATH, $LD_LIBRARY_PATH, $C_INCLUDE_PATH, $CPLUS_INCLUDE_PATH 这几个环境变量:

export PATH=/home/<user>/.local/bin:/home/<user>/.local/usr/bin:$PATH
export LD_LIBRARY_PATH=/home/<user>/.local/lib:/home/<user>/.local/usr/lib:$LD_LIBRARY_PATH
export C_INCLUDE_PATH=/home/<user>/.local/include:/home/<user>/.local/usr/include:$C_INCLUDE_PATH
export CPLUS_INCLUDE_PATH=/home/<user>/.local/include:/home/<user>/.local/usr/include:$CPLUS_INCLUDE_PATH

<user> 修改为自己的 Unix 用户名

在修改了这些环境变量之后,配合编译时的 –prefix 参数以及 pip/python 的 –user 参数就可以将程序安装在自己的 $HOME 目录下

Deluge 依赖的安装

pip

对,你没看错,这机器 pip 都没有,好在这个相对来说还是比较简单,Python 官方也提供了对应的 py 程序

wget --no-check-certificate https://bootstrap.pypa.io/get-pip.py -O - | python - --user

Boost

libtorrent 编译需要 boost,我们选择 Boost 1.65.1 这个经过大量测试的版本

wget https://dl.bintray.com/boostorg/release/1.65.1/source/boost_1_65_1.tar.gz
tar xzvf boost_1_65_1.tar.gz
cd boost_1_65_1
./bootstrap.sh --prefix=$HOME/.local
./b2 install -j $(nproc)

Geoip

这也是 libtorrent 依赖的库之一

git clone https://github.com/maxmind/geoip-api-c.git
./bootstrap
./configure --prefix=$HOME/.local
make -j $(nproc)
make check
make install

libtorrent

终于可以安装 libtorrent 了,这个和之前正常安装的区别不大,唯一的区别在于要指定 –prefix 和 –with-boost-libdir

git clone https://github.com/arvidn/libtorrent.git libtorrent-1.0.11
git checkout RC_1_0
./autotool.sh
./configure --enable-python-binding --with-libiconv --disable-debug --enable-encryption --with-libgeoip=system CXXFLAGS=-std=c++11 --prefix=$HOME/.local --with-boost-libdir=$HOME/.local/lib
make -j $(nproc)
make install

Deluge 的 py 依赖

这个没什么好说的

pip install attr chardet click colorama pyopenssl pam pyasn1 pyasn1-modules serial service_identity Twisted zope.interface setuptools notify pygame mako automat constantly hyperlink incremental pyxdg --user

但是有三个库,intltool, libsrvg 和 xdg-utils 没有,我们需要另行安装

intltool

wget http://ftp.gnome.org/pub/gnome/sources/intltool/0.40/intltool-0.40.6.tar.gz
tar zxvf intltool-0.40.6.tar.gz
cd intltool-0.40.6
./configure --prefix=$HOME/.local
make && make install

libsrvg

该库依赖 librsvg2-common librsvg2-2 libglib2.0-0 和 libgdk-pixbuf,其中前三个可以直接用 apt-get download 命令取得,后一个不知为何没办法在 apt 上找到,只能去补佳乐的 package 网站上寻找,地址在这里。我们用的版本是 2.31.1-2+deb8u7。

使用 dpkg -x 命令可以将 .deb 包释放在指定目录下,但是不能完成 apt 安装的配置过程,好在这几个 library 只是文件而已,所以这么做并没有什么问题

apt-get download librsvg2-common librsvg2-2 libglib2.0-0
wget http://ftp.us.debian.org/debian/pool/main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.31.1-2+deb8u7_amd64.deb
dpkg -x libgdk-pixbuf2.0-0_2.31.1-2+deb8u7_amd64.deb ~/.local
dpkg -x libglib2.0-0_2.42.1-1+b1_amd64.deb ~/.local
dpkg -x librsvg2-2_2.40.5-1+deb8u2_amd64.deb ~/.local
dpkg -x librsvg2-common_2.40.5-1+deb8u2_amd64.deb ~/.local

注意 .deb 的名字可能随着版本升级而改变,所以复用的时候要注意一下

xdg-utils

和上面一样,用 apt 取得包以后再释放

apt-get download xdg-utils
dpkg -x xdg-utils_1.1.0~rc1+git20111210-7.4_all.deb ~/.local

Deluge

最后,正常安装 deluge 即可

wget http://download.deluge-torrent.org/source/deluge-1.3.15.tar.gz
tar xzvf deluge*.tar.gz
python setup.py build
python setup.py install --user

之后 deluged 和 deluge-web 会被安装在 $HOME/.local/bin 下面,由于之前已经修改了环境变量,所以直接运行就可以了

如果要让 deluged 工作在不同的端口,使用 deluged -p 23333 这样的命令就行,然后在 deluge-web 中改一下连接的 daemon 端口就行了

至此,deluge 应该已经可以正常运行了。