[调整queue-fs参数]Debian Wiki的ZRam脚本修改版(修复BUG和更恰当的默认值)

sh/bash/dash/ksh/zsh等Shell脚本
回复
科学之子
帖子: 2261
注册时间: 2013-05-26 6:58
系统: Debian 9
送出感谢: 842 次
接收感谢: 30 次

[调整queue-fs参数]Debian Wiki的ZRam脚本修改版(修复BUG和更恰当的默认值)

#1

帖子 科学之子 » 2016-09-06 17:56

Debian Wiki的ZRam脚本修改版(修复BUG和更恰当的默认值)
修复了stop时提示顺序异常的问题
原版地址:https://wiki.debian.org/ZRam
FRACTION改为200%.
因为zram.txt提示压缩率的期望是50%
所以应该zram的大小应该为物理内存的200%,而非小于物理内存
但如果存储的数据对象压缩率极端不可预测,新版Linux内核的zram也是支持限制占用内存大小(mem_limit文件)
但如果您的配置文件中没有mem_limit,数据存储的压缩率又极端不可预测,则只能设置一个小于内存总容量的zram了

另外,实际情况下zram的出现低于50%的压缩率也是很常见的,但考虑到内存中还有一些压缩效果不佳的页面会拉高压缩率,所以我觉得仍应该期望压缩率为50%.
注:在本文中压缩率越低表示压缩效果越好
Tue Sep 6 17:33:27 CST 2016 更新:
增加了compact
compact的用法就是执行Debian Wiki的操作步骤后用命令:"service zram compact"来调用即可(已不适用于Debian Stretch)
"zram compact" 这样直接调用就好,记得像Debian Wiki上说的一样加上执行权限
compact的作用是通过重新排列内存中数据来降低内存碎片,增加连续的可用空间
zram(zsmalloc)的compact则通过重新排列自己的数据避免因不恰当的碎片浪费内存空间

此外如果使用zram不建议开启任何其它swap设备,如果zram实在不够用,那么您应该启动zswap配合传统swap,而非使用zram
理由是如果直接让zram和普通swap设备一起使用,会出现LRU倒置的情况
值得注意的是zswap在写缓存未填满时就会因为大量reject_compress_poor(还有其它各种原因的拒绝存储)导致写缓存远未填满就大量读写后端swap设备
如果被zswap拒绝的页面是热页面,就会类似于zram的LRU倒置.
所以zram能满足需要的情况下我不推荐使用zswap.

单独使用zram应该把swappiness设置为100
https://lists.ubuntu.com/archives/lubun ... 05831.html
Letting the swappiness at default (60) or even set it higher to 100
would help avoid this bottleneck as swapping early would avoid
RAM running full too fast.
Setting swappiness higher here would be also only work until ZRAM is
filled and than would lead to bottleneck 1 again.
然而在只开启zram作为交换设备的情况下,swappiness=100(较早交换冷页面)的副作用微乎其微,并不存在交换到外部设备那样的可怕延迟
而如果swappiness=1之类,当发生交换时因为没能提前进行冷页面交换,交换过度集中,即使是在内存中完成,也有相当可怕的延迟
swappiness=100的另一个好处系统可以通过压缩内存中的冷页面来更少的抛弃高价值页缓存.

并且也只应该在单纯开启zram的情况下开启它,否则因为上述的LRU倒置的问题,应该使用zswap+普通swap设备

脚本里注释掉的行是我不确定应该怎么做的部分
此脚本的更多描述见2楼

代码: 全选

#!/bin/sh
### BEGIN INIT INFO
# Provides:          zram
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Default-Start:     S
# Default-Stop:      0 1 6
# Short-Description: Use compressed RAM as in-memory swap
# Description:       Use compressed RAM as in-memory swap
### END INIT INFO

# Author: Antonio Galea <antonio.galea@gmail.com>
# Thanks to Przemysław Tomczyk for suggesting swapoff parallelization
# Distributed under the GPL version 3 or above, see terms at
#      https://gnu.org/licenses/gpl-3.0.txt

FRACTION=200

