linux swap是怎么触发的

65次阅读
没有评论

共计 6217 个字符,预计需要花费 16 分钟才能阅读完成。

今天丸趣 TV 小编给大家分享一下 linux swap 是怎么触发的的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

linux swap 指的是 linux 交换分区,是磁盘上的一块区域,可以是一个分区,也可以是一个文件,或者是两者的组合;swap 类似于 Windows 的虚拟内存,就是当内存不足时,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。

本教程操作环境:linux5.9.8 系统、Dell G3 电脑。

linux swap

Linux 的交换分区(swap),或者叫内存置换空间(swap space),是磁盘上的一块区域,可以是一个分区,也可以是一个文件,或者是他们的组合。

SWAP 的作用类似 Windows 系统下的“虚拟内存”。当物理内存不足时,拿出部分硬盘空间当 SWAP 分区(虚拟成内存)使用,从而解决内存容量不足的情况。

SWAP 意思是交换,顾名思义,当某进程向 OS 请求内存发现不足时,OS 会把内存中暂时不用的数据交换出去,放在 SWAP 分区中,这个过程称为 SWAP OUT。当某进程又需要这些数据且 OS 发现还有空闲物理内存时,又会把 SWAP 分区中的数据交换回物理内存中,这个过程称为 SWAP IN。

当然,swap 大小是有上限的,一旦 swap 使用完,操作系统会触发 OOM-Killer 机制,把消耗内存最多的进程 kill 掉以释放内存。

数据库系统为什么嫌弃 swap?

显然,swap 机制的初衷是为了缓解物理内存用尽而选择直接粗暴 OOM 进程的尴尬。但坦白讲,几乎所有数据库对 swap 都不怎么待见,无论 MySQL、Oracal、MongoDB 抑或 HBase,为什么?这主要和下面两个方面有关:

1. 数据库系统一般都对响应延迟比较敏感,如果使用 swap 代替内存,数据库服务性能必然不可接受。对于响应延迟极其敏感的系统来讲,延迟太大和服务不可用没有任何区别,比服务不可用更严重的是,swap 场景下进程就是不死,这就意味着系统一直不可用……再想想如果不使用 swap 直接 oom,是不是一种更好的选择,这样很多高可用系统直接会主从切换掉,用户基本无感知。

2. 另外对于诸如 HBase 这类分布式系统来说,其实并不担心某个节点宕掉,而恰恰担心某个节点夯住。一个节点宕掉,最多就是小部分请求短暂不可用,重试即可恢复。但是一个节点夯住会将所有分布式请求都夯住,服务器端线程资源被占用不放,导致整个集群请求阻塞,甚至集群被拖垮。

从这两个角度考虑,所有数据库都不喜欢 swap 还是很有道理的!

swap 的工作机制

既然数据库们对 swap 不待见,那是不是就要使用 swapoff 命令关闭磁盘缓存特性呢?非也,大家可以想想,关闭磁盘缓存意味着什么?实际生产环境没有一个系统会如此激进,要知道这个世界永远不是非 0 即 1 的,大家都会或多或少选择走在中间,不过有些偏向 0,有些偏向 1 而已。很显然,在 swap 这个问题上,数据库必然选择偏向尽量少用。HBase 官方文档的几点要求实际上就是落实这个方针:尽可能降低 swap 影响。知己知彼才能百战不殆,要降低 swap 影响就必须弄清楚 Linux 内存回收是怎么工作的,这样才能不遗漏任何可能的疑点。

先来看看 swap 是如何触发的?

简单来说,Linux 会在两种场景下触发内存回收,一种是在内存分配时发现没有足够空闲内存时会立刻触发内存回收;一种是开启了一个守护进程(swapd 进程)周期性对系统内存进行检查,在可用内存降低到特定阈值之后主动触发内存回收。第一种场景没什么可说,来重点聊聊第二种场景,如下图所示:

这里就要引出我们关注的第一个参数:vm.min_free_kbytes,代表系统所保留空闲内存的最低限 watermark[min],并且影响 watermark[low]和 watermark[high]。简单可以认为:

watermark[min] = min_free_kbytes
watermark[low] = watermark[min] * 5 / 4 = min_free_kbytes * 5 / 4
watermark[high] = watermark[min] * 3 / 2 = min_free_kbytes * 3 / 2
watermark[high] - watermark[low] = watermark[low] - watermark[min] = min_free_kbytes / 4

可见,LInux 的这几个水位线与参数 min_free_kbytes 密不可分。min_free_kbytes 对于系统的重要性不言而喻,既不能太大,也不能太小。

