Linux環境下Java應用效能分析定位-CPU使用篇

來源:互聯網
上載者:User

標籤:jprofiler   host   並發編程   資料交換   quota   stack   總計   owa   膝上型電腦   

1     CPU熱點分析定位背景

CPU資源還是很昂貴的,為了深刻感受到這種昂貴,間當前CPU的資源售價:

 

所以對於程式猿們來說,需要讓程式合理高效的使用CPU資源。利用有限的CPU資源來解決完成我們面對的實際問題,這就是為什麼我們要儘可能最佳化程式。

不篇從微觀層面展開介紹說明,不做宏觀層面的介紹(譬如資料中心級容量監控,管理調度(OpenStack,Kubernates等)以及遷移(手動,自動,冷遷,熱遷))。

本篇將以反向推算式方法組織目錄結構。出現了問題怎麼辦,以及為什麼要這樣做,以及後續儘可能如何預防。

 

 

  • CPU熱點佔用分析定位
  • 什麼是CPU
  • Linux核心的進程調度
  • 反映CPU佔用的相關效能指標
  • JVM的線程與Linux進程對應關係
  • Java並發編程
2     CPU熱點佔用分析定位

 

當然也可以藉助各種神器輔助定位,譬如JProfiler 等。

3     什麼是CPU

CPU:解釋電腦指令以及處理電腦軟體中的資料。

電腦的效能在很大程度上由CPU的效能決定,而CPU的效能主要體現在其運行程式的速度上。影響運行速度的效能指標包括CPU的工作頻率、Cache容量、指令系統和邏輯結構等參數

主頻:主頻也叫時鐘頻率,單位是兆赫(MHz)或千兆赫(GHz),用來表示CPU的運算、處理資料的速度。通常,主頻越高,CPU處理資料的速度就越快。

CPU的主頻=外頻×倍頻係數。主頻和實際的運算速度存在一定的關係,但並不是一個簡單的線性關係。 所以,CPU的主頻與CPU實際的運算能力是沒有直接關係的,主頻表示在CPU內數字脈衝訊號震蕩的速度。CPU的運算速度還要看CPU的流水線、匯流排等各方面的效能指標。

外頻:外頻是CPU的基準頻率,單位是MHz。CPU的外頻決定著整塊主板的運行速度。通俗地說,在台式機中,所說的超頻,都是超CPU的外頻(當然一般情況下,CPU的倍頻都是被鎖住的)相信這點是很好理解的。但對於伺服器CPU來講,超頻是絕對不允許的。前面說到CPU決定著主板的運行速度,兩者是同步啟動並執行,如果把伺服器CPU超頻了,改變了外頻,會產生非同步運行,(台式機很多主板都支援非同步運行)這樣會造成整個伺服器系統的不穩定。

匯流排頻率:前端匯流排(FSB)是將CPU串連到北橋晶片的匯流排。前端匯流排(FSB)頻率(即匯流排頻率)是直接影響CPU與記憶體直接資料交換速度。有一條公式可以計算,即資料頻寬=(匯流排頻率×資料位元寬)/8,資料轉送最大頻寬取決於所有同時傳輸的資料的寬度和傳輸頻率

外頻與前端匯流排(FSB)頻率的區別:前端匯流排的速度指的是資料轉送的速度,外頻是CPU與主板之間同步啟動並執行速度。也就是說,100MHz外頻特指數字脈衝訊號在每秒鐘震蕩一億次;而100MHz前端匯流排指的是每秒鐘CPU可接受的資料轉送量是100MHz×64bit÷8bit/Byte=800MB/s。

緩衝大小也是CPU的重要指標之一,而且緩衝的結構和大小對CPU速度的影響非常大,CPU內緩衝的運行頻率極高,一般是和處理器同頻運作,工作效率遠遠大於系統記憶體和硬碟。實際工作時,CPU往往需要重複讀取同樣的資料區塊,而緩衝容量的增大,可以大幅度提升CPU內部讀取資料的命中率,而不用再到記憶體或者硬碟上尋找,以此提高系統效能。但是由於CPU晶片面積和成本的因素來考慮,緩衝都很小。

