kkt*_*uri 7 linux cache swap zram tmpfs
考虑以下场景。您有一个安装了 Linux的慢速只读媒体(例如写保护的拇指驱动器、CD/DVD 等)(不是 Live CD 本身,而是正常版本),并且在没有字面意义的计算机上使用它其他形式的存储。它很慢,因为它是 USB 2。根文件系统作为overlayfs 挂载,因此它对于日志和您所做的许多其他临时工作是“可写的”,但所有写入都转到 RAM (tmpfs upperdir)。为Live发行情况非常典型的场景。
由于没有其他形式的存储,swap 挂载在 zram 上。因此,当 Linux 决定交换时,它会压缩这些页面并将它们仍然存储在 RAM 中,但至少它们是被压缩的。这实际上很不错,因为大多数应用程序的 RAM 很容易压缩(RAM 通常在数据中非常冗余,因为它意味着“快速”)。这适用于应用程序内存,但不适用于 tmpfs。
事情是这样的:zram很快,令人难以置信。另一方面,拇指驱动器很慢。假设它是 20 MiB/s,相比之下这真的很慢。您可以在这里看到问题以及为什么内核不会做正确的事情。
请注意,此问题不是重复如何使 TMPFS 内的文件更可能交换。问题几乎相同,但我对那个问题的答案并不满意,抱歉。内核绝对不会不自行做“正确的事”,不管如何聪明的人设计它是。我不喜欢人们不了解情况并认为他们更了解情况。他们迎合一般情况。这就是 Linux 具有如此可调整性的原因,因为无论它多么智能,它都无法预测它的用途。
例如,我可以(并且确实)将vm.swappiness (/proc/sys/vm/swappiness) 设置为 100,这告诉它积极交换应用程序内存并保留文件缓存。这个选项很好,但不幸的是,它不是全部。
我希望它在处理交换时将文件缓存优先于任何其他 RAM 使用。这是因为丢弃文件缓存导致它不得不从慢20 MIB /秒的驱动器,这是多读回多比交换zram慢。对于应用程序,vm.swappiness 有效,但不适用于 tmpfs。
tmpfs 挂载为页缓存,因此它与文件缓存具有相同的优先级。如果您从 tmpfs 读取文件,它将优先于较旧的文件缓存条目(最近使用)。但是,这是不好的,内核显然没有做正确的事情在这里。应该考虑将 tmpfs 交换为 zram 比文件缓存“最近使用”要好得多,因为从驱动器读取非常慢。
所以我需要明确地告诉它与文件缓存相比更频繁地从 tmpfs 交换:它应该比 tmpfs 保留更多的文件缓存。/proc/sys/vm 中有很多选项,但我找不到。真让人失望。
如果做不到这一点,有没有办法告诉内核某些设备/驱动器比其他设备/驱动器慢得多,并且它应该比其他人更愿意为它们保留缓存?tmpfs 和 zram 很快。拇指驱动器不是。我可以告诉内核这个信息吗?
如果它对所有驱动器都一视同仁,它就不能自己做“正确的事情”。将 tmpfs 交换到像 zram 这样的快速驱动器比从慢速驱动器中删除缓存要快得多,即使最近使用了 tmpfs。
当它用完可用内存时,它将开始由于swappiness而交换应用程序内存(好),或者丢弃旧文件缓存(坏)。如果我最终从这些文件中重新读取,它会很慢。比决定交换一些 tmpfs 慢得多,即使最近使用过,然后再次从中读取。因为 zram 快了一个数量级。
增加swappiness值使内核更愿意交换 tmpfs 页面,并且不太愿意从其他没有交换支持的文件系统中驱逐缓存页面。
由于 zram swap 比您的拇指驱动器快,因此您最好将 swappiness 增加到 100 以上。这只能在内核版本 5.8 或更高版本中实现。Linux 5.8 允许将 swappiness 设置为最大 200。
对于内存交换,如 zram 或 zswap,可以考虑超过 100 的 [...] 值。例如,如果针对交换设备的随机 IO 平均比来自文件系统的 IO 快 2 倍,则 swappiness 应该是 133 (x + 2x = 200, 2x = 133.33)。
请参阅内核提交“ vmscan:将 LRU 列表拆分为匿名和文件集”-
将 LRU 列表分成两部分,一组用于由真实文件系统(“文件”)支持的页面,一组用于由内存和交换(“匿名”)支持的页面。后者包括 tmpfs。
- 以及linux-4.16/mm/vmscan.c:2108处的代码-
/*
* Determine how aggressively the anon and file LRU lists should be
* scanned. The relative value of each set of LRU lists is determined
* by looking at the fraction of the pages scanned we did rotate back
* onto the active list instead of evict.
*
* nr[0] = anon inactive pages to scan; nr[1] = anon active pages to scan
* nr[2] = file inactive pages to scan; nr[3] = file active pages to scan
*/
static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
struct scan_control *sc, unsigned long *nr,
unsigned long *lru_pages)
{
int swappiness = mem_cgroup_swappiness(memcg);
Run Code Online (Sandbox Code Playgroud)
...
/*
* With swappiness at 100, anonymous and file have the same priority.
* This scanning priority is essentially the inverse of IO cost.
*/
anon_prio = swappiness;
file_prio = 200 - anon_prio;
Run Code Online (Sandbox Code Playgroud)
随着快速随机 IO 设备(SSD、PMEM)和内存交换设备(如 zswap)的出现,交换可能比文件系统快得多,并且交换比颠簸文件系统缓存更可取。
允许设置 swappiness - 它定义了页面缓存和交换支持页面之间缓存未命中的粗略相对 IO 成本 - 通过使交换首选范围可配置来反映这种情况。
这是 Linux 5.8 中一系列补丁的一部分。在以前的版本中,Linux的“大多无二页面缓存并按照交换,直到VM正在显著内存压力”。这是因为“算法发展所依据的旋转驱动器的高寻道成本也意味着错误可能会因过于激进的交换(主要是随机 IO)而迅速导致锁定。”
本系列旨在解决这个问题。自提交(“a528910e12ec mm:基于 thrash 检测的文件缓存大小调整”)以来,我们可以准确跟踪 refault IO - 回收错误页面的最终成本。这允许我们使用基于 IO 成本的平衡模型,该模型在缓存抖动时更积极地扫描匿名内存,同时能够避免不必要的交换风暴。
这些补丁将 LRU 平衡基于每个列表上的错误率,乘以交换设备和文件系统之间的相对 IO 成本(swappiness),以优化回收以产生最少的 IO 成本。