天天看點

linux性能分析及調優

第一節:cpu 性能瓶頸 

計算機中,cpu是最重要的一個子系統,負責所有計算任務;

基于摩爾定律的發展,cpu是發展最快的一個硬體,是以瓶頸很少出現在cpu上;

我們線上環境的cpu都是多核的,并且基于SMP(symmetric multiprocessing)結構的。

通過觀察線上機器cpu使用率會發現,使用率很低很低,不到5%; 說明我們的資源浪費情況多麼嚴重啊;(但為什麼不能一台機器多部署幾個應用呢,後邊我會解釋); 我們線上的cpu一個核支援超級線程,也就是一個核上可以并行運作幾個線程)

機器CPU使用情況監控:

1、良好狀态名額

                    CPU使用率:User Time <= 70%,System Time <= 35%,User Time + System Time <= 70%。

                   上下文切換:    與CPU使用率相關聯,如果CPU使用率狀态良好,大量的上下文切換也是可以接受的。

                   可運作隊列:   每個處理器的可運作隊列<=3個線程。

2、監控工具   vmstat

$ vmstat 1

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------

r b swpd free buff cache si so bi bo in cs us sy id wa st

14 0 140 2904316 341912 3952308 0 0 0 460 1106 9593 36 64 1 0 0

17 0 140 2903492 341912 3951780 0 0 0 0 1037 9614 35 65 1 0 0

20 0 140 2902016 341912 3952000 0 0 0 0 1046 9739 35 64 1 0 0

17 0 140 2903904 341912 3951888 0 0 0 76 1044 9879 37 63 0 0 0

16 0 140 2904580 341912 3952108 0 0 0 0 1055 9808 34 65 1 0 0

重要參數:

r, run queue, 可運作隊列的線程數,這些線程都是可運作狀态,隻不過CPU暫時不可用;

                            一般要求小于CPU*3的數量。

       cat   /proc/stat         可以看到有幾個CPU。

b,被blocked的程序數,正在等待IO請求;

in,interrupts,被處理過的中斷數

cs,context switch,系統上正在做上下文切換的數目

us,使用者占用CPU的百分比

sys,核心和中斷占用CPU的百分比

id,CPU完全空閑的百分比

上例可得:

sy高us低,以及高頻度的上下文切換(cs),說明應用程式進行了大量的系統調用;

這台4核機器的r應該在12個以内,現在r在14個線程以上,此時CPU負荷很重。

一般我們認為,如果是4核機器,r高于8是,應該就是負載很高了。

可調優性能參數:

1、 通過調整程序優先級調整: nice 指令來調整程序優先級别;可調範圍(-20到 19) 如: renice 5 pid

2、 通過調整cpu的親和度來集中處理某一個中斷類型:(比如網卡中斷)

      将系統發出的中斷都綁定在一個cpu上,這樣其他cpu繼續執行自己正在執行的線程,不被中斷打擾,進而較少了線程上下文切換時間,增強性能;

       注: cpu親和度的概念: 在多核cpu中,linux作業系統搶占式排程系統,按照cpu時間片/中斷/等不斷排程程序給cpu去執行的;

如果在一個時間片排程線程1在cpu1上運作,另外一個時間片排程線程1在cpu2上去運作,這樣會造成線程執行速度慢,性能降低。

        為什麼呢?

        我們知道SMP上多核都是共享L1 ,L2 CPU Cache的。并且各個核的記憶體空間都是不可共享的,一個線程如果多次時間片上在不同的cpu上運作,會造成cache的不斷失效和寫入,性能會降低;

       而linux的程序排程有個親和度算法可以将盡量将程序每次都排程到同一個cpu上處理;

       linux排程時當然也有Loadbalance算法保證程序排程的均勻負載的;

       例如: echo 03 > /proc/irq/19/smp-affinity (将中斷類型為19的中斷綁定到第三個cpu上處理)

第二節:記憶體性能瓶頸 