L1 Cache(一級緩衝)是CPU第一層快取,分為資料緩衝和指令緩衝。內建的L1快取的容量和結構對CPU的效能影響較大,不過高速緩衝儲存空間均由靜態RAM組成,結構較複雜,在CPU管芯面積不能太大的情況下,L1級快取的容量不可能做得太大。一般伺服器CPU的L1緩衝的容量通常在32-256KB。

L2 Cache(二級緩衝)是CPU的第二層快取,分內部和外部兩種晶片。內部的晶片二級緩衝運行速度與主頻相同,而外部的二級緩衝則只有主頻的一半。L2快取容量也會影響CPU的效能,原則是越大越好,以前家庭用CPU容量最大的是512KB,膝上型電腦中也可以達到2M,而伺服器和工作站上用CPU的

L2快取更高,可以達到8M以上。

L3 Cache(三級緩衝),分為兩種,早期的是外置,記憶體延遲,同時提升大資料量計算時處理器的效能。降低記憶體延遲和提升大資料量計算能力對遊戲都很有協助。而在伺服器領域增加L3緩衝在效能方面仍然有顯著的提升。比方具有較大L3緩衝的配置利用實體記憶體會更有效,故它比較慢的磁碟I/O子系統可以處理更多的資料請求。具有較大L3緩衝的處理器提供更有效檔案系統快取行為及較短訊息和處理器隊列長度

 

我們常說的核心數,個數等之間什麼關係呢?

術語

概述

查看指令

CPU個數

(socket )

就是實實在在插在主機上看得見摸得著那塊CPU硬體

cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

CPU核心數

(core )

一塊物理CPU上能處理資料的晶片集數量。也就是說一個物理CPU上可能會有多個核心,日常中說的雙核,四核就是指的CPU核心

cat /proc/cpuinfo| grep "cpu cores"| uniq

超執行緒

(thread)

一個CPU核就是一個物理線程,由英特爾開發超執行緒技術可以把一個物理線程類比出兩個線程來使用,使得單個核心用起來像兩個核一樣,以充分發揮CPU的效能

 

邏輯CPU

可簡單理解為一個處理單元,通常來說,總的邏輯CPU數對應總的CPU核心數,但藉助超執行緒技術,一個核用起來像兩個核,這時邏輯CPU數就是核心數的兩倍了

cat /proc/cpuinfo| grep "processor"| wc -l

vCPU

對於host來說,kvm虛擬機器是一個進程,虛擬機器的vcpu都是這個進程衍生出來的線程

不同的vcpu只是不同的線程,而不同的線程是跑在不同的cpu上的

 KVM 中,可以指定 socket,core 和 thread 的數目,比如 設定 “-smp 5,sockets=5,cores=1,threads=1”,則 vCPU 的數目為 5*1*1 = 5。客戶機看到的是基於 KVM vCPU 的 CPU 核,而 vCPU 作為 QEMU 線程被 Linux 作為普通的線程/輕量級進程調度到物理的 CPU 核上。

使用者希望把虛擬機器的VCPU綁定在特定物理CPU上,VCPU只在綁定的物理CPU上調度,達到隔離VCPU並提升虛擬機器效能的目的。如果沒有作VCPU綁定,則虛擬機器的VCPU可以在所有物理CPU上調度(libvirt中cputune提供了精細的vcpu綁定設定,可以具體到每個vcpu設定。而且提供vcpu能力的標準化,如quota,period,shares,可以用於實現cpu的Qos)

宿主機上ps 指令可查看是否KVM虛擬機器對應宿主的一個進程,而不同vCPU實際是此進程衍生的不同的線程

 

虛擬化情境下vCPU的親和性:

 

實踐:

1:Linux中CPU的主頻,匯流排頻率,外頻,Cache容量 如何查看

2:Linux中CPU個數,核心數,是否開啟了超執行緒,超執行緒個數如何查看?

3:KVM虛擬化下如何設定vCPU親和性?

4:Docker容器化中如何設定CPU親和性?

4     反映CPU佔用的相關效能指標