min_free_kbytes 如果太小,[min,low]之间水位的 buffer 就会很小,在 kswapd 回收的过程中一旦上层申请内存的速度太快(典型应用:数据库),就会导致空闲内存极易降至 watermark[min]以下,此时内核就会进行 direct reclaim(直接回收),直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因此实际会阻塞应用程序,带来一定的响应延迟。当然,min_free_kbytes 也不宜太大,太大一方面会导致应用程序进程内存减少,浪费系统内存资源,另一方面还会导致 kswapd 进程花费大量时间进行内存回收。再看看这个过程,是不是和 Java 垃圾回收机制中 CMS 算法中老生代回收触发机制神似,想想参数 -XX:CMSInitiatingOccupancyFraction,是不是?官方文档中要求 min_free_kbytes 不能小于 1G(在大内存系统中设置 8G),就是不要轻易触发直接回收。

至此,基本解释了 Linux 的内存回收触发机制以及我们关注的第一个参数 vm.min_free_kbytes。接下来简单看看 Linux 内存回收都回收些什么。Linux 内存回收对象主要分为两种:

1. 文件缓存,这个容易理解,为了避免文件数据每次都要从硬盘读取,系统会将热点数据存储在内存中,提高性能。如果仅仅将文件读出来,内存回收只需要释放这部分内存即可,下次再次读取该文件数据直接从硬盘中读取即可(类似 HBase 文件缓存)。那如果不仅将文件读出来,而且对这些缓存的文件数据进行了修改(脏数据),回收内存就需要将这部分数据文件写会硬盘再释放(类似 MySQL 文件缓存)。

2. 匿名内存,这部分内存没有实际载体,不像文件缓存有硬盘文件这样一个载体,比如典型的堆、栈数据等。这部分内存在回收的时候不能直接释放或者写回类似文件的媒介中,这才搞出来 swap 这个机制,将这类内存换出到硬盘中,需要的时候再加载出来。

具体 Linux 使用什么算法来确认哪些文件缓存或者匿名内存需要被回收掉,这里并不关心,有兴趣可以参考这里。但是有个问题需要我们思考:既然有两类内存可以被回收,那么在这两类内存都可以被回收的情况下,Linux 到底是如何决定到底是回收哪类内存呢?还是两者都会被回收?这里就牵出来了我们第二个关心的参数:swappiness,这个值用来定义内核使用 swap 的积极程度,值越高,内核就会积极地使用 swap,值越低,就会降低对 swap 的使用积极性。该值取值范围在 0~100,默认是 60。这个 swappiness 到底是怎么实现的呢?具体原理很复杂,简单来讲,swappiness 通过控制内存回收时,回收的匿名页更多一些还是回收的文件缓存更多一些来达到这个效果。swappiness 等于 100,表示匿名内存和文件缓存将用同样的优先级进行回收,默认 60 表示文件缓存会优先被回收掉,至于为什么文件缓存要被优先回收掉,大家不妨想想(回收文件缓存通常情况下不会引起 IO 操作,对系统性能影响较小)。对于数据库来讲,swap 是尽量需要避免的,所以需要将其设置为 0。此处需要注意,设置为 0 并不代表不执行 swap 哦!

至此,我们从 Linux 内存回收触发机制、Linux 内存回收对象一直聊到 swap,将参数 min_free_kbytes 以及 swappiness 进行了解释。接下来看看另一个与 swap 有关系的参数:zone_reclaim_mode,文档说了设置这个参数为 0 可以关闭 NUMA 的 zone reclaim,这又是怎么回事?提起 NUMA,数据库们又都不高兴了,很多 DBA 都曾经被坑惨过。那这里简单说明三个小问题:NUMA 是什么?NUMA 和 swap 有什么关系?zone_reclaim_mode 的具体意义?

NUMA(Non-Uniform Memory Access)是相对 UMA 来说的,两者都是 CPU 的设计架构,早期 CPU 设计为 UMA 结构,如下图 (图片来自网络) 所示:

为了缓解多核 CPU 读取同一块内存所遇到的通道瓶颈问题,芯片工程师又设计了 NUMA 结构,如下图(图片来自网络)所示:

这种架构可以很好解决 UMA 的问题,即不同 CPU 有专属内存区,为了实现 CPU 之间的”内存隔离”,还需要软件层面两点支持:

1. 内存分配需要在请求线程当前所处 CPU 的专属内存区域进行分配。如果分配到其他 CPU 专属内存区,势必隔离性会受到一定影响,并且跨越总线的内存访问性能必然会有一定程度降低。

2. 另外,一旦 local 内存(专属内存)不够用,优先淘汰 local 内存中的内存页,而不是去查看远程内存区是否会有空闲内存借用。

这样实现,隔离性确实好了,但问题也来了:NUMA 这种特性可能会导致 CPU 内存使用不均衡,部分 CPU 专属内存不够使用,频繁需要回收,进而可能发生大量 swap,系统响应延迟会严重抖动。而与此同时其他部分 CPU 专属内存可能都很空闲。这就会产生一种怪现象:使用 free 命令查看当前系统还有部分空闲物理内存,系统却不断发生 swap,导致某些应用性能急剧下降。见叶金荣老师的 MySQL 案例分析:《找到 MySQL 服务器发生 SWAP 罪魁祸首》。

