第一節: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
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
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
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去親和這個類型中斷,避免頻繁的中斷,影響線程調度性能)
總結: 我們在性能優化一個應用時,首要的是設定優化要達到的目標,然後尋找瓶頸,調整參數,達到優化目的;但是尋找瓶頸時可能是最累的,要從大範圍,通過很多用例,很多測試報告,不斷的縮小範圍,最終確定瓶頸點;以上這些參數只是個認識,系統性能優化中可能用到,但並不是放之四海而皆準的; 有的參數要邊測試,邊調整的;