Linux CPU 佔用率計算,都是根據/proc/stat 檔案內容計算而來,在Linux/Unix 下,CPU 利用率分為使用者態、系統態和空閑態,  分別表示CPU 處於使用者態執行的時間,系統核心執行的時間,和空閑系統進程執行的時間。

 

原始指標

描述

備忘

使用者時間(User time)

表示CPU 執行使用者進程的時間,包括nices時間。通常期望使用者空間CPU 越高越好。

 

系統時間(System time)

表示CPU 在核心已耗用時間,包括IRQ 和softirq 時間。系統CPU 佔用率高,表明系統某部分存在瓶頸。通常值越低越好。

 

等待時間(Waiting time)

CPI 在等待I/O 操作完成所花費的時間。系統部應該花費大量時間來等待I/O 操作,否則就說明I/O 存在瓶頸。

幹嘛的

空閑時間(Idle time)

系統處於空閑期,等待進程運行

幹嘛的

Nice時間(Nice time)

系統調整進程優先順序所花費的時間。

幹嘛的

硬中斷處理時間(Hard Irq time)

系統處理硬中斷所花費的時間。

這個指標幹嘛的

非強制中斷處理時間(SoftIrq time)

系統處理非強制中斷中斷所花費的時間

這個指標幹嘛的

 

上述為Linux中CPU相關的原子指標,實際我們所說的佔用率等都是統計指標,統計指標的解釋和計算如下:

統計指標

概述

計算公式

CPU時間

核心中的時間HZ是系統時鐘在一秒內固定發出時鐘中斷的次數。HZ在編譯核心前是可以進行配置的,因此通過下述命令就可以查看當前系統的時鐘中斷頻率:cat /boot/config-`uname -r` | grep CONFIG_HZ。tick為系統時鐘每“滴答“一次的時間,其值為(1/HZ)秒。也就是連續兩次時鐘中斷之間的時間間隔。jiffies用來計算自系統啟動以來tick的次數,也就是說系統時鐘每產生一次時鐘中斷,該變數的值就增加一次

user+system+nice+idle+iowait+irq+softirq+Stl

使用者態CPU佔用率

使用者使用CPU的進程包括:cpu運行常規使用者進程,cpu運行niced process,cpu運行即時進程。一個Linux進程可以在使用者方式下執行,也可以在系統(核心)方式下執行,當一個進程在核心代碼中運行時,我們稱其處於核心態;當一個進程正在執行使用者自己的代碼時,我們稱其處於使用者態,在使用者方式下執行時,進程在它自己的應用應用代碼中執行,不需要核心資源來進行計算、管理記憶體或設定變數

(User time + Nice time)/CPU時間*100%

核心態CPU佔用率

顯示了系統方式下所花費cpu時間的百分比,包括核心進程(kprocs)和其他需要訪問核心資源的進         程所消耗的cpu資源,系統使用cpu的進程包括:用於系統調用,用於I/O管理(中斷和驅動),用於記憶體管理(paging and swapping),用於進程管理(context switch and        process start),如果一個進程需要核心資源,它必須執行一個系統調用,並由此切換到系統方式從而使該資源可用

(System time + Hard Irq time +SoftIRQ time)/CPU時間*100%

空閑率

如果沒有線程可以執行(運行隊列為空白),系統指派一個叫做wait的線程,可稱為idle kproc。如果ps報告顯示這個線程的總計時間較高,這表明存在時間段,其中沒有其它線程準備在cpu上運行或等待執行。系統因此大部分時間空閑或等待新任務

(Idle time)/CPU 時間*100%

 

上述涉及的幾個術語:使用者態,核心態,中斷。這就涉及了Linux核心的一些知識,主要是進程調度相關。

實踐:

  1. 1.      Linux中查看CPU使用的原始指標
  2. 2.      Linux中查看CPU使用的統計指標
5     Linux核心的進程調度

由前面介紹可知:CPU是完成具體計算的,但是CPU是硬體,對於上層應用程式來說不直接與CPU互動,而是通過作業系統來完成的,也就是應用程式實際通過與作業系統指令互動,有作業系統內部通過裝置驅動與CPU互動完成相關計算任務的。

