1. 程式人生 > 實用技巧 >linux效能調優總結

linux效能調優總結

系統性能一直是個熱門話題。做運維這幾年也一直在搞效能調優,寫這個文章也算是對工作的總結。

講調優第一步是,要講為什麼要調優?也就是系統分析,分析還需要有指標,做好效能監控的情況下,看到確實需要調優才能進行。不能為了調優而 “調優“ 那不是調優,那是破壞。

效能分析的目的

找出系統性能瓶頸
為以後的優化提供方案或者參考
達到良好利用資源的目的。硬體資源和軟體配置。

影響效能的因素

想確定有哪些因素,首先確定你的應用是什麼型別的?
例如:

  1. cpu密集型
    例如web伺服器像nginx node.js需要CPU進行批處理和數學計算都屬於此型別
  2. io密集型
    例如資料庫常見的mysql,大量消耗記憶體和儲存系統,對CPU和網路要求不高,這種應用使用CPU來發起IO請求,然後進入sleep狀態。

確定了應用型別就開始分析有哪些情況能影響效能:

大量的網頁請求會填滿執行佇列、大量的上下文切換,中斷
大量的磁碟些請求
網絡卡大量的吞吐
以及記憶體耗盡等。

歸結起來就是4個方面

cpu
memory
i/o
network

系統檢測的工具

我們知道了這四大塊影響著我們的效能,那我們有什麼工具進行檢測呢?

在工作中常用到的有:
htop vmstat iotop sar strace iftop ss lsof ethtool mtr等

另外推薦阿里的tsar以及glances進行系統性能監控。

CPU 效能監控以及調優

我們可以 通過檢查cpu使用量,通過工具觀測上下文切換、中斷以及程式碼呼叫等方面來進行優化。

首先明確幾個術語:
快取:為了提供記憶體i/o效能cpu提供硬體級快取。檢視快取可以用過 lscpu -p命令來檢視

[root@master ~]# lscpu
L1d 快取:          32K
L1i 快取:          32K
L2 快取:           256K
L3 快取:           3072K

1級快取為靜態快取,分為資料快取和指令快取。
2級和3級快取為動態快取,其中2級快取為共享快取。

為了提高cpu快取命中率我們通常的做法是把cpu繫結在某一個核上,也就是”cpu親和性”
linux下我們可以通過”taskset”命令來實現

[root@master ~]# taskset -pc 0
6552 pid 6552's current affinity list: 0 pid 6552's new affinity list: 0

但是這樣還是有問題。例如不能保證本地記憶體分配,所以這時候我們需要使用numa來解決問題

NUMA:非一致性記憶體訪問機制。每個屋裡核心都有一段自己使用的記憶體成為本地節點,都有自己的記憶體控制器,距離最近的記憶體節點成稱為鄰均節點。

上圖為numa的簡單的拓撲,來源於網際網路。

numactl可以將程式繫結到特定的numa節點

# numactl --show #檢視當前的numa配置
policy: default
preferred node: current
physcpubind: 0 
cpubind: 0 
nodebind: 0 
membind: 0 

注:資料庫伺服器不要用numa,如果要使用請在資料庫啟動請使用numactl —interleave=all。作為運維可能都被坑過。

cpu排程策略

  1. 實時排程策略
    • SCHED_FIFO 靜態排程策略,一旦佔用cpu則一直執行,一直執行直到有更高優先順序任務到達或自己放棄。
    • SCHED_RR 時間輪詢策略,當程序的時間片用完,系統將重新分配時間片,並置於就緒佇列尾。放在佇列尾保證了所有具有相同優先順序的RR任務的排程公平。
      實時排程策略作用值為1-99,數字越大優先順序越高。
  2. 一般策略
    • SCHED_OTHER 預設排程策略通過nice和counter值決定權值,nice越小,counter越大,被排程的概率越大,也就是曾經使用了cpu最少的程序將會得到優先排程。作用值為100-139,數字越小優先順序越高。
    • SCHED_BATCH
    • SCHED_IDLE

chrt 修改實時優先順序,生產中一般不要修改,預設是rr排程