首先,linux的記憶體管理是聰明和智能的;

        linux通過(virtual memory manage)來管理記憶體的; 對于大多數應用,linux是不直接寫到硬碟上去的,而是先寫到 virtual memory manage 管理的檔案系統緩存(也在記憶體中的)裡 ,友善應用的後續的讀請求;因為和磁盤的I/O操作是昂貴的;linux會根據一些算法政策适當的時候同步到硬碟的;這就是為什麼我們運作linux一段時間後,發現可用記憶體那麼少的原因,多數被cache+buffer占用咧;

是以我們提高性能的辦法就是減少寫到磁盤的次數,提高每次寫磁盤時的效率品質;    

機器記憶體使用情況監控:

        1、良好狀态名額

           swap in (si) == 0,swap out (so) == 0

           應用程式可用記憶體/系統實體記憶體 <= 70%

2、監控工具    vmstat

$ vmstat  1

r b swpd free buff cache si so bi bo in cs us sy id wa st

0 3 252696 2432 268 7148 3604 2368 3608 2372 288 288 0 0 21 78 1

0 2 253484 2216 228 7104 5368 2976 5372 3036 930 519 0 0 0 100 0

0 1 259252 2616 128 6148 19784 18712 19784 18712 3821 1853 0 1 3 95 1

1 2 260008 2188 144 6824 11824 2584 12664 2584 1347 1174 14 0 0 86 0

2 1 262140 2964 128 5852 24912 17304 24952 17304 4737 2341 86 10 0 0 4

swpd,    已使用的 SWAP 空間大小,KB 為機關;

free,      可用的實體記憶體大小,KB 為機關;

buff,       實體記憶體用來緩存讀寫操作的buffer大小,KB 為機關;

cache,   實體記憶體用來緩存程序位址空間的 cache 大小,KB 為機關;

si,          資料從 SWAP 讀取到 RAM(swap in)的大小,KB 為機關;

so,         資料從 RAM 寫到 SWAP(swap out)的大小,KB 為機關。

實體可用記憶體 free 基本沒什麼顯著變化,swapd逐漸增加,說明最小可用的記憶體始終保持在 256MB(實體記憶體大小) * 10% = 2.56MB 左右,當髒頁達到10%的時候就開始大量使用swap。

這個10%來自" /proc/sys/vm/dirty_background_ratio "。

1.、通過調節緩存的髒資料同步到硬碟的政策:(髒資料表示沒有被目前的線程使用的資料)

       例如: echo 10 > /proc/sys/vm/dirty_background_ratio  (當髒資料占據實體記憶體10%時,觸發pdflush同步到硬碟):

小心調節,會大幅度的影響性能;

       echo 2000 > /proc/sys/vm/dirty_expire_centisecs            (當髒資料在實體記憶體的逗留時間超過2000ms時被同步到硬碟);

2、通過調節swap參數,來優化linux虛拟記憶體管理:基于程式的局部性原理,linux通過虛拟記憶體機制來實作并發運作程序,linux發現實體記憶體不夠用時,會根據LRU算法将一部分記憶體swap out到硬碟;當運作被換出的那個線程時,在swap in 到記憶體裡;

      例如: echo 10 > /proc/sys/vm/swappiness (值為0表示盡量都用實體記憶體,值為100表示積極的使用swap分區;)這個參數很重要;小心調節; 一般為60;                              ##在緊急處理線上問題時,可以緊急使用一下。

       更多的參數:

一、作業系統設定swap的目的

       程式運作的一個必要條件就是足夠的記憶體,而記憶體往往是系統裡面比較緊張的一種資源。為了滿足更多程式的要求,作業系統虛拟了一部分記憶體位址,并将之映射到swap上。對于程式來說,它隻知道作業系統給自己配置設定了記憶體位址,但并不清楚這些記憶體位址到底映射到實體記憶體還是swap。實體記憶體和swap在功能上是一樣的,隻是因為實體存儲元件的不同(記憶體和磁盤),性能上有很大的差别。作業系統會根據程式使用記憶體的特點進行換入和換出,盡可能地把實體記憶體留給最需要它的程式。但是這種排程是按照預先設定的某種規則的,并不能完全符合程式的需要。

       一些特殊的程式(比如MySQL)希望自己的資料永遠寄存在實體記憶體裡,以便提供更高的性能。于是作業系統就設定了幾個api,以便為調用者提供“特殊服務”。