所以,对于小内存应用来讲,NUMA 所带来的这种问题并不突出,相反,local 内存所带来的性能提升相当可观。但是对于数据库这类内存大户来说,NUMA 默认策略所带来的稳定性隐患是不可接受的。因此数据库们都强烈要求对 NUMA 的默认策略进行改进,有两个方面可以进行改进:

1. 将内存分配策略由默认的亲和模式改为 interleave 模式,即会将内存 page 打散分配到不同的 CPU zone 中。通过这种方式解决内存可能分布不均的问题,一定程度上缓解上述案例中的诡异问题。对于 MongoDB 来说,在启动的时候就会提示使用 interleave 内存分配策略:

WARNING: You are running on a NUMA machine.
We suggest launching mongod like this to avoid performance problems:
numactl –interleave=all mongod [other options]

2. 改进内存回收策略:此处终于请出今天的第三个主角参数 zone_reclaim_mode,这个参数定义了 NUMA 架构下不同的内存回收策略,可以取值 0 /1/3/4,其中 0 表示在 local 内存不够用的情况下可以去其他的内存区域分配内存;1 表示在 local 内存不够用的情况下本地先回收再分配;3 表示本地回收尽可能先回收文件缓存对象;4 表示本地回收优先使用 swap 回收匿名内存。可见,HBase 推荐配置 zone_reclaim_mode=0 一定程度上降低了 swap 发生的概率。

不都是 swap 的事

至此,我们探讨了三个与 swap 相关的系统参数,并且围绕 Linux 系统内存分配、swap 以及 NUMA 等知识点对这三个参数进行了深入解读。除此之外,对于数据库系统来说,还有两个非常重要的参数需要特别关注:

1. IO 调度策略:这个话题网上有很多解释,在此并不打算详述,只给出结果。通常对于 sata 盘的 OLTP 数据库来说,deadline 算法调度策略是最优的选择。

2. THP(transparent huge pages)特性关闭。THP 特性笔者曾经疑惑过很久,主要疑惑点有两点,其一是 THP 和 HugePage 是不是一回事,其二是 HBase 为什么要求关闭 THP。经过前前后后多次查阅相关文档,终于找到一些蛛丝马迹。这里分四个小点来解释 THP 特性:

(1)什么是 HugePage?

网上对 HugePage 的解释有很多,大家可以检索阅读。简单来说,计算机内存是通过表映射(内存索引表)的方式进行内存寻址,目前系统内存以 4KB 为一个页,作为内存寻址的最小单元。随着内存不断增大,内存索引表的大小将会不断增大。一台 256G 内存的机器, 如果使用 4KB 小页, 仅索引表大小就要 4G 左右。要知道这个索引表是必须装在内存的,而且是在 CPU 内存,太大就会发生大量 miss,内存寻址性能就会下降。

HugePage 就是为了解决这个问题,HugePage 使用 2MB 大小的大页代替传统小页来管理内存,这样内存索引表大小就可以控制的很小,进而全部装在 CPU 内存,防止出现 miss。

(2)什么是 THP(Transparent Huge Pages)?

HugePage 是一种大页理论,那具体怎么使用 HugePage 特性呢?目前系统提供了两种使用方式,其一称为 Static Huge Pages,另一种就是 Transparent Huge Pages。前者根据名称就可以知道是一种静态管理策略,需要用户自己根据系统内存大小手动配置大页个数,这样在系统启动的时候就会生成对应个数的大页,后续将不再改变。而 Transparent Huge Pages 是一种动态管理策略,它会在运行期动态分配大页给应用,并对这些大页进行管理,对用户来说完全透明,不需要进行任何配置。另外,目前 THP 只针对匿名内存区域。

(3)HBase(数据库)为什么要求关闭 THP 特性?

THP 是一种动态管理策略,会在运行期分配管理大页,因此会有一定程度的分配延时,这对追求响应延时的数据库系统来说不可接受。除此之外,THP 还有很多其他弊端,可以参考这篇文章《why-tokudb-hates-transparent-hugepages》

(4)THP 关闭 / 开启对 HBase 读写性能影响有多大?

为了验证 THP 开启关闭对 HBase 性能的影响到底有多大,本人在测试环境做了一个简单的测试:测试集群仅一个 RegionServer,测试负载为读写比 1:1。THP 在部分系统中为 always 以及 never 两个选项,在部分系统中多了一个称为 madvise 的选项。可以使用命令 echo never/always /sys/kernel/mm/transparent_hugepage/enabled 来关闭 / 开启 THP。测试结果如下图所示:

如上图,TPH 关闭场景下(never)HBase 性能最优,比较稳定。而 THP 开启的场景(always),性能相比关闭的场景有 30% 左右的下降,而且曲线抖动很大。可见,HBase 线上切记要关闭 THP。

以上就是“linux swap 是怎么触发的”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,丸趣 TV 小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-03发表,共计6217字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)