一次外場宕機引發對linux記憶體管理的進一步思考--Linux虛擬地址空間如何分佈
0x01 緣由
外場一次伺服器宕機,一群人baba的上去圍觀,分析問題,大部分是猜測,通過回退版本後只解決了問題表象,內在的真實原因沒確定。伺服器上執行著JAVA程式和C程式,到底是什麼導致這次宕機事故。通過分析日誌發現有類似如下錯誤:
test_mem invoked oom-killer: gfp_mask=0x280da, order=0, oom_adj=0, oom_score_adj=0
Pid: 10021, comm: test_mem Tainted: G --------------- H 2.6.32-431.el6.i686 #1
Call Trace:
[<c04ec6c4>] ? dump_header+0x84/0x190
[<c04eca68>] ? oom_kill_process+0x68/0x280
[<c04ec9a2>] ? oom_badness+0x92/0xf0
[<c04ecfe8>] ? out_of_memory+0xc8/0x1e0
[<c04f773d>] ? __alloc_pages_nodemask+0x7fd/0x810
[<c050df91>] ? handle_pte_fault+0x9d1/0xdd0
[<c0444e82>] ? __wake_up+0x42/0x60
[<c043fb80>] ? kmap_atomic_prot+0x120/0x150
[<c050e4c1>] ? handle_mm_fault+0x131/0x1d0
[<c04398fb>] ? __do_page_fault+0xfb/0x410
[<c0536df1>] ? vfs_write+0x121/0x190
[<c086279a>] ? do_page_fault+0x2a/0x90
[<c0862770>] ? do_page_fault+0x0/0x90
[<c0860247>] ? error_code+0x73/0x78
Mem-Info:
DMA per-cpu:
CPU 0: hi: 0, btch: 1 usd: 0
CPU 1: hi: 0, btch: 1 usd: 0
CPU 2: hi: 0, btch: 1 usd: 0
CPU 3: hi: 0, btch: 1 usd: 0
Normal per-cpu:
CPU 0: hi: 186, btch: 31 usd: 0
CPU 1: hi: 186, btch: 31 usd: 30
CPU 2: hi: 186, btch: 31 usd: 0
CPU 3: hi: 186, btch: 31 usd: 0
HighMem per-cpu:
CPU 0: hi: 186, btch: 31 usd: 0
CPU 1: hi: 186, btch: 31 usd: 0
CPU 2: hi: 186, btch: 31 usd: 0
CPU 3: hi: 186, btch: 31 usd: 0
active_anon:693728 inactive_anon:221684 isolated_anon:64
active_file:26 inactive_file:51 isolated_file:0
unevictable:0 dirty:0 writeback:3072 unstable:0
free:27528 slab_reclaimable:1391 slab_unreclaimable:9790
mapped:131 shmem:872 pagetables:4219 bounce:0
DMA free:7576kB min:64kB low:80kB high:96kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15796kB 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
lowmem_reserve[]: 0 863 3938 3938
Normal free:102148kB min:3724kB low:4652kB high:5584kB active_anon:260712kB inactive_anon:259352kB active_file:156kB inactive_file:88kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:883912kB mlocked:0kB dirty:0kB writeback:4380kB mapped:68kB shmem:0kB slab_reclaimable:5564kB slab_unreclaimable:39160kB kernel_stack:1312kB pagetables:1916kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:32 all_unreclaimable? no
lowmem_reserve[]: 0 0 24605 24605
HighMem free:388kB min:512kB low:3828kB high:7148kB active_anon:2514200kB inactive_anon:627384kB active_file:0kB inactive_file:116kB unevictable:0kB isolated(anon):256kB isolated(file):0kB present:3149484kB mlocked:0kB dirty:0kB writeback:7908kB mapped:456kB shmem:3488kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:14960kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:53 all_unreclaimable? no
lowmem_reserve[]: 0 0 0 0
DMA: 4*4kB 3*8kB 3*16kB 4*32kB 3*64kB 2*128kB 3*256kB 0*512kB 2*1024kB 2*2048kB 0*4096kB = 7576kB
Normal: 623*4kB 395*8kB 236*16kB 129*32kB 89*64kB 54*128kB 33*256kB 18*512kB 15*1024kB 7*2048kB 7*4096kB = 102196kB
HighMem: 23*4kB 14*8kB 11*16kB 2*32kB 0*64kB 2*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 700kB
4464 total pagecache pages
3404 pages in swap cache
Swap cache stats: add 2804401, delete 2800997, find 71974/72729
Free swap = 0kB
Total swap = 4046840kB
1046000 pages RAM
819202 pages HighMem
76971 pages reserved
1403 pages shared
939149 pages non-shared
[ pid ] uid tgid total_vm rss cpu oom_adj oom_score_adj name
[ 485] 0 485 696 2 0 -17 -1000 udevd
[ 1211] 0 1211 3233 21 3 -17 -1000 auditd
[ 1227] 0 1227 9296 19 2 0 0 rsyslogd
[ 1273] 0 1273 3102 22 0 0 0 usbdaemon
[ 1287] 0 1287 2237 13 2 -17 -1000 sshd
[ 1363] 0 1363 3242 12 0 0 0 master
[ 1372] 89 1372 3278 9 2 0 0 qmgr
[ 1373] 0 1373 1501 33 2 0 0 crond
[ 1405] 0 1405 1376 2 0 0 0 su
[ 1413] 0 1413 502 2 0 0 0 mingetty
[ 1415] 0 1415 502 2 3 0 0 mingetty
[ 1417] 0 1417 502 2 0 0 0 mingetty
[ 1419] 0 1419 502 2 1 0 0 mingetty
[ 1421] 0 1421 502 2 3 0 0 mingetty
[ 1423] 0 1423 502 2 1 0 0 mingetty
[ 1430] 0 1430 860 2 0 -17 -1000 udevd
[ 1431] 0 1431 860 2 2 -17 -1000 udevd
[ 1433] 0 1433 2525 1286 2 0 0 startup.sh
[ 1452] 0 1452 2973 33 2 0 0 sshd
[ 1507] 0 1507 1314 2 0 0 0 bash
[ 2305] 0 2305 3073 13 2 0 0 sshd
[ 2309] 0 2309 1314 17 0 0 0 bash
[30012] 0 30012 3307 2 2 0 0 sshd
[30024] 0 30024 2280 2 0 0 0 sftp-server
[30075] 0 30075 2280 2 0 0 0 sftp-server
[30094] 0 30094 2280 2 0 0 0 sftp-server
[ 6973] 0 6973 2973 11 2 0 0 sshd
[ 6985] 0 6985 1314 2 2 0 0 bash
[12591] 0 12591 3065 11 2 0 0 sshd
[12611] 0 12611 1314 2 0 0 0 bash
[19446] 0 19446 3196 41 0 0 0 sshd
[19458] 0 19458 1314 17 0 0 0 bash
[21347] 0 21347 2973 38 2 0 0 sshd
[21351] 0 21351 1314 17 0 0 0 bash
[21483] 0 21483 3008 44 0 0 0 sshd
[21495] 0 21495 1314 17 0 0 0 bash
[21583] 0 21583 3008 41 3 0 0 sshd
[21587] 0 21587 1314 27 2 0 0 bash
[ 5391] 89 5391 3261 18 2 0 0 pickup
[ 8906] 0 8906 642 46 2 0 0 top
[ 9064] 0 9064 675 74 2 0 0 top
[ 9289] 0 9289 2973 40 2 0 0 sshd
[ 9301] 0 9301 1314 17 0 0 0 bash
[10020] 0 10020 785602 2722 3 0 0 test_mem1
[10021] 0 10021 636028 457164 0 0 0 test_mem
[10022] 0 10022 495963 449718 1 0 0 test_mem
[10118] 0 10118 1016 23 1 0 0 sleep
Out of memory: Kill process 10020 (test_mem1) score 365 or sacrifice child
0x02 日誌現象分析
系統觸發了invoked oom-killer機制,下面為相關簡介,但不是導致宕機的原因,只能導致程式退出重啟; oom kiiler會在記憶體緊張的時候,會依次kill記憶體佔用較高的程序,傳送Signal 15(SIGTERM)。並在/var/log/message中進行記錄。裡面會記錄一些如pid,process name,cpu mask,trace等資訊,通過監控可以發現類似問題。0x03 記憶體佈局
x86_32: 《深入理解計算機系統》圖x86_64:
虛擬記憶體的佈局說明,Linux使用虛擬地址空間,大大增加了程序的定址空間,由低地址到高地址分別為:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int global_num = 0;
char global_str_arr [65536] = {'a'};
int main(int argc, char** argv)
{
char* heap_var = NULL;
int local_var = 0;
printf("Address of function main 0x%lx\n", main);
printf("Address of global_num 0x%lx\n", &global_num);
printf("Address of global_str_arr 0x%lx ~ 0x%lx\n", &global_str_arr[0], &global_str_arr[65535]);
printf("Bot of stack is 0x%lx\n", &heap_var);
printf("Top of stack is 0x%lx\n", &local_var);
printf("Top of heap is 0x%lx\n", sbrk(0));
heap_var = malloc(sizeof(char) * 127 * 1024);
printf("Address of heap_var is 0x%lx\n", heap_var);
printf("Top of heap after malloc is 0x%lx\n", sbrk(0));
free(heap_var);
heap_var = NULL;
printf("Top of heap after free is 0x%lx\n", sbrk(0));
return 1;
}
執行結果:gcc -o mem_layout mem_layout.c
[email protected] test]# ./mem_layout
Address of function main 0x8048454
Address of global_num 0x8059928
Address of global_str_arr 0x8049920 ~ 0x805991f
Bot of stack is 0xbfbb8b9c
Top of stack is 0xbfbb8b98
Top of heap is 0x8486000
Address of heap_var is 0x8486008
Top of heap after malloc is 0x84c6000
Top of heap after free is 0x84a7000
可以檢視彙編: objdump -d mem_layout -M intel > mem_layout.asm 找對應的關係。
虛擬地址位數:
x86_32: 32位表示地址,可定址空間為4G;
x86_64:
[[email protected] test]# ./mem_layout
Address of function main 0x400594
Address of global_num 0x610bd0
Address of global_str_arr 0x600bc0 ~ 0x610bbf
Bot of stack is 0x7fff3d81ce38
Top of stack is 0x7fff3d81ce34
Top of heap is 0x1984000
Address of heap_var is 0x1984010
Top of heap after malloc is 0x19c4000
Top of heap after free is 0x19a5000
虛擬地址位數:
x86_64: 48位表示地址,可虛擬空間為128TB;具體系統具體檢視:cat /proc/cpuinfo | grep address
0x04 模擬記憶體分配耗盡場景
模擬目的: 1、觸發oom-killer機制,看是否導致宕機; 2、malloc 記憶體申請和分配機制的原理; 3、多個程式對記憶體資源的搶佔問題; 測試程式碼1:#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLOCK_SIZE 1024*1024
int main(void)
{
char *block = NULL;
int mem_total = 0;
while(1)
{
usleep(200);
block = malloc(BLOCK_SIZE);
if(block == NULL)
{
printf("Malloc Fail\n");
sleep(360);
}
mem_total++;
printf("Mem Total %d Kb\n", mem_total);
//memset(block, 'a', BLOCK_SIZE);
}
return EXIT_SUCCESS;
}
編譯執行:
gcc -o test_mem test_mem.c
./test_mem
執行結果:
Mem Total 3052 Kb
Mem Total 3053 Kb
Mem Total 3054 Kb
Mem Total 3055 Kb
Mem Total 3056 Kb
Malloc Fail
ps -ef | grep test_mem
top -p xxxx
截圖如下:
虛擬地址 3G 實體地址才12M,為什麼? 因為不是 malloc 後就馬上佔用實際記憶體,而是第一次使用時發現虛存對應的物理頁面未分配,產生缺頁中斷,才真正分配物理頁面,同時更新程序頁面的對映關係。這也是 Linux 虛擬記憶體管理的核心概念之一。 測試程式2(將上述註釋去掉):
A.執行上述程式後,使用者態可訪問的記憶體空間已經佔完,結果還是未觸發 oom-killer機制,為什麼?
執行另一個程式處理過程:
./test_mem2
B.top觀察,出現的現象時,test_mem佔用的記憶體在減少,test_mem2記憶體在不斷上升,為什麼?
同時執行兩個程式後,也未觸發 oom-killer,為什麼?
觀察下記憶體情況:
[[email protected] ~]# free -m
total used free shared buffers cached
Mem: 3819 3693 126 0 0 8
-/+ buffers/cache: 3684 135
Swap: 3951 2654 1297
./test_mem3執行後,系統相當卡頓,說明資源不足。此時觸發了oom-killer,殺掉了test_mem;
A問題的解答:當實體記憶體使用完或者達到一定比例之後,我們可以使用swap做臨時的記憶體使用。當實體記憶體和swap都被使用完那麼就會出錯,out of memory。對於使用多大比例記憶體之後開始使用swap,在系統的配置檔案中可以通過調整引數進行修改。cat /proc/sys/vm/swappiness
B問題的解答:當記憶體沒有可用的,就必須要把記憶體中不經常執行的程式給踢出去。但是踢到哪裡去,這時候swap就出現了。swap全稱為swap place,,即交換區,當記憶體不夠的時候,被踢出的程序被暫時儲存到交換區。當需要這條被踢出的程序的時候,就從交換區重新載入到記憶體,否則它不會主動交換到真是記憶體中。
0x05 結論
當某個程序記憶體洩露嚴重時,會觸發oom-killer和系統卡頓。宕機的原因還是不明。後期繼續分析!!相關推薦
一次外場宕機引發對linux記憶體管理的進一步思考--Linux虛擬地址空間如何分佈
0x01 緣由 外場一次伺服器宕機,一群人baba的上去圍觀,分析問題,大部分是猜測,通過回退版本後只解決了問題表象,內在的真實原因沒確定。伺服器上執行著JAVA程式和C程式,到底是什麼導致這次宕機事故。通過分析日誌發現有類似如下錯誤: test_me
MongoDB一次節點宕機引發的思考(原始碼剖析)
目錄 簡介 日誌分析 副本集 如何實現 Failover 心跳的實現 electionTimeout 定時器 業務影響評估 參考連結
由Redis的hGetAll函式所引發的一次服務宕機事件
昨晚通宵生產壓測,終於算是將生產服務宕機的原因定位到了,心累。這篇部落格,算作一個覆盤和記錄吧。。。 先來看看Redis的快取淘汰演算法思維導圖: 說明:當實際佔用的記憶體超過Redis配置的maxmemory時,Redis就會根據使用者選擇淘汰策略清除被選中的key。
Linux虛擬地址空間分佈
在多工作業系統中,每個程序都執行在屬於自己的記憶體沙盤中。這個沙盤就是虛擬地址空間(Virtual Address Space),在32位模式下它是一個4GB的記憶體地址塊。在Linux系統中, 核心程序和使用者程序所佔的虛擬記憶體比例是1:3,而Windo
編譯後的程式是如何在作業系統(linux)中執行的,虛擬地址空間到實際實體記憶體的訪問
Linux中,每個程序通過一個task_struct結構體描述,每個程序地址虛擬空間通過一個mm_struct描述,c語言中每個段空間通過vm_area_struct描述,關係如下, 當執行
一次“淘寶購物”引發出來對產品的思考
b)告訴使用者,哪些關鍵點必須注意,否則會影響安裝質量,有點東西安裝錯了,會導致木板損壞,很難恢復(例如:塑料螺帽安裝到木板的小孔中的時候,不能砸得太狠,必須保證跟木板齊平,突出來會讓木板銜接不密封,太深了會讓螺絲無法卡在旋轉螺帽中) (adsbygoogle = window.a
一次給女朋友轉賬引發我對分散式事務的思考
本文在個人技術部落格不同步釋出,詳情可用力戳 亦可掃描螢幕右側二維碼關注個人公眾號,公眾號內有個人聯絡方式,等你來撩... 前兩天發了工資,第一反應是想著要給遠方的女朋友一點驚喜!於是打開了平安銀行的APP給女朋友轉點錢!填寫上對方招商銀行卡的卡號、開戶名,一鍵轉賬!搞定!在我點選的那瞬間,就收到了
ORACLE sql調優之記錄一次trim函數引發的大表全表掃描
oracle trim 全表掃描 sql 調優 2017年8月14日,一地市oracle相關的調度程序ETL抽取速度奇慢,sql語句每次執行平均時間要9秒左右,如果所示:該調度過程涉及的sql語句如下:select count(*) from (SELECT rtrim(
一次事務配置失敗引發的總結
第一個 過程 service logs 代理 生成 bsp time log 環境 : springboot + mybatis + shiro + mysql 需求: service 層配置事務過程 : 1. springboot 啟動類加上 @Enabl
Nginx+Tomcat做負載均衡時一臺伺服器宕機實現自動切換
思路:有兩種方式。 第一種:設定一臺伺服器為備機,只有當訪問的伺服器異常時才會訪問它; 第二種:設定伺服器轉發請求超時時間。 一、設定備機: 在安裝目錄下(例E:\nginx-1.14.0\conf)開啟nginx.conf修改 upstream netitcast.com {
一次bochs磁碟問題引發的除錯慘案
最近用bochs模擬一個簡單的作業系統,將自己建立的硬碟作為啟動盤,建立硬碟的命令如下: 建立的flat模式的硬碟,命令列已經提示瞭如何在bochs配置檔案中加入該硬碟,自己卻作死寫了下面這句: ata0-master: type=disk, mo
一次mybatis中ognl引發的bug排查
現象 專案組一妹子程式設計師求助,說mybatis有bug,有一個值明明設定的是A.prop1=XXX,但是存到資料庫裡面卻會自動變成A.prop1=true,嘗試了各種調整也找不原因,都快急瘋了!我以前確實沒有研究過mybatis原始碼,本著專(ba)研(me
記一次全站升級https引發的一系列問題
中秋假期,閒來無事。花了一下午折騰了下https,說實話這年頭還有網站不上https顯然是折騰精神不夠啊~ 1、SSL證書評估 看了市面上各種型別的證書,有收費的也有免費的,但是最終還是選擇了騰訊雲提供的TrustAsia一年免費期的證書,沒有次數限制,可以過期後再次申請。最主要的原因還是我懶,哈哈~~
記一次Spring refresh context引發Data source is closed異常的坑
背景:Spring的profile寫在了自定義配置檔案中,需要手動讀取配置檔案,手動啟用profile,關於啟用profile的方法參考Spring啟用profile的幾種方式,我們採用了方案2。程式是首先初始化Spring上下文,建立連線池和事務管理器等等,然後讀取配置檔案,獲
記一次裝mysql服務引發的血案
上午閒玩dos命令,因為dos命令無法啟動mysql服務,於是百度查詢原因,然後從裝了服務。從這裡開始一場沒有硝煙血案就開始了。 從裝mysql服務之後,按原來的方式(原來的使用者名稱密碼)連線資料庫,可是不管怎樣都連線不上 這是什麼原因呢?我想了想,試試不填寫密碼看能不
記一次排查mbstowcs誤用引發的bug
問題程式碼如下: #define MAX_LINE_LEN (10240*2) char tieziLine[MAX_LINE_LEN]; wchar_t oneTieziLine_wchar[MAX_LINE_LEN];
記一次synchronized鎖字串引發的坑兼再談Java字串
問題描述業務有一個需求,我把問題描述一下:通過代理IP訪問國外某網站N,每個IP對應一個固定的網站N的COOKIE,COOKIE有失效時間。併發下,取IP是有一定策略的,取到IP之後拿IP對應的COOK
記一次MongoDB效能問題+Linux記憶體管理學習筆記--實體記憶體分配
最近忙著把一個專案從MySQL遷移到MongoDB,在匯入舊資料的過程中,遇到了些許波折,犯了不少錯誤,但同時也學到了不少知識,遂記錄下來。 公司為這個專案專門配備了幾臺高效能務器,清一色的雙路四核超執行緒CPU,外加32G記憶體,運維人員安裝好MongoDB後,就交我手裡了,我習慣於在使用新伺服器前先看
害你加班的bug就是我寫的,記一次升級Jenkins外掛引發的加班
## 主旨 本文主要記錄了下Jenkins升級外掛過程中出現的場景,一次加班經歷,事發時沒有截圖,有興趣可以看看。 ## 起因 ### 需求 最近有個需求:在Jenkins流水線中完成下載Git上的檔案簡單修改並提交的功能 起初找到了相關的外掛用法,即使用 `SSH Agent Plugin` 來完成這個
一次依賴注入不慎引發的一連串事故
一次依賴注入不慎引發的一連串事故 ## 起因和現象 偶爾會看到線上服務啟動的時候第一波流量進來之後, 遲遲沒有任何的響應,同時服務的監控檢查介面正常, 所以 K8S 叢集認為服務正常,繼續放入流量。 檢視日誌基本如下: ```log [2020-06-05T13:00:30.7080743+00