Hadoop集群服務器升級為rhel6內核后,System Cpu占用非常高,有任務運行的時候經常到50%以上。對其中一臺機器一天的運行狀態采樣的數據: idle: 76%?? sys:14%? user: 9% 從采樣數據中,可以發現System Cpu比User Cpu還要高,這在Hadoop集群環境中很不尋常。
Hadoop集群服務器升級為rhel6內核后,System Cpu占用非常高,有任務運行的時候經常到50%以上。對其中一臺機器一天的運行狀態采樣的數據:
idle: 76%?? sys:14%? user: 9%
從采樣數據中,可以發現System Cpu比User Cpu還要高,這在Hadoop集群環境中很不尋常。
先簡單地用strace看了一下占用cpu高的java程序經常去調哪些系統調用,發現sched_yield調用頻率非常之高,莫非是鎖的問題?分析了下內核中的文檔和代碼,發現CFS調度下sched_yield的行為與以前的O(1)算法略有出入——CFS下sched_yield返回非常快,對于一些借助sched_yield實現鎖的應用來說,開銷會很大。內核提供了一個proc參數sched_compat_yield,設置該參數為1,就可以解決這個問題。于是設置了該參數,仍然沒有效果,分析代碼后,竟然發現sched_compat_yield在rhel6內核中并沒有實現,只是留下了一個接口兼容而已。于是乎將upstream中的相關部分的代碼port到rhel6的內核中,sched_compact_yield終于能干活了,但出乎意料的是,系統態cpu仍然非常高。
沒辦法了,上個大招:oprofile,結果如下:
samples???????? %???????? ?symbol name
2822865? ?71.2192?? ?compact_zone
160729??? ?4.0551?????? clear_page_c
156913?? ?? 3.9588???? ?compaction_alloc
47691?????? ?1.2032????? ?copy_user_generic_string
一看到結果,一頭霧水。compact_zone為何物?為何cpu占用如此之高?不懂了就看代碼。
__alloc_pages_slowpath
__alloc_pages_direct_compact
try_to_compact_pages
compact_zone_order
compact_order
有點頭緒了,內核要分配一塊高階物理內存,buddy system中又沒有滿足條件的,似乎內核要在compact_zone中做些什么事,來滿足對高階物理內存的分配。
下一步,快速驗證下是不是compact_zone的問題,修改config文件,去掉CONFIG_COMPACTION,重新編譯,換內核,竟然真的OK了 。 那基本斷定是compact_zone的問題了,后面就得分析下代碼,研究下其中的原理了。
經過幾天的艱苦奮戰,終于把compaction的基本原理搞明白了。
linux物理內存的管理采用的是經典的伙伴系統,當然也就存在伙伴系統的問題——內存碎片。當然,此處的內存碎片問題并不算大,因為伙伴系統是以頁為單位為管理內存的,碎片也是以“頁”為單位,4k的物理內存還算不上是“碎片”。對于用戶態的程序,幾乎不需要超過4k的連續空間。但是對內核來說,碎片永遠都不是好東西。某些硬件相關的操作會需要連續的物理內存,如果無法滿足,內核就只能panic。
另外,引入compaction的另一個重要因素就是使用THP(Transparent hugepages)。4k的頁面大小已經出現了很多年了,就像文件系統上1k-4k的block_size一樣,都是適應二十年前硬件的容量與速度而出現的,對于現在的硬件來說它們都顯得太小了。使用更大的物理頁,可以帶來兩個好處:TLB緩存命中率的提高和page_fault的次數降低。compaction正是為了支持THP而出現的。
在以前版本的內核中,要獲得連續的物理內存只有一個辦法:釋放掉一部分內存,一般是釋放page cache、臟頁,或者進行頁面swap。
而compaction提出了另外一個思路:重新組織內存。為此,提出了“可移動”頁面的概念。在內核中的物理內存,有一部分是“可移動”的,內核使用的反碎片技術的基本原理,就是根據頁的“可移動性”將頁面分組。
那哪些頁面是可以移動的呢? 非空閑的物理內存,當然要么是用戶態進程在用,要么內核本身在用。對于前者,進程在訪問物理內存的時候,實際上要通過頁表的映射來訪問。頁表是一個可以做文章的地方:如果把一個頁移動到另一個地方,如果可以同時修改頁表,那么對應用程序就不會有影響。而對于內核訪問物理內存時,是通過簡單的常量偏移來做的。因此內核使用的物理頁面無法移動。
定義了“可移動”的頁面,具體到某一個頁面,內核怎樣知道它是否是可移動的?分配內存的函數,kmalloc,alloc_pages等在任何地方都可能被調用。內核又是怎樣知道在這些地方分配的頁面屬于哪種類型呢?看這幾個函數的原型
void *kmalloc(size_t size, gfp_t flags)
struct page * alloc_pages(gfp_t gfp_mask, unsigned int order)
內核自然不知道kmalloc分配的內存是作什么用途的,但是kernel 開發者知道,一個頁面是否可移動,自然也是開發者們告訴內核的。gft_t中有個標志位:GFP_MOVABLE,開發者需要根據相應的內存是否要移動來設置該位。
了解了如何識別“可移動”頁面,下面看看頁面移動的流程:
1.???????? 鎖定頁,以避免在移動頁的過程中有進程修改頁面。頁面記為oldpage
2.???????? 確保“writeback”已經完成
3.???????? 刪除當前頁面的全部映射,并將指向該頁的頁表項標記MIGRATION
4.???????? 查找新頁,記為newpage
5.???????? 獲取radix tree的鎖,以阻塞所有試圖通過radix tree來訪問頁面的進程。將radix tree中oldpage的指針指向newpage。釋放radix tree的鎖。
6.???????? 舊頁的內容被拷到新頁面中,設置新頁面的各項標志
7.???????? 將所有頁表項指向新頁面
了解了compaction的目標和原理,那么該怎樣查看系統中當前的碎片情況呢?/proc/pagetypeinfo文件提供了“可移動”和“不可移動”頁面的分布數據, 一方面方便開發者調試,另一方面可以讓系統管理員了解當前的系統運行狀態。
Compaction在hadoop上所帶來的性能問題,目前還不知道是在這種特定場景下才出現還是compaction本身就影響了性能。不過現在看來,在其它機器上還沒有發現這種情況。
Compaction的目的是減少內存碎片,主要和THP搭配使用,適合需要大量連續內存的應用,比如KVM,能提升TLB效率和減少page fault次數,從而提高應用程序的執行效率。因此,去掉Compaction的支持,會對此類應用的性能所有影響。
參考:http://lwn.net/Articles/359158/你也許會喜歡:
原文地址:hadoop集群System Cpu消耗過高問題分析 by 雜貨店店長, 感謝原作者分享。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com