MEMORY=`perl -ne'/^MemTotal:\s+(\d+)/ && print $1*1024;' </proc/meminfo`
#CPUS=`grep -c processor /proc/cpuinfo`
#swap_cache_pressure=29
#max_swap_priority=32767
#CPUS=$swap_cache_pressure
CPUS=1
SIZE=$(( MEMORY * FRACTION / 100 / CPUS ))
case "$1" in
  "start")
    echo 100 >/proc/sys/vm/swappiness
    echo 0 >/proc/sys/vm/page-cluster
    echo 0 >/proc/sys/vm/extfrag_threshold
    echo 1 >/proc/sys/vm/watermark_scale_factor
    #echo 1 > /sys/kernel/mm/ksm/run
    param=`modinfo zram|grep num_devices|cut -f2 -d:|tr -d ' '`
    modprobe zram $param=$CPUS
    for n in `seq $CPUS`; do
      i=$((n - 1))
      #echo 2 >/sys/block/zram$i/max_comp_streams
      #echo $2 >/sys/block/zram$i/comp_algorithm
      echo deflate >/sys/block/zram$i/comp_algorithm
      echo $SIZE >/sys/block/zram$i/disksize
      echo 0 >/sys/block/zram$i/queue/read_ahead_kb
      echo 2 >/sys/block/zram$i/queue/nomerges
      echo 2 >/sys/block/zram$i/queue/rq_affinity
      mkswap /dev/zram$i
      swapon -p 10 /dev/zram$i
      #swapon /dev/zram$i -d -p $((max_swap_priority-i))
    done
    #echo 32767 >/proc/sys/vm/vfs_cache_pressure
    echo 1 >/proc/sys/vm/compact_memory
    #echo 0 >/proc/sys/vm/min_free_kbytes
    #echo 1 >/proc/sys/vm/lowmem_reserve_ratio
    #echo 0 >/proc/sys/vm/admin_reserve_kbytes
    ;;
  "stop")
    echo 60 >/proc/sys/vm/swappiness
    echo 3 >/proc/sys/vm/page-cluster
    echo 500 >/proc/sys/vm/extfrag_threshold
    echo 10 >/proc/sys/vm/watermark_scale_factor
    #echo 0 > /sys/kernel/mm/ksm/run
    #echo 100 >/proc/sys/vm/vfs_cache_pressure
    #echo 42980 >/proc/sys/vm/min_free_kbytes
    #echo 256 >/proc/sys/vm/lowmem_reserve_ratio
    #echo 8192 >/proc/sys/vm/admin_reserve_kbytes
    for n in `seq $CPUS`; do
      i=$((n - 1))
      swapoff /dev/zram$i && echo "disabled disk $n of $CPUS" 
    done
    wait
    sleep .5
    modprobe -r zram
    ;;
  "compact")
    for n in `seq $CPUS`; do
      i=$((n - 1))
      echo 1 >/sys/block/zram$i/compact
    done
    echo 1 >/proc/sys/vm/compact_memory
    ;;
  *)
    echo "Usage: `basename $0` (start | stop | compact)"
    exit 1
    ;;
esac
上次由 科学之子 在 2017-09-05 14:51,总共编辑 4 次。
这些用户感谢了作者 科学之子 于这个帖子:
vickycq (2017-08-17 0:21)
评价: 3.7%
科学之子
帖子: 2261
注册时间: 2013-05-26 6:58
系统: Debian 9
送出感谢: 842 次
接收感谢: 30 次

Re: [2楼增加更详细改进思路描述]Debian Wiki的ZRam脚本修改版(修复BUG和更恰当的默认值)

#2

帖子 科学之子 » 2017-08-19 22:24

