Why'sTheDesign(Why'sTHEDesign)是一系列关于计算机领域编程决策的文章。在本系列的每篇文章中,我们都会提出一个特定的问题,并从不同的角度讨论设计。优缺点,影响具体实施。对Linux稍有了解的人都知道,Linux将物理随机存取存储器(RandomAccessMemory,RAM)按页划分为4KB的内存块,而今天要介绍的Swapping机制就与内存息息相关。它是操作系统将物理内存页的内容复制到硬盘上的交换空间(SwapSpace)来释放内存。硬盘上的物理内存和交换分区构成了操作系统可用的虚拟内存,这些交换空间是系统管理员预先配置的[^1]。图1-LinuxSwapping正是因为Linux上的所有进程都会通过虚拟内存的抽象来间接与物理内存打交道,而Swapping也充分利用了这一特性,让应用程序看到了操作系统内存充足的错觉。但是,我不知道它使用的那部分虚拟内存实际上是在磁盘上的。由于内存和磁盘读写速度的巨大差异,导致这部分虚拟内存的读写非常慢。我们已经介绍过CPU访问硬盘慢的原因:SSD随机访问4KB数据的时间是访问主存的1500倍,机械盘的寻道时间是访问主存的10万倍[^2]如此巨大的性能差异使得触发Swapping的进程可能会遇到Performanceloss。频繁进出同一个页面会导致极其明显的性能抖动。如果没有相应的背景知识,可能很难找到类似问题的根源。例如,当MySQL错误配置NUMA时,会出现内存页频繁换入换出的问题,影响服务质量。Linux提供了两种不同的方式来启用Swapping,分别是SwapPartition和Swapfile:Swap分区是硬盘上一个独立的区域,只用于交换分区,其他文件不能存放在这个区域,我们可以使用swapon-s命令查看当前系统上的交换分区;Swap文件是文件系统中的一个特殊文件,与文件系统中的其他文件没有太大区别;Swap分区的大小需要由系统管理员手动设置。但是,最好在不同的场景下设置不同的交换分区大小。比如桌面系统的交换分区的大小可以是系统内存的两倍,这样我们就可以同时运行更多的应用程序;swap分区应该关闭或者使用少量的swap分区,但是一旦swap分区启用,就应该引入监控来监控应用程序的性能。既然我们对Linux上的Swapping有了一定的了解,那么我们就回到本文要讨论的问题——“为什么Linux需要Swapping?”我们将从以下两个方面介绍Swapping解决和触发入场的问题。以及执行路径:Swapping可以直接换出进程内存不足的相对较少的page,立即分配内存给正在执行的进程;Swapping可以换出进程中的空闲页,为以后其他进程使用内存做准备;内存不足当系统需要的内存超过可用的物理内存时,内核会将内存中不常用的内存页交换到磁盘中为当前进程做内存,保证正在执行的进程的可用性。该过程是强制性的直接内存回收(DirectPageReclaim)。图2-直接内存回收当Linux调用__alloc_pages_nodemask申请新的内存页时,会触发直接内存回收。该函数首先检查空闲页面列表中是否有可用页面。如果没有可用的页面,就会进入__alloc_pages_slowpath函数分配内存页面。与直接从freelist中查找内存相比,该函数通过以下步骤分配内存:get_page_from_freelist(gfp_mask,order,alloc_flags,ac);if(page)gotogot_pg;if(can_direct_reclaim&&(costly_order||(order>0&&ac->migratetype!=MIGRATE_MOVABLE))&&!gfp_pfmemalloc)f_mask(){page=__alloc_pages_direct_compact(gfp_mask,order,alloc_flags,ac,INIT_COMPACT_PRIORITY,&compact_result);if(page)gotogot_pg;...}retry:page=__alloc_pages_direct_reclaim(gfp_mask,order,alloc_flags,ac,&did_some_progress);page=__alloc_pages_direct_compact(gfp_mask,order,alloc_flags,ac,compact_priority,&compact_result);page=__alloc_pages_may_oom(gfp_mask,order,ac,&did_some_progress);got_pg:returnpage;}唤醒kswapd线程在后台回收内存,尝试调用get_page_from_freelist快速从freelist中获取内存页;昂贵的内存申请会先调用__alloc_pages_direct_compact尝试压缩内存页,调用get_page_from_freelist在压缩后的内存中寻找空闲内存页;调用__alloc_pages_direct_reclaim直接回收分配新的内存页;再次调用__alloc_pages_direct_compact,尝试压缩内存,获取空闲内存页;调用__alloc_pages_may_oom分配内存,如果内存分配失败,会触发out-of-memory警告并随机杀掉操作系统上面的几个进程;虽然大大删减了获取内存页的步骤,但展示了Linux在内存不足时获取内存的几种常用方法:内存压缩、直接回收、触发内存不足错误杀死部分进程内存空闲。应用程序在启动阶段使用的大量内存在启动后往往不会被使用。通过后台运行的守护进程,我们可以将这部分只使用一次的内存交换到磁盘上,供其他内存申请使用。空间。kswapd是Linux中负责页面替换(Pagereplacement)的守护进程。它也是负责交换空闲内存的主要进程。当空闲内存低于某个水位时,它会回收内存页中的空闲内存,以确保系统中的其他进程能够尽快使用它。获取请求的内存,如下图所示:图3-Linux空闲页面水位当空闲页面小于WMARK_LOW时,kswapd进程开始工作,将内存页面交换到磁盘直到空闲页面水位返回WMARK_HIGH,但是当freepage的水位低于WMARK_MIN时,会触发上节提到的内存直接回收,水位高于WMARK_HIGH,表示free内存充足,没有恢复是必需的。Linux操作系统使用最近最少使用(LeastRecentlyUsed,LRU)算法来替换内存中的页面。系统中的每个区域都会在内存中保存两个链表,active_list和inactive_list。前者包含活跃的内存页,后者存放的内存页都是回收的候选页。另外,Linux还会根据内存页的特点将lru_list分为以下几种类型:其中包含ANON表示匿名内存页,这些内存页存放的是与文件无关的进程栈的内容,而包含FILE表示与文件相关的内存,即程序文件或数据对应的内存,最后一个LRU_UNEVICTABLE表示禁止回收的内存页。图4-活动链表和非活动链表每当访问内存页时,Linux会将访问过的内存页移动到链表的头部,因此链表中“最旧”的内存页位于活动链表的末尾linkedlist,guarding进程kswapd的作用是平衡两个链表的长度,将active链表尾部的内存页移动到inactive链表的头部进行回收,函数shrink_zones会负责回收LRU链表中不活跃的内存页。总结很多人认为当系统内存不足时,应该立即触发内存不足(Outofmemory,OOM)并杀死进程,但Swapping实际上为系统管理员提供了另一种选择,利用磁盘交换空间来防止程序直接退出,以降低服务质量为代价换取服务的部分可用性。Linux中的Swapping机制主要是针对内存不足和内存空闲这两种常见的情况。swapping可以直接把进程中使用的比较少的pages换出内存:当系统需要的内存超过了可用的物理内存时,kernel会将内存中不常用的内存pages换到磁盘上,为进程腾出内存当前进程并确保执行进程的可用性;Swaping可以换出进程中的空闲页:应用程序在启动阶段使用的大量内存,启动后往往不用。通过后台运行的daemon进程,我们可以将这部分只使用一次的内存交换到磁盘上,为其他内存申请预留空间;关于是否开启Swapping其实有很多讨论。今天,我们不应该全面考虑必须启用或禁用交换。我们还是要分析场景,好好利用Linux提供的这个机制。例如,Kubernetes要求禁用交换。我们应该听从社区的建议,部署Kubernetes。此功能在计算机上已关闭[^3]。最后,让我们看看一些未解决的相关问题。有兴趣的读者可以仔细思考以下问题:Linux提供了哪些参数来控制交换的行为?降低服务质量成本的部分可以用在什么场景下?这是可取的吗?如果您对文章内容有疑问,或者想更多地了解软件工程中一些设计决策背后的原因,可以在博客下留言,作者会及时回复与本文相关的问题并选择适当的主题作为后续内容。参考Kubelet/KubernetesshouldworkwithSwapEnabled#53533https://github.com/kubernetes/kubernetes/issues/53533LinuxPerformance:WhyYouAlmostAlmostAlwaysAddSwapSpacehttps://haydenjames.io/linux-performance-almost-always-add-swap-space/我们真的需要在现代系统上进行交换吗?https://www.redhat.com/en/blog/do-we-really-need-swap-modern-systems本文转载自微信公众号“一点逻辑都没有”,大家可以照着看以下二维码。转载本文请联系真诺逻辑公众号。