對於Linux,內部可分三層:硬體-核心-使用者空間

 

  1. 使用者模式+核心模式

一般說來,一個進程在CPU上運行可以有兩種運行模式,既可在使用者模式下運行,又可在核心模式下運行(即進程分別工作在使用者態和核心態,在核心態工作仍舊是這個進程,除非進行了進程的切換)。Linux整個核心就是由各種中斷和例外處理常式組成的。即,正常情況下處理器在使用者模式執行使用者程式,在中斷或異常情況下處理器切換到特權模式執行核心程式,處理完中斷或異常之後再返回使用者模式繼續執行使用者程式,例如,使用者進程A調用了核心系統調用來擷取當前的時鐘滴答數,在執行使用者進程A中的系統調用指令時會儲存目前使用者進程的IP,CS等當前寄存器狀態,然後再跳轉到核心空間(即核心代碼地區)去執行像應的系統調用函數,擷取當前的時鐘滴答數。執行完後再通過IRET指令返回到進程A中(就是將進入時儲存的資訊再複位到相應的寄存器中),再接著從CS:EIP地址開始執行A進程的指令

  1. Linux調度方式:

Linux核心的調度方式基本上採用“搶佔式優先順序”方式,即當進程在使用者模式下運行時,不管是否自願,在一定條件下(如時間片用完或等待I/O),核心就可以暫時剝奪其運行而調度其它進程進入運行。但是,一旦進程切換到核心模式下運行,就不受以上限制而一直運行下去,直至又回到使用者模式之前才會發生進程調度。Linux系統中的調度策略基本上繼承了Unix的以優先順序為基礎的調度。就是說,核心為系統中每個進程計算出一個優先權,該優先權反映了一個進程獲得CPU使用權的資格,即高優先權的進程優先得到運行。核心從進程就緒隊列中挑選一個優先權最高的進程,為其分配一個CPU時間片,令其投入運行。在運行過程中,當前進程的優先權隨時間遞減,這樣就實現了“負反饋”作用:經過一段時間之後,原來層級較低的進程就相對“提升”了層級,從而有機會得到運行。當所有進程的優先權都變為0時,就重新計算一次所有進程的優先權

  1. Linux調度演算法:

Linux執行進程調度時,首先尋找所有在就緒隊列中的進程,從中選出優先順序最高且在記憶體的一個進程。如果隊列中有即時進程,那麼即時進程將優先運行。如果最需要啟動並執行進程不是當前進程,那麼當前進程就被掛起,並且儲存它的現場所涉及的一切機器狀態,包括程式計數器和CPU寄存器等,然後為選中的進程恢複運行現場

  1. CPU環境切換

在切換時,一個進程儲存在處理器各寄存器中的中間資料叫做進程的上下文,所以進程的切換實質上就是被中止運行進程與待運行進程內容相關的切換。在進程未佔用處理器時,進程 的上下文是儲存在進程的私人堆棧中的。佔用處理器時,是恢複到處理器的寄存器中去,並把待運行進程的斷點送入處理器的程式指標PC,於是待運行進程就開始被處理器運行了,也就是這個進程已經佔有處理器的使用權了。進程的切換可以用中斷技術來實現

由上述可知:CPU的環境切換時影響核心CPU佔用率的關鍵因素。

6     JVM的線程與Linux進程對應關係

上面說的是Linux的進程調度,對於我們第一章節介紹的是分析Java應用的熱點線程,進程和Java線程,這到底怎麼回事兒呢?

Java裡的線程是由JVM來管理的,它如何對應到作業系統的線程是由JVM的實現來確定的。Linux 2.6上的HotSpot使用了NPTL機制,JVM線程跟核心輕量級進程有一一對應的關係線程的調度完全交給了作業系統核心,當然jvm還保留一些策略足以影響到其內部的線程調度,舉個例子,在linux下,只要一個Thread.run就會調用一個fork產生一個線程。

