2021-05-12 14:32:11
深入理解作業系統記憶體
圖片來源:http://www.tomshardware.com/
序言:
Memory(記憶體)是一台計算機組成的重要部分,也是最基礎的一部分。其它基礎元件有主機板、CPU、磁碟、顯示卡(可獨立可整合)等。寫這篇文章源自後面的一個案例,出於想搞明白,以及分享以前關於記憶體方面的一些記錄的知識點。
本文概要主要講了記憶體的介紹;如何正確檢視系統記憶體使用率;對Swap分割區進行介紹;如何將記憶體當作硬碟來加速資料讀寫,以及分享關於記憶體異常的案例分析;介紹了oom-killer的機制。
一、記憶體的介紹
1.何為記憶體
記憶體 是一種利用半導體技術製成的儲存資料的電子裝置。其電子電路中的資料以二進位制方式儲存,記憶體的每一個儲存單元稱做記憶元。記憶體根據儲存能力及電源關係又可分為易失性記憶體(斷電後丟失),非易失性記憶體(斷電後持久)。
- 易失性記憶體:是指當電源供應中斷後,記憶體所儲存的資料將會丟失。有兩類:動態隨機存取記憶體(DRAM),靜態隨機存取記憶體(SRAM)。後者速度更快。
- 非易失性記憶體:是指當電源供應中斷後,記憶體說儲存的資料並不會小時。供電恢復後,資料可用正常讀取(有很小的幾率會出現資料損壞的情況)。有三類,唯讀記憶體、快閃記憶體、磁碟(磁碟就是我們最常見的非易失性記憶體的記憶體)
- 後文所出現‘記憶體’字樣,均指易失性記憶體。
2.記憶體、CPU、磁碟三者的關係
- 記憶體與cpu的關係:cpu(中央處理器)就像人類的大腦一樣,負責解釋計算機指令以及處理計算機軟體中的資料。由於cpu需要處理資料,如果直接從硬碟中讀取寫入資料,以現在的機械定址的硬碟和固態SSD硬碟的速度來比較,兩者差距太大。所以記憶體作為CPU和硬碟 兩者的橋樑存在,另外CPU與記憶體之間為了縮小讀寫差距,CPU技術加入了快取記憶體概念(L1、L2、L3,三種級別的Cache),一般在CPU產品型號技術參數列中都會具體的介紹。
- 記憶體與硬碟的關係:程式是在記憶體上執行的,為了加快讀速度,記憶體會將讀取過的資料在自身中進行快取。直到cache已滿,會釋放最先快取的資料,將其寫入磁碟,並騰出一定空間來滿足當前正在讀取的新資料。硬碟是為了持久化儲存程序執行的資料,保證資料在機器斷電後不被丟失。
二、如何正確檢視記憶體的使用率
1.free 命令檢視記憶體使用
[root@docker ~]# free total used free shared buff/cache available Mem: 1883740 440288 896080 31024 547372 1256984 Swap: 0 0 0
註:本機已關閉swap分割區。
- 物理總記憶體total:1883740KB / 1024 =1.8G(這裡不包括核心在啟動時為其自身保留的一小部分,所以這裡是1.8G,而其實是2G記憶體)
- 使用記憶體:1883740KB - 896080KB -547372KB = 440288KB(計算公式:total - free - buffers - cache = used)
- free 空閒記憶體:1883740KB - 440288KB -547372KB = 440288KB(同used計算公式)
- shared共用記憶體:被tmpfs使用的(大部分)記憶體
- buffers緩衝區:核心緩衝區使用的記憶體(寫資料時的緩衝)
- cache快取:頁面快取和slab 使用的記憶體 (註:slab記憶體分配機制 參考頁面點此)(讀資料時的快取,設定drop_cache=3,使用time分別計算 讀檔案開啟時間,動態watch cache的大小)
- available有效記憶體:估計有多少記憶體可用於啟動新的應用程式,沒有交換。 與快取或free欄位提供的資料不同,此欄位考慮到頁面快取,並且由於專案正在使用,並不是所有可回收記憶體板都將被回收。(由系統動態的估算,此值相當於6.x系統裡 free+cache+buffers的可用記憶體)
2.top 檢視進程使用的記憶體
可指定進程檢視,不加引數顯示所有的進程,以及概覽。
[root@docker ~]# top -p `pgrep nginx|head -n 1` ...省略 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 26826 root 20 0 45816 1000 0 S 0.0 0.1 0:00.00 nginx
注釋:
第一行,顯示了預設的欄位,另top狀態下,可輸入 f 鍵,進行選擇其它欄位,如DATA、SWAP等
第二行,顯示欄位的值。這裡說下進程RES (駐留記憶體空間)和%MEM的關係,%MEM 是該進程佔用系統物理total記憶體的百分比。RES計算方式:total*%MEM=RES;VIRT包括所需要的程式碼、資料和共用庫。
3.vmstat 檢視虛擬記憶體使用以及swap分割區 和系統、cpu的io 報告
[root@docker ~]# vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 4 0 0 858708 15756 571772 0 0 6 49 16 0 8 0 92 0 0
三、Swap——與記憶體緊密相關的交換空間
1.Swap 用途介紹
當實體記憶體(RAM)的數量已滿時,會使用Linux中的swap交換空間。如果系統需要更多記憶體資源並且RAM已滿,則記憶體中的非活動頁面將移動到交換空間中。雖然交換空間可以幫助機器使用少量的RAM,但不應該被認為是更多RAM的替代品。因為交換空間位於硬碟機上,存取時間比實體記憶體慢的很多。發生的交換越多,系統越慢。
Linux有兩種形式的交換空間:交換分割區和交換檔案。交換分割區是僅用於交換的硬碟的獨立部分,沒有其他檔案可以存放在那裡。交換檔案是位於系統和資料檔案之間在檔案系統中的一個特殊檔案。另外,swap 空間一般設定實體記憶體的2倍。
2.啟用或禁止交換空間
- 啟用:如果覺得伺服器應用對記憶體的讀寫不是特別在意,但伺服器記憶體又很小的話,可設定開啟swap 交換空間。
- 禁止:一種情況是當主機記憶體夠大時,如果開啟swap空間,當發生實體記憶體使用到達核心設定的一個臨界值時(稍後會講),記憶體中的資料會移動到swap交換空間內,而這時,實體記憶體還是有很多的。由於swap分割區是走磁碟IO,所以我們有必要修改這個臨界值或者禁止使用swap分割區。還有一種情況就是我們的客戶機作業系統是虛擬機器(如kvm虛擬化上的),這個時候是要一定禁止swap分割區的。
3.如何啟用或禁用交換空間
檢視當前swap空間狀態
root@docker ~]# swapon -s 檔名 型別 大小 已用 許可權 /mnt/os_swap file 4194300 0 -1
禁用swap空間
[root@docker ~]# swapoff -a
啟用swap空間(這裡使用的檔案形式作為swap分割區)
[root@docker ~]# swapon /mnt/os_swap
4.建立swap分割區大小
- 用檔案形式來建立swap
在當前的檔案系統裡,用dd或者fallocate(更快更簡單)建立一個用於swap分割區的檔案:
[root@docker ~]# dd if=/dev/zero of=/mnt/os_swap bs=1M count=4096
或
[root@docker ~]# fallocate -l 4G /mnt/os_swap
修改該檔案許可權為600
[root@docker ~]# chmod 600 /mnt/os_swap
使用mkswap命令將檔案建成一個交換空間(也可在最後用 -p size 指定劃分給swap空間的大小,預設使用整個file 大小)
[root@docker ~]# mkswap /mnt/os_swap mkswap: /mnt/os_swap: warning: wiping old swap signature. 正在設定交換空間版本 1,大小 = 4194300 KiB 無標籤,UUID=fc870bd5-c823-4e70-9d14-966543a52db2
使用swap分割區,並檢查swap空間大小
[root@docker ~]# swapon /mnt/os_swap [root@docker ~]# swapon -s 檔名 型別 大小 已用 許可權 /mnt/os_swap file 4194300 0 -1
- 用磁碟分割區的方式建立swap
首先找到一個大小合適的磁碟分割區,分割區型別選擇82-Linux Swap。然後之後和上述類似,用mkswap命令建立啟用swap分割區。並用swapon /dev/vdb1(vdb1為分割區裝置)命令啟用swap分割區。
5.swappiness-系統什麼時候開始使用交換空間
當我們設定啟用swap分割區後,系統會在什麼情況下使用交換空間?這要從物理RAM記憶體使用情況來看,系統核心引數定義了這個界限:vm.swappiness,該引數取值範圍在0-100之間,它定義了當系統剩餘記憶體是總記憶體的多少百分比後,即開始使用交換空間。(暫時對這句話保持質疑,經過多方記憶體使用的測試,系統在由RAM轉向Swap空間時並沒有一個固定的剩餘記憶體值!如你有相關計算方式,還望不吝賜教,謝謝!)
vm.swappiness 預設值是60。swappiness引數的值越高,表示核心將會更積極地從記憶體到交換空間中移動資料。經測試
當值為0時,系統可用記憶體在使用完後再使用swap進行交換。
當值為1時,和0的區別不大。
推薦在資料庫讀寫資料密集的應用中禁用swap交換空間或者設定更低的vm.swappiness值,避免更多的硬碟IO操作,以此作為提高讀寫速度的一個方式。
四、如何將記憶體當作磁碟使用來加速資料讀寫
1.記憶體檔案系統介紹
圖片來源:www.thomas-krenn.com
如上圖所示,利用記憶體作為特殊檔案系統,目前知道的方式有3種,RAMdisk、ramfs、tmpfs。
ramdisk:RAM disk是使用主系統記憶體作為塊裝置的一種方式。它也可用於臨時檔案系統的加密工作,因為內容在重新啟動時將被擦除。由於這個塊裝置大小是固定的,因此安裝存放在其上面的檔案系統是固定的大小。
ramfs:Ramfs是一個非常簡單的檔案系統,用於匯出Linux的磁碟快取 機制(頁面快取和dentry快取)基於RAM的檔案系統,可以動態的根據需要調整大小(前提不超過總RAM的情況)。通常,檔案都被Linux快取在記憶體中,資料頁從後備儲存(通常是安裝檔案系統的塊裝置)中讀取並被儲存 防止它再次需要,但標記為乾淨(可自由使用的),以防萬一 虛擬記憶體系統需要其他記憶體。但ramfs 是沒有後備儲存的,像往常一樣,寫入ramfs的檔案分配 dentry和頁面快取,但是沒有地方可寫。這意味著頁面從未被標記為乾淨,因此當VM正在尋找回收記憶體時,它們不能被釋放 。除非關機斷電。
tmpfs:將所有檔案儲存在虛擬記憶體中的檔案系統。tmpfs中的所有內容都是臨時的,因為在你的硬碟上不會有檔案被建立。如果解除安裝tmpfs範例, 儲存在其中的一切都丟失。如果你umount tmpfs檔案系統,儲存在裡面的內容將丟失。tmpfs可以將所有內容放入核心內部快取並增長收縮以容納它包含的檔案,並能夠交換不需要的頁面到swap交換空間。由於tmpfs 完全位於頁面快取和交換中,所有tmpfs頁面將在/proc/meminfo 和‘shared’ 中顯示為 ”Shmem“
2.它們三的簡單比較
ramfs與ramdisk比較:使用ram disk還需要不必要地將偽造塊裝置中的記憶體複製到頁面快取(並複製更改),以及建立和銷毀dentries。此外,它還需要一個檔案系統驅動程式(如ext2)來格式化和解釋這些資料。與ramfs相比,這浪費了記憶體(和記憶體匯流排頻寬),為CPU創造了不必要的工作,並汙染了CPU快取記憶體。更重要的一點,ramfs的所有的工作都發生在_anyway_,因為所有檔案存取都通過頁面和dentry快取。 RAM disk是不必要的; ramfs在內部更簡單,使用起來更靈活,大小可隨著需要的空間而動態增加或減少。
ramfs與tmpfs比較:ramfs的一個缺點是你可以持續的往裡面寫入資料,直到填滿所有的記憶體,並且VM無法釋放它,因為VM認為檔案應該寫入後備儲存(而不是交換空間),但是ramfs 它沒有任何後備儲存。因此,只有root(或受信任的使用者)才允許對ramfs mount進行寫存取。建立一個名為tmpfs的ramfs派生物,以增加大小限制和能力,將資料寫入swap交換空間。普通使用者也可以允許寫入許可權 tmpfs掛載。
3.如何設定ramfs
建立一個目錄,用於掛載ramfs
[root@docker ~]# mkdir /ramfs_test
掛載ramfs到上一步建立的目錄中
[root@docker ~]# mount -t ramfs ramfs /ramfs_test/ 檢查 [root@docker ~]# mount |grep ramfs_test ramfs on /ramfs_test type ramfs (rw,relatime)
測試一下ramfs與磁碟io讀寫的比較,一目了然。
[root@docker ~]# dd if=/dev/zero of=/ramfs_test/testfile.ramfs bs=1M count=1000 記錄了1000+0 的讀入 記錄了1000+0 的寫出 1048576000位元組(1.0 GB)已複製,0.60369 秒,1.7 GB/秒 [root@docker ~]# dd if=/dev/zero of=/tmp/testfile.ramfs bs=1M count=1000 記錄了1000+0 的讀入 記錄了1000+0 的寫出 1048576000位元組(1.0 GB)已複製,13.3286 秒,78.7 MB/秒
另外一個需要說明,網上大部分文章說掛載ramfs時,可以指定maxsize,即使用的最大的記憶體,經過測試,size(maxsize)引數沒有生效,我使用以下命令進行掛載:
[root@docker ~]# mount -t ramfs ramfs /ramfs_test -o size=1024M && mount | grep ramfs ramfs on /ramfs_test type ramfs (rw,relatime,size=1024M)
然後放入一個大於1G的檔案,並檢查大小
[root@docker ~]# dd if=/dev/zero of=/ramfs_test/testramfs.file bs=1M count=1200 記錄了1200+0 的讀入 記錄了1200+0 的寫出 1258291200位元組(1.3 GB)已複製,0.78763 秒,1.6 GB/秒 [root@docker ~]# ll -h /ramfs_test/testramfs.file -rw-r--r-- 1 root root 1.2G 6月 2 09:04 /ramfs_test/testramfs.file
從上面可以看出,使用ramfs作檔案系統,並沒有受到限制,所以它有可能佔用系統全部的RAM,並導致系統死鎖,無法進行操作,系統核心將崩潰。所以這裡在使用ramfs時,要慎重考慮使用場景,避免程式故障或記憶體溢位導致系統崩潰,必須重新啟動才能解決!另外檢視了mount的man 手冊,掛載ramfs內容時只有以下內容:
Mount options for ramfs Ramfs is a memory based filesystem. Mount it and you have it. Unmount it and it is gone. Present since Linux 2.3.99pre4. There are no mount options.
而,size引數只適用於tmpfs!
Mount options for tmpfs size=nbytes Override default maximum size of the filesystem. The size is given in bytes, and rounded up to entire pages. The default is half of the memory. The size parameter also accepts a suffix % to limit this tmpfs instance to that percentage of your physical RAM: the default, when neither size nor nr_blocks is specified, is size=50%
4.如何設定tmpfs
和ramfs有點類似,先建立一個目錄,用於掛載tmpfs
[root@docker ~]# mkdir /tmpfs_test
使用mount命令掛載到tmpfs_test目錄中,並檢查掛載情況
[root@docker ~]# mount -t tmpfs -o size=1G tmpfs /tmpfs_test && mount |grep tmpfs_test tmpfs on /tmpfs_test type tmpfs (rw,relatime,size=1048576k)
現在我們使用dd來測試一下速度,並檢查下size 限制空間的效果
[root@docker ~]# dd if=/dev/zero of=/tmpfs_test/testtmpfs.file bs=1M count=1100 dd: error writing ‘/tmpfs_test/testtmpfs.file’: No space left on device 1025+0 records in 1024+0 records out 1073741824 bytes (1.1 GB) copied, 0.497443 s, 2.2 GB/s
從上面的提示可以看出,空間已經不夠,現在看下實際存入的檔案大小
[root@docker ~]# ls -l --block-size=K /tmpfs_test/testtmpfs.file -rw-r--r-- 1 root root 1048576K Jun 2 12:16 /tmpfs_test/testtmpfs.file
從ls的輸出可以看到,實際存入的檔案大小,剛好是size限制的大小。很明顯,size起到了避免系統RAM/SWAP記憶體被tmpfs 全部填滿的情況。也體現了tmpfs 比ramfs的優勢所在。所以推薦使用tmpfs。
下面是之前tmpfs介紹中所說的tmpfs在/proc/meminfo 以及shared 顯示。
[root@docker ~]# free -m && echo '-------------------------/proc/meminfo' && cat /proc/meminfo |grep Shmem total used free shared buff/cache available Mem: 1839 268 174 1024 1397 393 Swap: 0 0 0 -------------------------/proc/meminfo Shmem: 1048964 kB
五、常見記憶體不足或記憶體溢位導致的故障分析
1.一次記憶體異常導致應用被kill的案例
某台應用無法提供服務,主機sshd無法存取,通訊異常。使用vnc連線到本地終端後,發現終端介面上報以下錯誤紀錄檔,也無法進行操作:
INFO: task sh:12628 blocked for more than 120 seconds.Not tainted 2.6.32-431.el6.x86 #1 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
上述錯誤,只是警告提示,跟系統核心引數vm.dirty_ratio有關係,後面會專門的介紹。 由於該主機無法響應任何操作,系統也登陸不進去,只有斷電重新啟動了(這裡也可看出系統紀錄檔收集到某個中心節點的好處Y(^_^)Y)。重新啟動後觀察系統messages紀錄檔,下面是紀錄檔的一部分,這裡有完整的紀錄檔,有興趣的可以下載看下:
May 19 00:31:07 robot-web kernel: VFS: file-max limit 65535 reached May 19 00:31:30 robot-web kernel: VFS: file-max limit 65535 reached May 19 00:32:24 robot-web kernel: sh invoked oom-killer: gfp_mask=0x84d0, order=0, oom_adj=0, oom_score_adj=0 May 19 00:32:24 robot-web kernel: sh cpuset=/ mems_allowed=0 May 19 00:32:24 robot-web kernel: Pid: 20387, comm: sh Not tainted 2.6.32-431.el6.x86_64 #1 May 19 00:32:24 robot-web kernel: Call Trace: May 19 00:32:24 robot-web kernel: [<ffffffff810d05b1>] ? cpuset_print_task_mems_allowed+0x91/0xb0 May 19 00:32:24 robot-web kernel: [<ffffffff81122960>] ? dump_header+0x90/0x1b0 May 19 00:32:24 robot-web kernel: [<ffffffff8122798c>] ? security_real_capable_noaudit+0x3c/0x70 May 19 00:32:24 robot-web kernel: [<ffffffff81122de2>] ? oom_kill_process+0x82/0x2a0 May 19 00:32:24 robot-web kernel: [<ffffffff81122d21>] ? select_bad_process+0xe1/0x120 May 19 00:32:24 robot-web kernel: [<ffffffff81123220>] ? out_of_memory+0x220/0x3c0 May 19 00:32:24 robot-web kernel: [<ffffffff8112fb3c>] ? __alloc_pages_nodemask+0x8ac/0x8d0 May 19 00:32:24 robot-web kernel: [<ffffffff81167a9a>] ? alloc_pages_current+0xaa/0x110 May 19 00:32:24 robot-web kernel: [<ffffffff8104ee9b>] ? pte_alloc_one+0x1b/0x50 May 19 00:32:24 robot-web kernel: [<ffffffff81146412>] ? __pte_alloc+0x32/0x160 May 19 00:32:24 robot-web kernel: [<ffffffff8114b220>] ? handle_mm_fault+0x1c0/0x300 May 19 00:32:24 robot-web kernel: [<ffffffff8104a8d8>] ? __do_page_fault+0x138/0x480 May 19 00:32:24 robot-web kernel: [<ffffffff8152d45e>] ? do_page_fault+0x3e/0xa0 May 19 00:32:24 robot-web kernel: [<ffffffff8152a815>] ? page_fault+0x25/0x30 May 19 00:32:24 robot-web kernel: [<ffffffff8152d45e>] ? do_page_fault+0x3e/0xa0 May 19 00:32:24 robot-web kernel: [<ffffffff8152a815>] ? page_fault+0x25/0x30 May 19 00:32:24 robot-web kernel: Mem-Info: May 19 00:32:24 robot-web kernel: Node 0 DMA per-cpu: May 19 00:32:24 robot-web kernel: CPU 0: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: CPU 1: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: CPU 2: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: CPU 3: hi: 0, btch: 1 usd: 0 May 19 00:32:24 robot-web kernel: Node 0 DMA32 per-cpu: May 19 00:32:24 robot-web kernel: CPU 0: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 1: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 2: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 3: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: Node 0 Normal per-cpu: May 19 00:32:24 robot-web kernel: CPU 0: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 1: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 2: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: CPU 3: hi: 186, btch: 31 usd: 0 May 19 00:32:24 robot-web kernel: active_anon:1459499 inactive_anon:284686 isolated_anon:0 May 19 00:32:24 robot-web kernel: active_file:54 inactive_file:45 isolated_file:0 May 19 00:32:24 robot-web kernel: unevictable:0 dirty:0 writeback:0 unstable:0 May 19 00:32:24 robot-web kernel: free:26212 slab_reclaimable:6599 slab_unreclaimable:53001 May 19 00:32:24 robot-web kernel: mapped:697 shmem:793 pagetables:131666 bounce:0 May 19 00:32:24 robot-web kernel: Node 0 DMA free:15728kB min:124kB low:152kB high:184kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15340kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes May 19 00:32:24 robot-web kernel: lowmem_reserve[]: 0 3000 8050 8050 May 19 00:32:24 robot-web kernel: Node 0 DMA32 free:45816kB min:25140kB low:31424kB high:37708kB active_anon:1983180kB inactive_anon:496216kB active_file:28kB inactive_file:72kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3072092kB mlocked:0kB dirty:0kB writeback:0kB mapped:2000kB shmem:1912kB slab_reclaimable:3200kB slab_unreclaimable:82768kB kernel_stack:10296kB pagetables:147684kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:1 all_unreclaimable? no May 19 00:32:24 robot-web kernel: lowmem_reserve[]: 0 0 5050 5050 May 19 00:32:24 robot-web kernel: Node 0 Normal free:43304kB min:42316kB low:52892kB high:63472kB active_anon:3854816kB inactive_anon:642528kB active_file:188kB inactive_file:108kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:5171200kB mlocked:0kB dirty:0kB writeback:0kB mapped:788kB shmem:1260kB slab_reclaimable:23196kB slab_unreclaimable:129236kB kernel_stack:26800kB pagetables:378980kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:59 all_unreclaimable? no May 19 00:32:24 robot-web kernel: lowmem_reserve[]: 0 0 0 0 May 19 00:32:24 robot-web kernel: Node 0 DMA: 2*4kB 1*8kB 2*16kB 2*32kB 2*64kB 1*128kB 0*256kB 0*512kB 1*1024kB 1*2048kB 3*4096kB = 15728kB May 19 00:32:24 robot-web kernel: Node 0 DMA32: 340*4kB 76*8kB 461*16kB 264*32kB 132*64kB 62*128kB 12*256kB 5*512kB 0*1024kB 1*2048kB 1*4096kB = 45952kB May 19 00:32:24 robot-web kernel: Node 0 Normal: 9334*4kB 326*8kB 2*16kB 8*32kB 4*64kB 2*128kB 2*256kB 0*512kB 0*1024kB 1*2048kB 0*4096kB = 43304kB May 19 00:32:24 robot-web kernel: 30346 total pagecache pages May 19 00:32:24 robot-web kernel: 29453 pages in swap cache May 19 00:32:24 robot-web kernel: Swap cache stats: add 691531, delete 662078, find 1720814/1738009 May 19 00:32:24 robot-web kernel: Free swap = 0kB May 19 00:32:24 robot-web kernel: Total swap = 2064376kB May 19 00:32:24 robot-web kernel: 0 8384 26517 56 1 0 0 sh May 19 00:32:24 robot-web kernel: [ 8385] 0 8385 64694 2309 2 0 0 php May 19 00:32:24 robot-web kernel: [ 8386] 0 8386 26517 56 2 0 0 sh May 19 00:32:24 robot-web kernel: [ 8387] 0 8387 26517 57 0 0 0 sh May 19 00:32:24 robot-web kernel: [ 8388] 0 8388 26517 55 1 0 0 sh May 19 00:32:24 robot-web kernel: [ 8402] 0 8402 26517 56 0 0 0 sh May 19 00:32:24 robot-web kernel: [ 8887] 93 8887 23967 272 1 0 0 sendmail May 19 00:32:24 robot-web kernel: [15917] 0 15917 64760 2347 3 0 0 php May 19 00:32:24 robot-web kernel: [15921] 0 15921 64760 2351 3 0 0 php May 19 00:32:24 robot-web kernel: [15923] 0 15923 64760 2349 2 0 0 php May 19 00:32:24 robot-web kernel: [15925] 0 15925 64696 2343 3 0 0 php May 19 00:32:24 robot-web kernel: [15950] 0 15950 64760 2346 3 0 0 php
1 May 19 00:31:30 robot-web kernel: VFS: file-max limit 65535 reached 2 ... 3 4 May 19 00:32:24 robot-web kernel: Free swap = 0kB 5 May 19 00:32:24 robot-web kernel: Total swap = 2064376kB 6 ... 7 8 May 19 00:32:24 robot-web kernel: [20477] 0 20477 26518 55 3 0 0 sh 9 May 19 00:32:24 robot-web kernel: Out of memory: Kill process 1572 (mysqld) score 3 or sacrifice child 10 May 19 00:32:24 robot-web kernel: Killed process 1572, UID 500, (mysqld) total-vm:452564kB, anon-rss:5400kB, file-rss:40kB 11 May 19 00:32:24 robot-web kernel: sh invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
重新啟動系統恢復正常後,根據以上出現的問題,對系統進行了調優工作。主要包括以下幾個部分:
- 按照提示修改 /proc/sys/kernel/hung_task_timeout_secs 值為 0
臨時: echo 0 > /proc/sys/kernel/hung_task_timeout_secs 或 sysctl -w hung_task_timeout_secs=0 永久 echo “kernel.hung_task_timeout_secs = 0” >>/etc/sysctl.conf sysctl -p
增加系統實體記憶體到16G,並修改使用者open files限制數為1048576 計算是每4M記憶體開啟256個檔案數,即:(16G*1024)M/4M *256。
臨時: ulimit -n 1048576 或 echo "ulimit -n 1048576" >> /etc/profile 永久:編寫/etc/security/limits.conf,根據提示在末行新增
- 增加file-max值為1048576
臨時: echo 1048576 > /proc/sys/fs/file-max 或 sysctl -w fs.file-max=1048576 永久 echo “fs.file-max=1048576” >> /etc/sysctl.conf sysctl -p
- 優化修改系統對臟資料的重新整理策略
臨時: sysctl -w vm.dirty_background_ratio=5 sysctl -w vm.dirty_ratio=10 永久: echo "vm.dirty_background_ratio=5" >> /etc/sysctl.conf echo "vm.dirty_ratio=10" >> /etc/sysctl.conf
sysctl -p - 優化crontab裡的任務計劃,檢查,確保執行後釋放
- 由於該系統是虛擬機器,關閉swap分割區。(虛擬機器裡使用磁碟做swap分割區,IO效能會更低)
做了以上修改優化後,系統到目前為止,沒有出現過異常。
2.對以上引數修改進行分析
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message
先說下這個吧。關於核心為什麼提示我們要“修改這個時間為0,來禁用這條訊息”的提示。先看下hung_task_timeout_secs的介紹,參考核心文件:
hung_task_timeout_secs: Check interval. When a task in D state did not get scheduled for more than this value report a warning. This file shows up if CONFIG_DETECT_HUNG_TASK is enabled. 0: means infinite timeout - no checking done. Possible values to set are in range {0..LONG_MAX/HZ}.
核心定時檢測系統中處於D狀態的進程,如果其處於D狀態的時間超過了指定時間(預設120s,可以設定),則列印相關堆疊資訊,也可以通過proc引數設定使其直接panic。
預設情況下,Linux使用高達40%的可用記憶體將進行檔案系統快取。達到此標記後,檔案系統將所有未完成的資料重新整理到磁碟,導致所有的IO進行同步。要將此資料重新整理到磁碟,預設情況下有120秒的時間限制。在這種情況下,IO子系統速度不夠快,可以有120秒的時間重新整理資料。由於IO子系統響應緩慢,並且使用者進程又提出了更多的請求,系統記憶體將被填滿,從而導致上述截圖中的錯誤提示。
將其值修改為 0,意味著表示可以無限超時--不檢查完成情況。但此並不能真正的解決問題根源。
與hung_task其相關的幾個引數
這裡只說下其中兩個相關的引數:vm.dirty_ratio 、vm.dirty_background_ratio,以下內容出自Linux核心文件介紹:
dirty_background_ratio Contains, as a percentage of total available memory that contains free pages and reclaimable pages, the number of pages at which the background kernel flusher threads will start writing out dirty data. The total available memory is not equal to total system memory. ============================================================== dirty_ratio Contains, as a percentage of total available memory that contains free pages and reclaimable pages, the number of pages at which a process which is generating disk writes will itself start writing out dirty data. The total available memory is not equal to total system memory.
dirty_background_ratio:是系統總記憶體的占用百分比,其中包括空閒頁面和可回收頁面。後台核心重新整理執行緒的頁面開始寫入臟資料。即dirty data如果達到了dirty_background_ratio,則核心將在後台執行回寫磁碟,但是應用程式仍然可以在不阻塞的情況下寫入頁面快取。
dirty_ratio:包含可用頁面和可回收頁面的佔 總可用記憶體的百分比,產生磁碟寫入的進程將自動開始寫入臟資料。這時應用程式將阻塞並將髒頁面寫入磁碟。直到系統內的dirty page低於該值。
即先達到dirty_background_ratio,這是程式不會阻塞,等到達dirty_ratio時,程式將阻塞請求,直到將資料寫入磁碟中。這些引數的值取決於系統的執行的什麼程式,如果執行大型資料庫,建議將這些值保持小數值 background_ratio < dirty_ratio,以避免I/O瓶頸以及增加系統負載。這也是作為系統VM優化的一個點。
說下file-max
sysctl -w fs.file-max=1048576
file-max中的值表示Linux核心將要分配的檔案控制代碼的最大數量。 每當應用程式請求檔案控制代碼時,核心會動態分配檔案控制代碼,但核心在應用程式關閉時並不會釋放銷毀這些檔案控制代碼。核心會迴圈使用這些檔案控制代碼。也意味著隨著時間的推移,分配的檔案控制代碼的總數將增加,即使當前使用的檔案控制代碼的數量可能較低。所以當您收到大量關於執行檔案控制代碼的錯誤訊息時,可能需要增加file-max值的大小。
3.什麼是oom-killer ?
介紹
OOM(Out Of Memory) Management:它有一個簡單的任務->檢查系統是否有足夠的可用記憶體來滿足應用程式,驗證系統是否真的是記憶體不足,如果是這樣,請‘選擇’一個進程來殺死它。
相關文章