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影片教學》
以上是linux swap是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!