SCHED_OTHER 使用nice、renice修改。
另外other支援動態調整,如果手動直接nice修改即可。

context switches:上下文切換

linux核心將每一個core當作一個獨立的處理器。一個核心可以同時執行50~50000個程序。每個執行緒將會分配一個時間片,直到這個執行緒的時間片用完,或是被更高優先順序的執行緒搶佔,它才會被重新放回cpu佇列。切換執行緒的過程就是context switch。context switch越高,則核心排程的工作負擔越大。

vmstat 既可以看到 cs的高低

run queue 執行佇列

每個cpu都有一個執行佇列。執行緒,要麼在sleep狀態(阻塞並等待IO),要麼在執行狀態。執行佇列越長,則等待cpu處理這個執行緒的時間越長。執行佇列是全域性的會被所有CPU共享

load就是用來描述執行佇列的。它的值等於當前正在處理的執行緒+執行佇列裡面的執行緒。

比如當前系統核數是2,有兩個執行緒正在執行行,還有4個執行緒在執行佇列裡面,那麼它的load=2+4。

vmstat w uptime 都可以觀測執行佇列負載情況。

cpu效能監控

說了這麼多,那正常情況下需要觀察哪些值呢?
首先numa 以及演算法都是特殊情況下優化的,一般情況下不會去動這些,需要根據你的業務場景來進行繫結調整,像虛擬化,雲端計算等可能就需要進行調整。

那麼我們日常需要觀測的效能點是:

  1. cpu利用率
    • us 60%-70%
    • sy 30%-35%
    • id 0%-5%
  2. cs上下文切換
    • cs和cpu利用率相關,如果能保持上面所說的利用率大量的切換可以接受
  3. 執行佇列
    • 小於等於4最好

例子:

# vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  0 1150840 271628 260684 5530984    0    0     2     1    0    0 22  4 73  0  0
 5  0 1150840 270264 260684 5531032    0    0     0     0 5873 6085 13 13 73  0  0
 5  0 1150840 263940 260684 5531040    0    0     0     4 6721 7507 15 13 72  0  0
 4  0 1150840 263320 260684 5531068    0    0     0     0 6111 7117 10 13 76  0  0
 4  0 1150840 262328 260684 5531072    0    0     0     0 6854 7673 18 13 68  0  0

例子中cpu中斷(in)以及上下文切換(cs)都比較高,說明核心不得不來回切換程序,同時in也是比較高說明cpu一直在請求資源。

記憶體memory

術語
MMU:
CPU是不能與硬碟打交道的,只有資料被載入到記憶體中才可以被CPU呼叫。cpu在訪問記憶體的時候需要先像記憶體監控程式請求,由監控程式控制和分配記憶體的讀寫請求,這個監控程式叫做MMU(記憶體管理單元)

線性地址到實體地址的對映,如果按照1個位元組1個位元組對映的話,需要一張非常大的表,這種轉換關係會非常的複雜。因此把記憶體空間又劃分成了另外一種儲存單元格式,通常為4K。

每個程序如果需要訪問記憶體的時候都需要去查詢page table的話需要藉助緩衝器TLB,但每次產找tlb沒有或者大量查詢還是會造成緩慢,所以又有了page table的分級目錄。page table可以分為1級目錄,2級目錄和偏移量。

另外讓系統管理大量記憶體有兩種方法:

  1. 增加硬體記憶體管理單元中頁表數
  2. 增大頁面大小
    第一種方法不太現實,所有我們考慮第二種方法。即:大頁面。
    32位系統4m大頁框64位系統2m大頁框,頁框越粗浪費越嚴重。
    檢視系統的大頁面:

    cat /proc/meminfo

    AnonHugePages: 309248 kB
    HugePages_Total: 0
    HugePages_Free: 0
    HugePages_Rsvd: 0
    HugePages_Surp: 0
    Hugepagesize: 2048 kB
    DirectMap4k: 6144 kB
    DirectMap2M: 1042432 kB
    DirectMap1G: 0 kB
    AnonHugePages:透明大頁面,THP是一個提取層,可自動建立、管理和使用超大頁面的大多數方面。
    另外HP必須在引導時設定。
    手動設定大頁面的頁數:
    sysctl vm.nr_hugepages = 20

