《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #15 ramzswap
HACK #15 ramzswap
本節介紹將一部分內存作為交換設備使用的ramzswap。
ramzswap是將一部分內存空間作為交換設備使用的基于RAM的塊設備。對要換出(swapout)的頁面進行壓縮后,不是寫入磁盤,而是寫入內存。可以使用的內存僅為完成壓縮的部分。壓縮處理使用的是LZO注1。
ramzswap是從Linux 2.6.33合并到Staging驅動程序的。Staging驅動程序是指尚未達到某種程度的質量的試驗性驅動程序。
通過使用ramzswap,運轉速度可以比換出到一般磁盤設備時更高。這是因為內存的I/O較快,且經過壓縮后I/O變小。只有用于嵌入式系統的內存等的機器中,可以避免內存不足時由于內存回收處理導致性能極端下降,或抑制OOM Killer的運行。
ramzswap的項目在如下環境中,即使減去壓縮/解壓縮的CPU系統開銷,也可以提高性能。
上網本或瘦客戶機(thin client)這種配備了內存容量小但CPU性能較高的的PC。
在組裝機器上,不想在外部閃存存儲器(flash memory storage)中生成交換區時。
使用ramzswap時,可以使用已經整合到上游內核的,也可以從論壇中下載并使用。
整合到上游內核的ramzswap實際安裝了論壇的部分成果。本節將針對上游內核和論壇版內核進行介紹。Linux內核以2.6.35為例,論壇數據包以版本0.6.2為例。操作系統使用Fedora 12。
使用論壇版ramzswap
使用論壇版的數據包時,首先需要下載數據包進行編譯。由于要對內核模塊進行編譯,因此必須事先安裝kernel-devel。
make命令結束后,將生成內核模塊ramzswap.ko和ramzswap設備的控制工具—rzscontrol命令和rzscontrol命令的manual文件。
小貼士:ramswap版本0.6.2的運行已經在Linux 2.6.32中確認。使用RHEL6編譯時,需要在ramzswap_drv.c的最前面加上#include 。
rzscontrol命令創建的路徑為compcache-0.6.2/sub-projects/rzscontrol/rzscontrol,manual文件創建的路徑為compcache-0.6.2/sub-projects/rzscontrol/man/rzscontrol.1。ramzswap版本0.6.2不會通過make命令自動安裝。可以直接使用這些文件。
ramzswap的使用方法有兩種。一種是在內存中創建虛擬交換區磁盤的ramzswap disk,另一種是在使用內存的同時使用交換文件或交換塊設備的backing swap。一般系統與使用ramzswap disk、backing swap系統的內存和交換區的關系如圖2-2所示。
圖2-2 一般系統與使用ramzswap disk、backing swap的系統的內存和交換區的關系
首先介紹第一個ramzswap disk。
ramzswap disk的使用方法
使用ramzswap disk,首先需要將用來壓縮/解壓縮數據的LZO模塊安裝到內核中。
注意事項:在部分發布版(Fedora14等)中,把lzo_decompress模塊靜態安裝到內核中,有時會因為沒有模塊而導致modprobe失敗。
# modprobe lzo_decompress FATAL:Module lzo_decompress not found.沒有模塊,也沒有靜態安裝到內核時,對ramzswap.ko執行insmod命令,就會出現如下錯誤。
# insmod ramzswap.ko insmod: error inserting 'ramzswap.ko': -1 Unknown symbol in module自己構建內核時,請將CONFIG_LZO_DECOMPRESS設置為y或m。把像Fedora 14這樣lzo_decompress靜態安裝到內核的情況下,ramzswap.ko的insmod會成功。
接下來安裝ramzswap模塊。這里將設置num_devices=4,以生成4個設備文件。
將ramzswap模塊安裝到內核的同時,還可以設置各參數。下面是設置作為ramzswap disk使用的內存大小的例子。
insmod ramzswap.ko num_devices=4 disksize_kb=20480
只有/dev/ramzswap0的初始化(后面介紹--init選項)和disksize_kb參數設置是自動進行的。/dev/ramzswap1~3的初始化和disksize_kb參數需要另行設置。
后面也可以在rzscontol命令中設置相同參數。但是num_devices只能在安裝模塊時進行設置。表2-9所示為可設置的參數列表。其內容將在后面詳細說明。
表2-9 ramzswap的模塊參數與rzscontrol命令的選項
安裝ramzswap模塊后,為了作為交換區使用對ramzswap設備進行初始化,并啟用交換功能。
# sub-projects/rzscontrol/rzscontrol /dev/ramzswap0 - -init # swapon /dev/ramzswap0這時也可以使用-p選項指定優先級,與已有的交換設備同時使用。這個值較大表示優先級較高,因此應當指定比一般的交換設備更大的值。
# swapon -p 100 /dev/ramzswap0 # swapon -s Filename Type Size Used Priority /dev/ramzswap0 partition 511992 0 100 /dev/sda2 partition 2047992 0 -1這時,ramzswap設備的交換功能就已啟用。使用一定數量的內存后,就會發生換出。
可以使用rzscontrol命令的--stats選項來確認ramzswap的統計信息和狀態。
表2-10為此時的輸出結果和各項目的說明。
表2-10 執行ramzswap disk命令時rzscontrol --stats的輸出結果
由于ramzswap不會立刻釋放保留的內存,因此OrigDataSize和free命令的數值不一定一致。
rzscontrol命令也可以對各個ramzswap設備進行設置。使用--disksize_kb選項可以設置ramzswap設備的大小(單位為千字節)。執行下列命令就可以設置ramzswap設備的容量。
要將ramzswap設備排除在交換對象之外,可以使用swapoff命令。
# swapoff /dev/ramzswap0要關閉ramzswap,需要在swapoff之后使用rzscontrol命令的--reset選項釋放殘留在ramzswap磁盤中的內存。最后將模塊從內核中移除。
# sub-projects/rzscontrol/rzscontrol /dev/ramzswap0 --reset # rmmod ramzswapbacking swap的使用方法
ramzswap還有另一種使用方法,就是將部分內存作為ramzswap disk使用,再將交換文件或交換塊設備作為backing swap使用。
ramswap為內存和磁盤的兩層。如果內存稍有不足,則僅使用內存的ramzswap disk進行處理,但如果缺少更多內存,則頁面的內容存放到backing swap中。
下面介紹backing swap的使用方法。
首先與ramzswap disk同樣進行設置。
然后使用rzscontrol命令指定backing swap。
# sub-projects/rzscontrol/rzscontrol /dev/ramzswap0 --init --backing_swap=/dev/sda2 --memlimit_kb=10240使用--backing_swap選項指定交換文件或交換塊設備。這里指定的是塊設備/dev/sda2。--memlimit_kb選項指定的是作為ramzswap disk使用的內存大小。使用內存的方式基本與ramzswap disk相同。沒有指定時設置為所有內存大小的15%。這里設置為10240KB。
最后啟用已生成設備的交換功能。
內存使用量一旦增加,首先壓縮的頁面會寫入ramzswap disk的區域中。這時未壓縮到50%以下的頁面則寫入backing swap中,而非ramzswap disk中。另外,超過--memlimit_kb選項指定的內存大小時也會寫入backing swap中。
表2-11所示為執行rzscontrol --stats的結果。說明中僅記載與ramzswap disk的不同之處。
表2-11 執行ramzswap --stats的結果
使用上游內核的ramzswap
要使用安裝在上游內核的ramzswap,需要首先啟用內核config(CONFIG_RAMZSWAP=y),編譯內核。使用make menuconfig命令啟用下列項目。
啟動編譯后的內核。
使用方法
使用方法與論壇版相同,但需要另外編譯用于上游內核的rzscontrol命令。由于上游內核驅動程序內沒有安裝backing swap,因此必須修改rzscontrol命令的代碼。
上游內核中還沒有安裝backing swap和memlimit,因此將這部分代碼從這個補丁中刪除。下面使用這個補丁來編譯rzscontrol命令。
按照下列方式指定上游內核的include文件進行編譯。
# gcc -g -Wall -D_GNU_SOURCE rzscontrol.c -o rzscontrol -I /linux-2.6.35/drivers/staging/ramzswap/ -I../include使用方法與論壇版相同。
小結
本節介紹了ramzswap。是否能夠通過壓縮頁面數據受益,是與內存數據的內容相關的。但是即使多少有一些壓縮/解壓縮的系統開銷,也比內存耗盡好得多。這在沒有交換區的無磁盤(diskless)組裝機器中尤其有效。
參考文獻
compcache Compressed Caching for Linux
http://code.google.com/p/compcache/
LZO1X Compressor from MiniLZO
http://www.oberhumer.com/opensource/lzo/
Compcache: in-memory compressed swapping
http://lwn.net/Articles/334649/
—Naohiro Ooiwa
HACK #16 OOM Killer的運行與結構
本節介紹OOM Killer的運行與結構。
Linux中的Out Of Memory(OOM) Killer功能作為確保內存的最終手段,可以在耗盡系統內存或交換區后,向進程發送信號,強制終止該進程。
這個功能即使在無法釋放內存的情況下,也能夠重復進行確保內存的處理過程,防止系統停滯。還可以找出過度消耗內存的進程。本節將介紹2.6內核的OOM Killer。
確認運行、日志
進行系統驗證或負載試驗時,有時會出現正在運行中的進程終止或者SSH連接突然斷開、嘗試重新登錄也無法連接的情況。
這時需要查看日志。有時會輸出如下內核信息。
最后出現了Out of memory(內存不足)。這就表示OOM Killer已經運行。無法重新連接的情況就是因為sshd被OOM Killer終止。如果不重新啟動sshd就無法登錄。
OOM Killer通過終止進程來確保空閑內存,接下來將介紹如何選定這個進程。
進程的選定方法
OOM Killer在內存耗盡時,會查看所有進程,并分別為每個進程計算分數。將信號發送給分數最高的進程。
計算分數的方法
在OOM Killer計算分數時要考慮很多方面。首先要針對每個進程確認下列1~9個事項再計算分數。
1.首先,計算分數時是以進程的虛擬內存大小為基準的。虛擬內存大小可以使用ps命令的VSZ或/proc//status的VmSize注2來確認。對于正在消耗虛擬內存的進程,其最初的得分較高。單位是將1KB作為1個得分。消耗1GB內存的進程,得分約為1 000 000。
2.如果進程正在執行swapoff系統調用,則得分設置為最大值(unsigned long的最大值)。這是因為禁用swap的行為與消除內存不足是相反的,會立刻將其作為OOM Killer的對象進程。
3.如果是母進程,則將所有子進程內存大小的一半作為分數。
首先,用得分除以CPU使用時間(以10秒為單位)的平方根。如果CPU使用時間為90秒,由于以10秒為單位,因此就是用得分除以9的平方根“3”。另外,根據進程啟動開始的時間也可以調整得分。用得分除以啟動時間(以1000秒為單位)的平方根的平方根。如果是持續運行16 000秒的進程,則用得分除以16的平方根“4”的平方根“2”。越是長時間運行的進程就越重要。
小貼士:雖然源代碼的備注中寫有以10秒為單位、以1000秒為單位,但是實際上在位運算中是以8和1024為單位來計算。
5.對于通過nice命令等將優先級設置得較低的進程,要將得分翻倍。nice-n中設置為1~19的命令的得分翻倍。
6.特權進程普遍較為重要,因此將其得分設置為1/4。
7.通過capset(3)等設置了功能(capability)CAP_SYS_RAWIO注3的進程,其得分為1/4。將直接對硬件進行操作的進程判斷為重要進程。
8.關于Cgroup,如果進程只允許與促使OOM Killer運行的進程所允許的內存節點完全不同的內存節點,則其得分為1/8。
9.最后通過proc文件系統oom_adj的值調整得分。
依據以上規則,為所有進程打分,向得分最高的進程發送信號SIGKILL(到Linux 2.6.10為止,在設置了功能CAP_SYS_RAWIO的情況下,發送SIGTERM,在沒有設置的情況下,發送SIGKILL)。
各進程的得分可以使用/proc//oom_score來確認。
但是init(PID為1的)進程不能成為OOM Killer的對象。當成為對象的進程包含子進程時,先向其子進程發送信號。
向成為對象的進程發送信號后,對于引用系統的全線程,即使線程組(TGID)不同,如果存在與對象進程共享相同內存空間的進程,則也向這些進程發送信號。
關于OOM Killer的proc文件系統
下面開始介紹與OOM Killer相關的proc文件系統。
/proc//oom_adj
為/proc//oom_adj設置值就可以調整得分。調整值的范圍為–16~15。正的值容易被OOM Killer選定。負值可能性較低。例如,當指定3時,得分就變為23倍;當指定–5時,得分就變為1/25。
“–17”是一個特殊的值。如果設置為–17,就會禁止OOM Killer發出的信號(從Linux 2.6.12開始支持設置–17)。
在OOM Killer運行的情況下,為了實現遠程登錄而想要將sshd排除在對象外時,可以執行下列命令。
從Linux 2.6.18開始可以使用/proc//oom_adj。內容記載在Documentation /filesystems/proc.txt中。
/proc/sys/vm/panic_on_oom
將/proc/sys/vm/panic_on_oom設置為1時,在OOM Killer運行時可以不發送進程信號,而是使內核產生重大故障。
從Linux 2.6.24開始proc文件系統就有oom_kill_allocating_task。如果對此設置除0以外的值,則促使OOM Killer運行的進程自身將接收信號。此處省略對所有進程的得分計算過程。
# echo 1 > /proc/sys/vm/oom_kill_allocating_task這樣就不需要參照所有進程,但是也不會考慮進程的優先級和root權限等,只發送信號。
/proc/sys/vm/oom_dump_tasks
從Linux 2.6.25開始,將oom_dump_tasks設置為除0以外的值時,在OOM Killer運行時的輸出中會增加進程的列表信息。
下面為設置示例。
列表信息顯示如下,可以使用dmesg或syslog來確認。
[ pid ] uid tgid total_vm rss cpu oom_adj name [ 1] 0 1 2580 1 0 0 init [ 500] 0 500 3231 0 1 -17 udevd [ 2736] 0 2736 1470 1 0 0 syslogd [ 2741] 0 2741 944 0 0 0 klogd [ 2765] 81 2765 5307 0 0 0 dbus-daemon [ 2861] 0 2861 944 0 0 0 acpid ... [ 3320] 0 3320 525842 241215 1 0 stress /proc/<PID>/oom_score_adj從Linux 2.6.36開始都安裝了/proc//oom_score_adj,此后將替換為/proc/ /oom_adj。詳細內容請參考Documentation/feature-removal-schedules.txt。即使當前是對/proc//oom_adj進行的設置,在內核內部進行變換后的值也是針對/proc//oom_score_adj設置的。
/proc//oom_score_adj可以設置–1000~1000之間的值。設置為–1000時,該進程就被排除在OOM Killer強制終止的對象外。
在內核2.6.36以后的版本中寫入oom_adj,只會輸出一次如下的信息。
RHEL5的特征
在RHEL5中運行OOM Killer時要比在上游內核中更加慎重。OOM Killer會計算調用的次數,僅在一定時間段內超出調用一定次數的情況下運行。
1.OOM Killer從上次調出到下一次調出之間超過5秒時,調用次數重新開始計算。這是為了避免僅因為產生突發性的內存負載就終止進程。
2.在計數變成0后的1秒以內調出時,不計入調用的次數。
3.OOM Killer的調用次數不足10次時,實際不會運行。OOM Killer調用10次時才開始認為內存不足。
4.最后OOM Killer運行不到5秒的話,OOM Killer不會再次運行。因此運行頻率最高也有5秒一次。這是為了防止不必要地連續終止多個進程。也有等待接收到OOM Killer發出信號的進程終止(釋放內存)的意思。
也就是說,只有在OOM Killer在5秒以內調出的狀態連續出現10次以上時才會運行。
這些限制原本是到Linux 2.6.10為止都有的。因此在基于Linux 2.6.9的RHEL4中也需要實施這些限制。當前的上游內核中已經取消了這些限制。
RHEL4的運行
查看OOM Killer在RHEL4(Linux 2.6.9)中的運行情況。在下例中,是內存、交換區都為2GB的環境下,使用負載測試工具stress刻意消耗內存。
stress是給內存、CPU、磁盤I/O施加負載的工具。既可以為其中一項增加負載,也可以同時為這三項中的幾項增加負載。stress在運行中如果接收到信號,就會輸出信息并終止。
在上游內核中無法禁用OOM Killer,而在RHEL4中則通過/proc/sys/vm/oom-kill可以禁用OOM Killer。
# echo 0 > /proc/sys/vm/oom-kill或者
# /sbin/sysctl -w vm.oom-kill=0禁用后OOM Killer就不會發送信號,但是會輸出如上內存信息。
RHEL5的運行
在RHEL5(Linux 2.6.18)中對OOM Killer的運行進行確認的方法與RHEL4中相同。
此時的控制臺畫面如下所示。添加了運行OOM Killer時的回溯輸出,便于調試。
Call Trace:
RHEL6的運行
RHEL6.0中OOM Killer計算得分的方式基本和RHEL5中沒有不同。RHEL6系不會如“RHEL5的特征”中所述慎重地運行。其運行基本與上游內核相同。
小結
本節介紹了OOM Killer的結構和各種設置。當系統運行異常時確認syslog等,如果有OOM Killer的輸出,就可以得知曾出現內存不足。
參考文獻
stress
http://weather.ou.edu/~apw/projects/stress/
—Naohiro Ooiwa
轉載于:https://www.cnblogs.com/tcicy/p/8552721.html
總結
以上是生活随笔為你收集整理的《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #15 ramzswap的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是MES系统?本文解释得很清楚了
- 下一篇: linux 其他常用命令