改进思路的更详细描述(只描述1楼没写的)(如有不同意见希望不吝赐教):
zram 的算法选择(本文的算法选择分析只针对标准内核,特殊情况请阅读本链接):
由于zram算法特点,我们最先排除掉压缩慢压缩效果也不好的lz4hc和lz4
选取两个最具代表性算法在本文对比:lzo(默认算法,压缩效果和速度都相对不错),deflate(最慢,也是压缩效果最好的算法)
折腾了半天,两者好像不能简单的说谁比谁好或优先尝试谁,要根据实机环境和需求决定
根本原则是最大化系统速度
lzo尽管自身很快,但问题是压缩率低,导致低内存环境下会更多丢弃缓存,甚至更多发生OOM,
deflate尽管很慢,但在我模拟老机的测试中使用 deflate 算法的 zram 响应速度仍明显快于使用HDD的交换文件.
但在模拟老机的测试中使用lzo算法,oom 就发生较为频繁.
测试负载就是LXDE+打开Firefox浏览几个图文网页
模拟老机=(禁用多核,CPU节能全开并以最低频率运行,用内核参数"mem=384M"限制内核的内存使用)

关于如何选择算法下面给出一些个人的建议:
Tue Sep 5 14:52:04 CST 2017{
进行了更多的尝试,deflate卡CPU没那么严重,卡CPU的主要原因是VirtualBox设置的虚拟机内存太小导致类似卡在kswapd0的情况.
想办法降低虚拟机系统的内存消耗或适当稍微调高虚拟机的内存,CPU占用率明显下降.
尽管不太确定,感觉在一些测试下设置为lzo算法更容易让整个系统卡住,deflate卡的没lzo那么彻底.
我会在方便时贴出具体测试方法
}
1.如果内存资源只是稍微短缺,同时CPU资源也稍微紧张,那么lzo更合适
"内存稍微短缺"具体对我个人来说就是开虚拟机,内存没zram也基本够用(很少发生OOM之类的事情),只是会大量丢弃缓存造成响应速度大幅下降.
而开虚拟机本身也是一个CPU密集型的负载,所以个人感觉使用lzo对我自己这种情况更合适
2.内存十分紧张,但没有CPU密集型的任务或负载,可以优先考虑使用deflate.

swap_cache_pressure是一个目前(Debian Strethc 4.9内核)失败的尝试
想法是把zram分割成多个较小的swap设备,当时以为这样就容易迫使内核释放swap_cache
但最后仔细看内核代码,是整个VM(全部swap空间)可用空间低于50%时才释放,而非单个swap设备
swap_cache 对 zram 理论上也有提速作用,只不过zram通常速度很快,体现不出来.
同时内核自己本身也会在整个VM(全部swap空间)可用空间低于50%时释放swap_cache
页面变脏时swap_cache也会被释放
所以完全没必要担心swap_cache
参阅:
http://elixir.free-electrons.com/linux/ ... ile.c#L576
http://elixir.free-electrons.com/linux/ ... wap.h#L392
vm_swap_full 中 nr_swap_pages 和 total_swap_pages 的含义:
https://www.kernel.org/doc/gorman/html/ ... nd028.html

关于per-CPU zram:
似乎新版本内核已经不需要这种措施了
Set max number of compression streams
Regardless the value passed to this attribute, ZRAM will always
allocate multiple compression streams - one per online CPUs - thus
allowing several concurrent compression operations. The number of
allocated compression streams goes down when some of the CPUs
become offline. There is no single-compression-stream mode anymore,
unless you are running a UP system or has only 1 CPU online.
在4.9内核甚至不需要设置max_comp_streams
我用time zramswaptest.c 测试时间时per-CPU zram 甚至比单个zram稍慢(差别非常微弱,懒得贴测试结果了,谁要是纠结可以自行按照我说的方法实验)

vm的参数调整参考内核源码树里的vm.txt
echo 100 >/proc/sys/vm/swappiness
swappiness等于100时将file和anonymous页面设置为同等优先级
swappiness小于100时则倾向于优先通过释放文件缓存避免使用swap空间

swappiness扩展阅读

echo 0 >/proc/sys/vm/page-cluster
禁用swap预读,每次只读取一个需要的页面,zram 自身设备延迟非常低,绝大多数时间都是花费在实际读取
page-cluster默认是8
另一些信息显示在使用zram作为交换设备的情况下默认的page-cluster=8可能导致内存浪费

echo 0 >/proc/sys/vm/extfrag_threshold
完全是我自己根据 vm.txt 里的介绍意淫出来的优化措施,没有任何参考资料和测试
目的是尽可能避免因碎片导致内存分配失败.