二、Linux提供的幾個api

1、mlockall()和munlockall()

        這一對函數,可以讓調用者的位址空間常駐實體記憶體,也可以在需要的時候将此特權取消。mlockall()的flag位可以是MCL_CURRENT和MCL_FUTURE的任意組合,分别代表了“保持已配置設定的位址空間常駐實體記憶體”和“保持未來配置設定的位址空間常駐實體記憶體”。對于Linux來說,這對函數是非常霸道的,隻有root使用者才有權限調用。

2、shmget()和shmat()

        這一對函數,可以向作業系統申請使用大頁記憶體(Large Page)。大頁記憶體的特點是預配置設定和永駐實體記憶體,因為使用了共享記憶體段的方式,page table有可能會比傳統的小頁配置設定方式更小。

       對于多程序共享記憶體的程式(比如ORACLE),大頁記憶體能夠節省很多page table開銷;

       而對于MySQL來說,性能和資源開銷都沒有顯著變化,好處就在于減少了記憶體位址被映射到swap上的可能。至于為什麼是減少,而不是完全避免,之後再講解。

3、O_DIRECT和posix_memalign()

        以上兩個方法都不會減少記憶體的使用量,調用者的本意是擷取更高的系統特權,而不是節約系統資源。

       O_DIRECT是一種更加理想化的方式,通過避免double buffer,節省了檔案系統cache的開銷,最終減少swap的使用率。O_DIRECT是Linux  IO排程相關的标志,在open函數裡面調用。通過O_DIRECT标志打開的檔案,讀寫都不會用到檔案系統的cache。

        傳統的資料庫(ORACLE、MySQL)基本都有O_DIRECT相關的開關,在提高性能的同時,也減少了記憶體的使用。至于posix_memalign(),是用來申請對齊的記憶體位址的。隻有用posix_memalign()申請的記憶體位址,才能用來讀寫O_DIRECT模式下的檔案描述符。

4、madvise()和fadvise()

        這對函數也是比較溫和的,可以将調用者對資料通路模式的預期傳遞給Linux,以期得到更好的性能。

我們比較感興趣的是MADV_DONTNEED和FADV_NOREUSE這兩個flag。前者會建議Linux釋放指定的記憶體區域,而後者會建議檔案系統釋放指定檔案所占用的cache。

當mysql出現記憶體導緻的性能瓶頸時,可以:

1、/proc/sys/vm/swappiness的内容改成0(臨時),/etc/sysctl.conf上添加vm.swappiness=0(永久)

       這個參數決定了Linux是傾向于使用swap,還是傾向于釋放檔案系統cache。在記憶體緊張的情況下,數值越低越傾向于釋放檔案系統cache。當然,這個參數隻能減少使用swap的機率,并不能避免Linux使用swap。

2、修改MySQL的配置參數innodb_flush_method,開啟O_DIRECT模式。

      這種情況下,InnoDB的buffer pool會直接繞過檔案系統cache來通路磁盤,但是redo log依舊會使用檔案系統cache。值得注意的是,Redo log是覆寫模式的,即使使用了檔案系統的cache,也不會占用太多。

3、添加MySQL的配置參數memlock

      這個參數會強迫mysqld程序的位址空間一直被鎖定在實體記憶體上,對于os來說是非常霸道的一個要求。必須要用root帳号來啟動MySQL才能生效。

4、還有一個比較複雜的方法,指定MySQL使用大頁記憶體(Large Page)。Linux上的大頁記憶體是不會被換出實體記憶體的,和memlock有異曲同工之妙。具體的配置方法可以參考:http://harrison-fisk.blogspot.com/2009/01/enabling-innodb-large-pages-on-linux.html