DMA:直接讀取記憶體
在實現DMA傳輸時,是由DMA控制器直接掌管匯流排,因此,存在著一個匯流排控制權轉移問題。即DMA傳輸前,CPU要把匯流排控制權交給DMA控制器,而在結束DMA傳輸後,DMA控制器應立即把匯流排控制權再交回給CPU。一個完整的DMA傳輸過程必須經過DMA請求、DMA響應、DMA傳輸、DMA結束4個步驟。

虛擬記憶體:
32位的系統上每一個程序在訪問記憶體的時候,每一個程序都當做自己有4個G的記憶體空間可用,這叫虛擬記憶體(地址),虛擬記憶體轉化成實體記憶體是通過MMU來完成的。生產中我們儘量不使用虛擬記憶體。

影響系統性能的幾個記憶體引數:

  1. overcommit_memory 過量使用記憶體
    • 0 預設設定系統決定是否過量使用。
    • 1 不過量使用
    • 2 過量使用但有一定的比例預設百分值五十由overcommit_ratio決定(他就是預設的50),舉個例子實體記憶體8g,swap4g,可以過量使用10g。
      注:生產中儘量避免過量使用,例如redis要關閉過量使用。
  2. spappines
    -將不活躍的程序換進swap。注:儘量不去使用swap。
    生產中設定:
    echp 10 > /proc/sys/vm/swappines
  3. 回收記憶體
    • 這個值設定為 1、2 或者 3 讓核心放棄各種頁快取和 slab 快取的各種組合。
      1 系統無效並釋放所有頁緩衝記憶體即buffers
      2 系統釋放所有未使用的 slab 緩衝記憶體。即cached
      3 系統釋放所有頁緩衝和 slab 緩衝記憶體。
      生產中使用:
      1.執行sync
    1. echo 3>/proc/sys/vm/drop_caches

i/o

IO子系統一般是linux系統中最慢的部分。一個原因是它距離CPU的距離,另一個原因是它的物理結構。因此儘量要減少磁碟IO。

磁碟排程策略:

[root@master ~]# cat /sys/block/sda/queue/scheduler 
noop [deadline] cfq 

其中當前使用cfq策略。
cfq:完全公平排程。在其時間片段中,程序每次最多可有八個請求(默
認)。排程程式會嘗試根據歷史資料估計某個程式是否會在近期發出更多 I/O,然後 CFQ 會閒置,等待那個
I/O,即使有其他程序正在等待發出 I/O
deadline:每一個請求在指定的期限前必須得到服務。
noop:沒有策略
anticipatory:已被拋棄,寫多讀少的場景使用。

linux核心以page為單位訪問磁碟IO,一般為4K。
檢視page: /usr/bin/time -v date

MPF
linux會將記憶體實體地址空間對映到虛擬記憶體,核心僅會對映需要的記憶體頁。當應用啟動時,核心依次搜尋CPU cache和實體記憶體,查詢是否有相應的記憶體頁,如果不存在,則核心將會發起一次MPF(major page fault),將磁碟中的資料讀出並快取到記憶體中。

如果在buffer cache找到了對應的記憶體頁,則將會產生一個MnPF(minor page fault).

/usr/bin/time -v helloworld
第一次執行會發現大部分是MPF
第二次執行會發現大部分是MnPF

The File Buffer Cache

file buffer cache用來減少MPF,增加MnPF,它將會持續增長,直到可用記憶體比較少或是核心需要為其它應用來釋放一些記憶體。free記憶體比較少,並不能說明系統記憶體緊張,只能說明linux系統充分使用記憶體來做cache.

[root@master ~]# cat /proc/meminfo 
MemTotal:         995896 kB
MemFree:          715976 kB
MemAvailable:     719832 kB
Buffers:            3140 kB

將資料頁寫回磁碟
可以使用fsync()或是sync()立即寫回,如果沒有直接呼叫這些函式,pdflush會定期刷回磁碟。

iotop可以顯示所有程序的IO佔用情況
lsof可以檢視所有的呼叫並開啟的檔案

其他命令:
vmstat sar iostat top htop等