echo 1 >/proc/sys/vm/watermark_scale_factor
这个参数我还不确定我是否理解正确
结合vm.txt 里的介绍和测试结果,我对 watermark_scale_factor 的理解是其数值越大kswapd越倾向于提前尝试释放内存(释放缓存或swap-out)
如果速度设备比较慢,内存需求的增加速度又较快,这个数值似乎应该调高,此种情况会增加速度
例如将zram设置为较慢的deflate,然后用dd往tmpfs挂载点里写的大量数据(注意要用"yes 12"三个不重复的字节填充,不然可能会被zram直接去重而非压缩)
我这里是往tmpfs写了2048M数据,free显示我有总共1.9G内存
设置为1000比1要稍微快一点.
但这个测试例子很极端甚至无用.
另一个测试是往tmpfs上写入 /dev/urandom 数据(即写入不可压缩数据).
如此这样便可模拟低内存环境,我往tmpfs上写入了1600M 的 /dev/urandom 数据,后台有一个程序不停调用mplayer播放不同文件
设置为1000时可以明显看到kswapd0大量活跃,后台程序调用mplayer播放不同文件的速度也比较慢
设置为1时则立刻停止了无用的swap,后台程序的播放切换速度也跟正常使用时一样,仿佛没有内存压力.
看内核代码和vm.txt 的描述,调高 watermark_scale_factor 的意义基本上等同于调高watermark(一个可用内存阀值,低于此阀值就会触发kswapd)
即使设置为deflate算法,zram 的 速度也通常足够(具体是否足够仍取决于实际速度(CPU速度,内存速度等)),因为桌面环境下swap大多是多次少量随机的进行,不会出现一次读写1600M这种情况.
我把我的E5500调到1.2GHz频率,BIOS设置为单核模式,内核限制为256M,zramswaptest.c测试256M仍然可以完成,时间用了约40秒(记不清了,差不多吧,时间不是重点,重点是没有出现异常(例如分配失败或OOM)).
鉴于此参数设置为1没有显著降低类似dd测试(即短时间内需要大量内存的测试)的速度.
简而言之对于watermark_scale_factor,我的测试结果(deflate算法下):
watermark_scale_factor=1000 显著增加CPU消耗,且速度提升微弱(个人认为可忽略不计)
watermark_scale_factor=1 显著减少CPU消耗,且速度下降微弱(个人认为可忽略不计)
所以在我的脚本里选择watermark_scale_factor=1
这些用户感谢了作者 科学之子 于这个帖子:
vickycq (2017-08-19 22:40)
评价: 3.7%
科学之子
帖子: 2261
注册时间: 2013-05-26 6:58
系统: Debian 9
送出感谢: 842 次
接收感谢: 30 次

Re: [调整queue-fs参数]Debian Wiki的ZRam脚本修改版(修复BUG和更恰当的默认值)

#3

帖子 科学之子 » 2018-09-02 19:19

分享一个适用于Debian initramfs 的zram脚本
里面的内存计算方法参考了Ubuntu的zram-config(无需perl,适合initramfs这种环境)和Debian Wiki上的脚本(计算百分比的算法)

代码: 全选

#!/bin/sh
PREREQ=""
prereqs()
{
   echo "$PREREQ"
}

case $1 in
prereqs)
   prereqs
   exit 0
   ;;
esac

FRACTION=200
MEMORY="$(LC_ALL=C free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/  *.*//')"
SIZE="$(( MEMORY * 1024 * FRACTION / 100 ))"
echo 100 >/proc/sys/vm/swappiness
echo 200 >/proc/sys/vm/swappiness
echo 0 >/proc/sys/vm/page-cluster
echo 0 >/proc/sys/vm/extfrag_threshold
echo 1 >/proc/sys/vm/watermark_scale_factor
modprobe zram num_devices=1
echo "${SIZE}" >/sys/block/zram0/disksize
echo 0 >/sys/block/zram0/queue/read_ahead_kb
echo 2 >/sys/block/zram0/queue/nomerges
echo 2 >/sys/block/zram0/queue/rq_affinity
mkswap /dev/zram0
swapon /dev/zram0
echo 1 >/proc/sys/vm/compact_memory

exit 0
回复

回到 “Shell脚本”