第三節: 磁盤I/O可調性能參數 

        linux的子系統VFS(virtural file system)虛拟檔案系統;從高層将各種檔案系統,以及底層磁盤特性隐藏,對程式員提供:read,write,delete等檔案操作;這就是之是以我們可以在linux上mount多種不同格式的檔案系統的,而window确不行;

當然基于:虛拟檔案系統,檔案系統,檔案系統驅動程式,硬體特性方面,都能找到性能瓶頸;

1、選擇适合應用的檔案系統;

2.、調整程序I/O請求的優先級,分三種級别:1代表 real time ; 2代表best-effort; 3代表idle ;

如:ionice -c1 -p 1113(給程序1113的I/O優先級設定為最高優先級)

3、根據應用類型,适當調整page size 和block size;

4、更新驅動程式; 

第四節 :網絡可調性能參數

       對于我們web應用來說,網絡性能調整如此重要,linux的網絡支援是無與倫比的;是作為網絡伺服器的首先;對于web服務來說:除了應用的響應速度外,linux網絡管理子系統,網卡,帶寬都可能成為性能瓶頸;

       網絡參數可以在/proc/sys/net/ipv4/   下面的檔案中進行配置。

可以檢視和設定的參數:

1、檢視網卡設定是否全雙工傳輸的: echtool eth0

2.、設定MTU(最大傳輸單元),在帶寬G以上的時候,要考慮将MTU增大,提高傳輸性能;

       如: ifconfig eth0 mtu 9000 up

       如果資料包的長度大于mtu的長度時,很容易出現丢包情況。

3.、增加網絡資料緩存;傳輸資料時linux是将包先放入緩存,填滿緩存後即發送出去;讀操作類似;

       sysctl -w net.ipv4.tcp_rmem="4096 87380 8388608" :設定tcp讀緩存:最小緩存,初始化時,最大緩存

       sysctl -w net.ipv4.tcp_wmem="4096 87380 8388608" :設定tcp寫緩存:最小緩存,初始化時,最大緩存

       由于是先将資料放入緩存再發送,或收取收據,那麼當記憶體緊張或記憶體不夠用時,網絡丢包就可能出現。

4、禁用window_scaling,并且直接設定window_size;(就像我們經常設定jvm的參數:xms = xmx一樣

       sysctl -w net.ipv4.tcp_window_scaling=0

5、設定TCP連接配接可重用性: 對于TIME_OUT狀态的TCP連接配接可用于下一個TCP重用,這樣減少了三次握手和建立時間,非常提高性能,尤其對于web server;

      如: 開啟可重用tcp功能: sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_tw_recyle=1

6、禁用掉沒必要的tcp/ip協定功能:比如icmp;broadcast包的接收;

7、linux對于keeplive的tcp連接配接有一個預設的過期時間;可以減小這個時間,讓沒用的連接配接釋放掉,畢竟tcp連接配接數是有限的嘛;

     如: sysctl -w net.ipv4.tcp_keepalive_time=1800 (設定過期時間,1800s)

8、設定最大tcp正在連接配接狀态(還沒ESTABLISHED)隊列長度;避免由于太多的tcp連接配接過來,導緻伺服器挂掉;比如DoS攻擊

     如:sysctl -w net.ipv4.tcp_max_syn_backlog=4096

9、 綁定tcp類型的中斷到一個cpu上;(讓cpu去親和這個類型中斷,避免頻繁的中斷,影響線程排程性能)

       總結: 我們在性能優化一個應用時,首要的是設定優化要達到的目标,然後尋找瓶頸,調整參數,達到優化目的;但是尋找瓶頸時可能是最累的,要從大範圍,通過很多用例,很多測試報告,不斷的縮小範圍,最終确定瓶頸點;以上這些參數隻是個認識,系統性能優化中可能用到,但并不是放之四海而皆準的; 有的參數要邊測試,邊調整的;

原文位址: http://blog.csdn.net/hn2002/article/details/7426907