第一節: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