Java線程在Windows及Linux平台上的實現方式,是核心線程的實現方式。這種方式實現的線程,是直接由作業系統核心支援的——由核心完成線程切換,核心通過操縱調度器(Thread Scheduler)實現線程調度,並將線程任務反映到各個處理器上。核心線程是核心的一個分身。程式一般不直接使用該核心線程,而是使用其進階介面,即輕量級進程(LWP),也即線程

 

說明:KLT即核心線程Kernel Thread,是“核心分身”。每一個KLT對應到進程P中的某一個輕量級進程LWP(也即線程),期間要經過使用者態、核心態的切換,並在Thread Scheduler 下反應到處理器CPU上。)

在程式面上使用核心線程,必然在作業系統上多次來回切換使用者態及核心態;另外,因為是一對一的執行緒模式,LWP的支援數是有限的。

各個線程既可以共用進程資源(記憶體位址、檔案I/O等),又可以獨立調度(線程是CPU調度的基本單位)。

從上述可知我們所說的Java的線程實際就是使用者態的輕量級進程,其映射到核心態的線程。(線程是CPU調度的基本單位)

7     Java並發
  • 線程數量

當Java線程數大於cpu線程數,作業系統使用時間片機制,採用線程調度演算法,頻繁的進行線程切換。活躍線程數為 CPU(核)數時最佳。過少的活躍線程導致 CPU 無法被充分利用,過多的活躍線程導致過大的線程環境切換開銷。線程應該是活躍的,處於 IO 的線程,休眠的線程等均不消耗 CPU。

I/O密集型 (IO-bound) 

I/O bound 指的是系統的CPU效能相對硬碟/記憶體的效能要好很多,此時,系統運作,大部分的狀況是 CPU 在等 I/O (硬碟/記憶體) 的讀/寫,此時 CPU Loading 不高。
CPU bound 指的是系統的 硬碟/記憶體 效能 相對 CPU 的效能 要好很多,此時,系統運作,大部分的狀況是 CPU Loading 100%,CPU 要讀/寫 I/O (硬碟/記憶體),I/O在很短的時間就可以完成,而 CPU 還有許多運算要處理,CPU Loading 很高。

我們現在做的開發大部分都是WEB應用,涉及到大量的網路傳輸,不僅如此,與資料庫,與緩衝間的互動也涉及到IO,一旦發生IO,線程就會處於等待狀態,當IO結束,資料準備好後,線程才會繼續執行。因此從這裡可以發現,對於IO密集型的應用,我們可以多設定一些線程池中線程的數量,這樣就能讓在等待IO的這段時間內,線程可以去做其它事,提高並發處理效率。
    那麼這個線程池的資料量是不是可以隨便設定呢?當然不是的,請一定要記得,線程環境切換是有代價的。目前總結了一套公式,對於IO密集型應用:
    線程數 = CPU核心數/(1-阻塞係數)
    這個阻塞係數一般為0.8~0.9之間,也可以取0.8或者0.9。

計算密集型 (CPU-bound) 

在多重程式系統中,大部份時間用來做計算、邏輯判斷等CPU動作的程式稱之CPU bound。

在多核CPU時代,我們要讓每一個CPU核心都參與計算,將CPU的效能充分利用起來,這樣才算是沒有浪費伺服器配置,如果在非常好的伺服器配置上還運行著單線程程式那將是多麼重大的浪費。對於計算密集型的應用,完全是靠CPU的核心數來工作,所以為了讓它的優勢完全發揮出來,避免過多的線程環境切換,比較理想方案是:
    線程數 = CPU核心數+1
    也可以設定成CPU核心數*2,這還是要看JDK的使用版本,以及CPU配置(伺服器的CPU有超執行緒)。對於JDK1.8來說,裡面增加了一個並行計算,計算密集型的較理想線程數 = CPU核心線程數*2

 

在Java中擷取CPU核心數方法:Runtime.getRuntime().availableProcessors()

    • Wait,sleep,notify:阻塞,睡眠,喚醒。
    • Java多線程架構:ExecutorService等。
    • 線程間通訊:訊號量,記憶體隊列等
    • 安全執行緒:各種鎖,各種安全集合等

Linux環境下Java應用效能分析定位-CPU使用篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.