日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

Part1Linux性能優(yōu)化

1性能優(yōu)化

性能指標(biāo)

高并發(fā)和響應(yīng)快對(duì)應(yīng)著性能優(yōu)化的兩個(gè)核心指標(biāo):吞吐延時(shí)

圖片來自: www.ctq6.cn
  • 應(yīng)用負(fù)載角度:直接影響了產(chǎn)品終端的用戶體驗(yàn)
  • 系統(tǒng)資源角度:資源使用率、飽和度等

    性能問題的本質(zhì)就是系統(tǒng)資源已經(jīng)到達(dá)瓶頸,但請(qǐng)求的處理還不夠快,無(wú)法支撐更多的請(qǐng)求。性能分析實(shí)際上就是找出應(yīng)用或系統(tǒng)的瓶頸,設(shè)法去避免或緩解它們。

    • 選擇指標(biāo)評(píng)估應(yīng)用程序和系統(tǒng)性能
    • 為應(yīng)用程序和系統(tǒng)設(shè)置性能目標(biāo)
    • 進(jìn)行性能基準(zhǔn)測(cè)試
    • 性能分析定位瓶頸
    • 性能監(jiān)控和告警

      對(duì)于不同的性能問題要選取不同的性能分析工具。下面是常用的Linux Performance Tools以及對(duì)應(yīng)分析的性能問題類型。

      圖片來自: www.ctq6.cn

      到底應(yīng)該怎么理解”平均負(fù)載”

      平均負(fù)載:單位時(shí)間內(nèi),系統(tǒng)處于可運(yùn)行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù),也就是平均活躍進(jìn)程數(shù)。它和我們傳統(tǒng)意義上理解的CPU使用率并沒有直接關(guān)系。

      其中不可中斷進(jìn)程是正處于內(nèi)核態(tài)關(guān)鍵流程中的進(jìn)程(如常見的等待設(shè)備的I/O響應(yīng))。不可中斷狀態(tài)實(shí)際上是系統(tǒng)對(duì)進(jìn)程和硬件設(shè)備的一種保護(hù)機(jī)制。

      平均負(fù)載多少時(shí)合理

      實(shí)際生產(chǎn)環(huán)境中將系統(tǒng)的平均負(fù)載監(jiān)控起來,根據(jù)歷史數(shù)據(jù)判斷負(fù)載的變化趨勢(shì)。當(dāng)負(fù)載存在明顯升高趨勢(shì)時(shí),及時(shí)進(jìn)行分析和調(diào)查。當(dāng)然也可以當(dāng)設(shè)置閾值(如當(dāng)平均負(fù)載高于CPU數(shù)量的70%時(shí))

      現(xiàn)實(shí)工作中我們會(huì)經(jīng)?;煜骄?fù)載和CPU使用率的概念,其實(shí)兩者并不完全對(duì)等:

      • CPU密集型進(jìn)程,大量CPU使用會(huì)導(dǎo)致平均負(fù)載升高,此時(shí)兩者一致
      • I/O密集型進(jìn)程,等待I/O也會(huì)導(dǎo)致平均負(fù)載升高,此時(shí)CPU使用率并不一定高
      • 大量等待CPU的進(jìn)程調(diào)度會(huì)導(dǎo)致平均負(fù)載升高,此時(shí)CPU使用率也會(huì)比較高

        平均負(fù)載高時(shí)可能是CPU密集型進(jìn)程導(dǎo)致,也可能是I/O繁忙導(dǎo)致。具體分析時(shí)可以結(jié)合mpstat/pidstat工具輔助分析負(fù)載來源

        2CPU

        CPU上下文切換(上)

        CPU上下文切換,就是把前一個(gè)任務(wù)的CPU上下文(CPU寄存器和PC)保存起來,然后加載新任務(wù)的上下文到這些寄存器和程序計(jì)數(shù)器,最后再跳轉(zhuǎn)到程序計(jì)數(shù)器所指的位置,運(yùn)行新任務(wù)。其中,保存下來的上下文會(huì)存儲(chǔ)在系統(tǒng)內(nèi)核中,待任務(wù)重新調(diào)度執(zhí)行時(shí)再加載,保證原來的任務(wù)狀態(tài)不受影響。

        按照任務(wù)類型,CPU上下文切換分為:

        • 進(jìn)程上下文切換
        • 線程上下文切換
        • 中斷上下文切換

          進(jìn)程上下文切換

          Linux進(jìn)程按照等級(jí)權(quán)限將進(jìn)程的運(yùn)行空間分為內(nèi)核空間和用戶空間。從用戶態(tài)向內(nèi)核態(tài)轉(zhuǎn)變時(shí)需要通過系統(tǒng)調(diào)用來完成。

          一次系統(tǒng)調(diào)用過程其實(shí)進(jìn)行了兩次CPU上下文切換:

          • CPU寄存器中用戶態(tài)的指令位置先保存起來,CPU寄存器更新為內(nèi)核態(tài)指令的位置,跳轉(zhuǎn)到內(nèi)核態(tài)運(yùn)行內(nèi)核任務(wù);
          • 系統(tǒng)調(diào)用結(jié)束后,CPU寄存器恢復(fù)原來保存的用戶態(tài)數(shù)據(jù),再切換到用戶空間繼續(xù)運(yùn)行。

            系統(tǒng)調(diào)用過程中并不會(huì)涉及虛擬內(nèi)存等進(jìn)程用戶態(tài)資源,也不會(huì)切換進(jìn)程。和傳統(tǒng)意義上的進(jìn)程上下文切換不同。因此系統(tǒng)調(diào)用通常稱為特權(quán)模式切換。

            進(jìn)程是由內(nèi)核管理和調(diào)度的,進(jìn)程上下文切換只能發(fā)生在內(nèi)核態(tài)。因此相比系統(tǒng)調(diào)用來說,在保存當(dāng)前進(jìn)程的內(nèi)核狀態(tài)和CPU寄存器之前,需要先把該進(jìn)程的虛擬內(nèi)存,棧保存下來。再加載新進(jìn)程的內(nèi)核態(tài)后,還要刷新進(jìn)程的虛擬內(nèi)存和用戶棧。

            進(jìn)程只有在調(diào)度到CPU上運(yùn)行時(shí)才需要切換上下文,有以下幾種場(chǎng)景:CPU時(shí)間片輪流分配,系統(tǒng)資源不足導(dǎo)致進(jìn)程掛起,進(jìn)程通過sleep函數(shù)主動(dòng)掛起,高優(yōu)先級(jí)進(jìn)程搶占時(shí)間片,硬件中斷時(shí)CPU上的進(jìn)程被掛起轉(zhuǎn)而執(zhí)行內(nèi)核中的中斷服務(wù)。

            線程上下文切換

            線程上下文切換分為兩種:

            • 前后線程同屬于一個(gè)進(jìn)程,切換時(shí)虛擬內(nèi)存資源不變,只需要切換線程的私有數(shù)據(jù),寄存器等;
            • 前后線程屬于不同進(jìn)程,與進(jìn)程上下文切換相同。

              同進(jìn)程的線程切換消耗資源較少,這也是多線程的優(yōu)勢(shì)。

              中斷上下文切換

              中斷上下文切換并不涉及到進(jìn)程的用戶態(tài),因此中斷上下文只包括內(nèi)核態(tài)中斷服務(wù)程序執(zhí)行所必須的狀態(tài)(CPU寄存器,內(nèi)核堆棧,硬件中斷參數(shù)等)。

              中斷處理優(yōu)先級(jí)比進(jìn)程高,所以中斷上下文切換和進(jìn)程上下文切換不會(huì)同時(shí)發(fā)生

              Docker+K8s+Jenkins 主流技術(shù)全解視頻資料

              CPU上下文切換(下)

              通過vmstat可以查看系統(tǒng)總體的上下文切換情況

              vmstat 5         #每隔5s輸出一組數(shù)據(jù)
              procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
               r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
               1  0      0 103388 145412 511056    0    0    18    60    1    1  2  1 96  0  0
               0  0      0 103388 145412 511076    0    0     0     2  450 1176  1  1 99  0  0
               0  0      0 103388 145412 511076    0    0     0     8  429 1135  1  1 98  0  0
               0  0      0 103388 145412 511076    0    0     0     0  431 1132  1  1 98  0  0
               0  0      0 103388 145412 511076    0    0     0    10  467 1195  1  1 98  0  0
               1  0      0 103388 145412 511076    0    0     0     2  426 1139  1  0 99  0  0
               4  0      0  95184 145412 511108    0    0     0    74  500 1228  4  1 94  0  0
               0  0      0 103512 145416 511076    0    0     0   455  723 1573 12  3 83  2  0

              登錄后復(fù)制

              • cs (context switch) 每秒上下文切換次數(shù)
              • in (interrupt) 每秒中斷次數(shù)
              • r (runnning or runnable)就緒隊(duì)列的長(zhǎng)度,正在運(yùn)行和等待CPU的進(jìn)程數(shù)
              • b (Blocked) 處于不可中斷睡眠狀態(tài)的進(jìn)程數(shù)

                要查看每個(gè)進(jìn)程的詳細(xì)情況,需要使用pidstat來查看每個(gè)進(jìn)程上下文切換情況

                pidstat -w 5
                14時(shí)51分16秒   UID       PID   cswch/s nvcswch/s  Command
                14時(shí)51分21秒     0         1      0.80      0.00  systemd
                14時(shí)51分21秒     0         6      1.40      0.00  ksoftirqd/0
                14時(shí)51分21秒     0         9     32.67      0.00  rcu_sched
                14時(shí)51分21秒     0        11      0.40      0.00  watchdog/0
                14時(shí)51分21秒     0        32      0.20      0.00  khugepaged
                14時(shí)51分21秒     0       271      0.20      0.00  jbd2/vda1-8
                14時(shí)51分21秒     0      1332      0.20      0.00  argusagent
                14時(shí)51分21秒     0      5265     10.02      0.00  AliSecGuard
                14時(shí)51分21秒     0      7439      7.82      0.00  kworker/0:2
                14時(shí)51分21秒     0      7906      0.20      0.00  pidstat
                14時(shí)51分21秒     0      8346      0.20      0.00  sshd
                14時(shí)51分21秒     0     20654      9.82      0.00  AliYunDun
                14時(shí)51分21秒     0     25766      0.20      0.00  kworker/u2:1
                14時(shí)51分21秒     0     28603      1.00      0.00  python3

                登錄后復(fù)制

                • cswch 每秒自愿上下文切換次數(shù) (進(jìn)程無(wú)法獲取所需資源導(dǎo)致的上下文切換)
                • nvcswch 每秒非自愿上下文切換次數(shù) (時(shí)間片輪流等系統(tǒng)強(qiáng)制調(diào)度)
                  vmstat 1 1    #首先獲取空閑系統(tǒng)的上下文切換次數(shù)
                  sysbench --threads=10 --max-time=300 threads run #模擬多線程切換問題
                  
                  vmstat 1 1    #新終端觀察上下文切換情況
                  此時(shí)發(fā)現(xiàn)cs數(shù)據(jù)明顯升高,同時(shí)觀察其他指標(biāo):
                  r列: 遠(yuǎn)超系統(tǒng)CPU個(gè)數(shù),說明存在大量CPU競(jìng)爭(zhēng)
                  us和sy列:sy列占比80%,說明CPU主要被內(nèi)核占用
                  in列: 中斷次數(shù)明顯上升,說明中斷處理也是潛在問題

                  登錄后復(fù)制

                  說明運(yùn)行/等待CPU的進(jìn)程過多,導(dǎo)致大量的上下文切換,上下文切換導(dǎo)致系統(tǒng)的CPU占用率高

                  pidstat -w -u 1  #查看到底哪個(gè)進(jìn)程導(dǎo)致的問題

                  登錄后復(fù)制

                  從結(jié)果中看出是sysbench導(dǎo)致CPU使用率過高,但是pidstat輸出的上下文次數(shù)加起來也并不多。分析sysbench模擬的是線程的切換,因此需要在pidstat后加-t參數(shù)查看線程指標(biāo)。

                  另外對(duì)于中斷次數(shù)過多,我們可以通過/proc/interrupts文件讀取

                  watch -d cat /proc/interrupts

                  登錄后復(fù)制

                  發(fā)現(xiàn)次數(shù)變化速度最快的是重調(diào)度中斷(RES),該中斷用來喚醒空閑狀態(tài)的CPU來調(diào)度新的任務(wù)運(yùn)行。分析還是因?yàn)檫^多任務(wù)的調(diào)度問題,和上下文切換分析一致。

                  某個(gè)應(yīng)用的CPU使用率達(dá)到100%,怎么辦?

                  Linux作為多任務(wù)操作系統(tǒng),將CPU時(shí)間劃分為很短的時(shí)間片,通過調(diào)度器輪流分配給各個(gè)任務(wù)使用。為了維護(hù)CPU時(shí)間,Linux通過事先定義的節(jié)拍率,觸發(fā)時(shí)間中斷,并使用全局變了jiffies記錄開機(jī)以來的節(jié)拍數(shù)。時(shí)間中斷發(fā)生一次該值+1.

                  CPU使用率,除了空閑時(shí)間以外的其他時(shí)間占總CPU時(shí)間的百分比??梢酝ㄟ^/proc/stat中的數(shù)據(jù)來計(jì)算出CPU使用率。因?yàn)?proc/stat時(shí)開機(jī)以來的節(jié)拍數(shù)累加值,計(jì)算出來的是開機(jī)以來的平均CPU使用率,一般意義不大??梢蚤g隔取一段時(shí)間的兩次值作差來計(jì)算該段時(shí)間內(nèi)的平均CPU使用率。性能分析工具給出的都是間隔一段時(shí)間的平均CPU使用率,要注意間隔時(shí)間的設(shè)置。

                  CPU使用率可以通過top 或 ps來查看。分析進(jìn)程的CPU問題可以通過perf,它以性能事件采樣為基礎(chǔ),不僅可以分析系統(tǒng)的各種事件和內(nèi)核性能,還可以用來分析指定應(yīng)用程序的性能問題。

                  perf top / perf record / perf report (-g 開啟調(diào)用關(guān)系的采樣)

                  sudo docker run --name nginx -p 10000:80 -itd feisky/nginx
                  sudo docker run --name phpfpm -itd --network container:nginx feisky/php-fpm
                  
                  ab -c 10 -n 100 http://XXX.XXX.XXX.XXX:10000/ #測(cè)試Nginx服務(wù)性能

                  登錄后復(fù)制

                  發(fā)現(xiàn)此時(shí)每秒可承受請(qǐng)求給長(zhǎng)少,此時(shí)將測(cè)試的請(qǐng)求數(shù)從100增加到10000。在另外一個(gè)終端運(yùn)行top查看每個(gè)CPU的使用率。發(fā)現(xiàn)系統(tǒng)中幾個(gè)php-fpm進(jìn)程導(dǎo)致CPU使用率驟升。

                  接著用perf來分析具體是php-fpm中哪個(gè)函數(shù)導(dǎo)致該問題。

                  perf top -g -p XXXX #對(duì)某一個(gè)php-fpm進(jìn)程進(jìn)行分析

                  登錄后復(fù)制

                  發(fā)現(xiàn)其中sqrt和add_function占用CPU過多, 此時(shí)查看源碼找到原來是sqrt中在發(fā)布前沒有刪除測(cè)試代碼段,存在一個(gè)百萬(wàn)次的循環(huán)導(dǎo)致。將該無(wú)用代碼刪除后發(fā)現(xiàn)nginx負(fù)載能力明顯提升

                  系統(tǒng)的CPU使用率很高,為什么找不到高CPU的應(yīng)用?

                  sudo docker run --name nginx -p 10000:80 -itd feisky/nginx:sp
                  sudo docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:sp
                  ab -c 100 -n 1000 http://XXX.XXX.XXX.XXX:10000/ #并發(fā)100個(gè)請(qǐng)求測(cè)試

                  登錄后復(fù)制

                  實(shí)驗(yàn)結(jié)果中每秒請(qǐng)求數(shù)依舊不高,我們將并發(fā)請(qǐng)求數(shù)降為5后,nginx負(fù)載能力依舊很低。

                  此時(shí)用top和pidstat發(fā)現(xiàn)系統(tǒng)CPU使用率過高,但是并沒有發(fā)現(xiàn)CPU使用率高的進(jìn)程。

                  出現(xiàn)這種情況一般時(shí)我們分析時(shí)遺漏的什么信息,重新運(yùn)行top命令并觀察一會(huì)。發(fā)現(xiàn)就緒隊(duì)列中處于Running狀態(tài)的進(jìn)行過多,超過了我們的并發(fā)請(qǐng)求次數(shù)5. 再仔細(xì)查看進(jìn)程運(yùn)行數(shù)據(jù),發(fā)現(xiàn)nginx和php-fpm都處于sleep狀態(tài),真正處于運(yùn)行的卻是幾個(gè)stress進(jìn)程。

                  下一步就利用pidstat分析這幾個(gè)stress進(jìn)程,發(fā)現(xiàn)沒有任何輸出。用ps aux交叉驗(yàn)證發(fā)現(xiàn)依舊不存在該進(jìn)程。說明不是工具的問題。再top查看發(fā)現(xiàn)stress進(jìn)程的進(jìn)程號(hào)變化了,此時(shí)有可能時(shí)以下兩種原因?qū)е拢?/span>

                  • 進(jìn)程不停的崩潰重啟(如段錯(cuò)誤/配置錯(cuò)誤等),此時(shí)進(jìn)程退出后可能又被監(jiān)控系統(tǒng)重啟;
                  • 短時(shí)進(jìn)程導(dǎo)致,即其他應(yīng)用內(nèi)部通過exec調(diào)用的外面命令,這些命令一般只運(yùn)行很短時(shí)間就結(jié)束,很難用top這種間隔較長(zhǎng)的工具來發(fā)現(xiàn)

                    可以通過pstree來查找 stress的父進(jìn)程,找出調(diào)用關(guān)系。

                    pstree | grep stress

                    登錄后復(fù)制

                    發(fā)現(xiàn)是php-fpm調(diào)用的該子進(jìn)程,此時(shí)去查看源碼可以看出每個(gè)請(qǐng)求都會(huì)調(diào)用一個(gè)stress命令來模擬I/O壓力。之前top顯示的結(jié)果是CPU使用率升高,是否真的是由該stress命令導(dǎo)致的,還需要繼續(xù)分析。代碼中給每個(gè)請(qǐng)求加了verbose=1的參數(shù)后可以查看stress命令的輸出,在中斷測(cè)試該命令結(jié)果顯示stress命令運(yùn)行時(shí)存在因權(quán)限問題導(dǎo)致的文件創(chuàng)建失敗的bug。

                    此時(shí)依舊只是猜測(cè),下一步繼續(xù)通過perf工具來分析。性能報(bào)告顯示確實(shí)時(shí)stress占用了大量的CPU,通過修復(fù)權(quán)限問題來優(yōu)化解決即可.

                    系統(tǒng)中出現(xiàn)大量不可中斷進(jìn)程和僵尸進(jìn)程怎么辦?

                    進(jìn)程狀態(tài)

                    • R Running/Runnable,表示進(jìn)程在CPU的就緒隊(duì)列中,正在運(yùn)行或者等待運(yùn)行;
                    • D Disk Sleep,不可中斷狀態(tài)睡眠,一般表示進(jìn)程正在跟硬件交互,并且交互過程中不允許被其他進(jìn)程中斷;
                    • Z Zombie,僵尸進(jìn)程,表示進(jìn)程實(shí)際上已經(jīng)結(jié)束,但是父進(jìn)程還沒有回收它的資源;
                    • S Interruptible Sleep,可中斷睡眠狀態(tài),表示進(jìn)程因?yàn)榈却硞€(gè)事件而被系統(tǒng)掛起,當(dāng)?shù)却录l(fā)生則會(huì)被喚醒并進(jìn)入R狀態(tài);
                    • I Idle,空閑狀態(tài),用在不可中斷睡眠的內(nèi)核線程上。該狀態(tài)不會(huì)導(dǎo)致平均負(fù)載升高;
                    • T Stop/Traced,表示進(jìn)程處于暫?;蚋櫊顟B(tài)(SIGSTOP/SIGCONT, GDB調(diào)試);
                    • X Dead,進(jìn)程已經(jīng)消亡,不會(huì)在top/ps中看到。

                      對(duì)于不可中斷狀態(tài),一般都是在很短時(shí)間內(nèi)結(jié)束,可忽略。但是如果系統(tǒng)或硬件發(fā)生故障,進(jìn)程可能會(huì)保持不可中斷狀態(tài)很久,甚至系統(tǒng)中出現(xiàn)大量不可中斷狀態(tài),此時(shí)需注意是否出現(xiàn)了I/O性能問題。

                      僵尸進(jìn)程一般多進(jìn)程應(yīng)用容易遇到,父進(jìn)程來不及處理子進(jìn)程狀態(tài)時(shí)子進(jìn)程就提前退出,此時(shí)子進(jìn)程就變成了僵尸進(jìn)程。大量的僵尸進(jìn)程會(huì)用盡PID進(jìn)程號(hào),導(dǎo)致新進(jìn)程無(wú)法建立。

                      磁盤O_DIRECT問題

                      sudo docker run --privileged --name=app -itd feisky/app:iowait
                      ps aux | grep '/app'

                      登錄后復(fù)制

                      可以看到此時(shí)有多個(gè)app進(jìn)程運(yùn)行,狀態(tài)分別時(shí)Ss+和D+。其中后面s表示進(jìn)程是一個(gè)會(huì)話的領(lǐng)導(dǎo)進(jìn)程,+號(hào)表示前臺(tái)進(jìn)程組。

                      其中進(jìn)程組表示一組相互關(guān)聯(lián)的進(jìn)程,子進(jìn)程是父進(jìn)程所在組的組員。會(huì)話指共享同一個(gè)控制終端的一個(gè)或多個(gè)進(jìn)程組。

                      用top查看系統(tǒng)資源發(fā)現(xiàn):1)平均負(fù)載在逐漸增加,且1分鐘內(nèi)平均負(fù)載達(dá)到了CPU個(gè)數(shù),說明系統(tǒng)可能已經(jīng)有了性能瓶頸;2)僵尸進(jìn)程比較多且在不停增加;3)us和sys CPU使用率都不高,iowait卻比較高;4)每個(gè)進(jìn)程CPU使用率也不高,但有兩個(gè)進(jìn)程處于D狀態(tài),可能在等待IO。

                      分析目前數(shù)據(jù)可知:iowait過高導(dǎo)致系統(tǒng)平均負(fù)載升高,僵尸進(jìn)程不斷增長(zhǎng)說明有程序沒能正確清理子進(jìn)程資源。

                      用dstat來分析,因?yàn)樗梢酝瑫r(shí)查看CPU和I/O兩種資源的使用情況,便于對(duì)比分析。

                      dstat 1 10    #間隔1秒輸出10組數(shù)據(jù)

                      登錄后復(fù)制

                      可以看到當(dāng)wai(iowait)升高時(shí)磁盤請(qǐng)求read都會(huì)很大,說明iowait的升高和磁盤的讀請(qǐng)求有關(guān)。接下來分析到底時(shí)哪個(gè)進(jìn)程在讀磁盤。

                      之前top查看的處于D狀態(tài)的進(jìn)程號(hào),用pidstat -d -p XXX 展示進(jìn)程的I/O統(tǒng)計(jì)數(shù)據(jù)。發(fā)現(xiàn)處于D狀態(tài)的進(jìn)程都沒有任何讀寫操作。在用pidstat -d 查看所有進(jìn)程的I/O統(tǒng)計(jì)數(shù)據(jù),看到app進(jìn)程在進(jìn)行磁盤讀操作,每秒讀取32MB的數(shù)據(jù)。進(jìn)程訪問磁盤必須使用系統(tǒng)調(diào)用處于內(nèi)核態(tài),接下來重點(diǎn)就是找到app進(jìn)程的系統(tǒng)調(diào)用。

                      sudo strace -p XXX #對(duì)app進(jìn)程調(diào)用進(jìn)行跟蹤

                      登錄后復(fù)制

                      報(bào)錯(cuò)沒有權(quán)限,因?yàn)橐呀?jīng)時(shí)root權(quán)限了。所以遇到這種情況,首先要檢查進(jìn)程狀態(tài)是否正常。ps命令查找該進(jìn)程已經(jīng)處于Z狀態(tài),即僵尸進(jìn)程。

                      這種情況下top pidstat之類的工具無(wú)法給出更多的信息,此時(shí)像第5篇一樣,用perf record -d和perf report進(jìn)行分析,查看app進(jìn)程調(diào)用棧。

                      看到app確實(shí)在通過系統(tǒng)調(diào)用sys_read()讀取數(shù)據(jù),并且從new_sync_read和blkdev_direct_IO看出進(jìn)程時(shí)進(jìn)行直接讀操作,請(qǐng)求直接從磁盤讀,沒有通過緩存導(dǎo)致iowait升高。

                      通過層層分析后,root cause是app內(nèi)部進(jìn)行了磁盤的直接I/O。然后定位到具體代碼位置進(jìn)行優(yōu)化即可。

                      僵尸進(jìn)程

                      上述優(yōu)化后iowait顯著下降,但是僵尸進(jìn)程數(shù)量仍舊在增加。首先要定位僵尸進(jìn)程的父進(jìn)程,通過pstree -aps XXX,打印出該僵尸進(jìn)程的調(diào)用樹,發(fā)現(xiàn)父進(jìn)程就是app進(jìn)程。

                      查看app代碼,看看子進(jìn)程結(jié)束的處理是否正確(是否調(diào)用wait()/waitpid(),有沒有注冊(cè)SIGCHILD信號(hào)的處理函數(shù)等)。

                      碰到iowait升高時(shí),先用dstat pidstat等工具確認(rèn)是否存在磁盤I/O問題,再找是哪些進(jìn)程導(dǎo)致I/O,不能用strace直接分析進(jìn)程調(diào)用時(shí)可以通過perf工具分析。

                      對(duì)于僵尸問題,用pstree找到父進(jìn)程,然后看源碼檢查子進(jìn)程結(jié)束的處理邏輯即可。

                      CPU性能指標(biāo)

                      • CPU使用率

                        • 用戶CPU使用率, 包括用戶態(tài)(user)和低優(yōu)先級(jí)用戶態(tài)(nice). 該指標(biāo)過高說明應(yīng)用程序比較繁忙.
                        • 系統(tǒng)CPU使用率, CPU在內(nèi)核態(tài)運(yùn)行的時(shí)間百分比(不含中斷). 該指標(biāo)高說明內(nèi)核比較繁忙.
                        • 等待I/O的CPU使用率, iowait, 該指標(biāo)高說明系統(tǒng)與硬件設(shè)備I/O交互時(shí)間比較長(zhǎng).
                        • 軟/硬中斷CPU使用率, 該指標(biāo)高說明系統(tǒng)中發(fā)生大量中斷.
                        • steal CPU / guest CPU, 表示虛擬機(jī)占用的CPU百分比.
                        • 平均負(fù)載

                          理想情況下平均負(fù)載等于邏輯CPU個(gè)數(shù),表示每個(gè)CPU都被充分利用. 若大于則說明系統(tǒng)負(fù)載較重.

                        • 進(jìn)程上下文切換

                          包括無(wú)法獲取資源的自愿切換和系統(tǒng)強(qiáng)制調(diào)度時(shí)的非自愿切換. 上下文切換本身是保證Linux正常運(yùn)行的一項(xiàng)核心功能. 過多的切換則會(huì)將原本運(yùn)行進(jìn)程的CPU時(shí)間消耗在寄存器,內(nèi)核占及虛擬內(nèi)存等數(shù)據(jù)保存和恢復(fù)上。另外,搜索公眾號(hào)程序員小樂后臺(tái)回復(fù)“面試題”,獲取一份驚喜禮包。

                        • CPU緩存命中率

                          CPU緩存的復(fù)用情況,命中率越高性能越好. 其中L1/L2常用在單核,L3則用在多核中

                          性能工具

                          • 平均負(fù)載案例
                            • 先用uptime查看系統(tǒng)平均負(fù)載
                            • 判斷負(fù)載在升高后再用mpstat和pidstat分別查看每個(gè)CPU和每個(gè)進(jìn)程CPU使用情況.找出導(dǎo)致平均負(fù)載較高的進(jìn)程.
                            • 上下文切換案例
                              • 先用vmstat查看系統(tǒng)上下文切換和中斷次數(shù)
                              • 再用pidstat觀察進(jìn)程的自愿和非自愿上下文切換情況
                              • 最后通過pidstat觀察線程的上下文切換情況
                              • 進(jìn)程CPU使用率高案例
                                • 先用top查看系統(tǒng)和進(jìn)程的CPU使用情況,定位到進(jìn)程
                                • 再用perf top觀察進(jìn)程調(diào)用鏈,定位到具體函數(shù)
                                • 系統(tǒng)CPU使用率高案例
                                  • 先用top查看系統(tǒng)和進(jìn)程的CPU使用情況,top/pidstat都無(wú)法找到CPU使用率高的進(jìn)程
                                  • 重新審視top輸出
                                  • 從CPU使用率不高,但是處于Running狀態(tài)的進(jìn)程入手
                                  • perf record/report發(fā)現(xiàn)短時(shí)進(jìn)程導(dǎo)致 (execsnoop工具)
                                  • 不可中斷和僵尸進(jìn)程案例
                                    • 先用top觀察iowait升高,發(fā)現(xiàn)大量不可中斷和僵尸進(jìn)程
                                    • strace無(wú)法跟蹤進(jìn)程系統(tǒng)調(diào)用
                                    • perf分析調(diào)用鏈發(fā)現(xiàn)根源來自磁盤直接I/O
                                    • 軟中斷案例
                                      • top觀察系統(tǒng)軟中斷CPU使用率高
                                      • 查看/proc/softirqs找到變化速率較快的幾種軟中斷
                                      • sar命令發(fā)現(xiàn)是網(wǎng)絡(luò)小包問題
                                      • tcpdump找出網(wǎng)絡(luò)幀的類型和來源, 確定SYN FLOOD攻擊導(dǎo)致

                                        根據(jù)不同的性能指標(biāo)來找合適的工具:

                                        圖片來自: www.ctq6.cn

                                        在生產(chǎn)環(huán)境中往往開發(fā)者沒有權(quán)限安裝新的工具包,只能最大化利用好系統(tǒng)中已經(jīng)安裝好的工具. 因此要了解一些主流工具能夠提供哪些指標(biāo)分析.

                                        圖片來自: www.ctq6.cn

                                        先運(yùn)行幾個(gè)支持指標(biāo)較多的工具, 如top/vmstat/pidstat,根據(jù)它們的輸出可以得出是哪種類型的性能問題. 定位到進(jìn)程后再用strace/perf分析調(diào)用情況進(jìn)一步分析. 如果是軟中斷導(dǎo)致用/proc/softirqs

                                        圖片來自: www.ctq6.cn

                                        CPU優(yōu)化

                                        • 應(yīng)用程序優(yōu)化

                                          • 編譯器優(yōu)化: 編譯階段開啟優(yōu)化選項(xiàng), 如gcc -O2
                                          • 算法優(yōu)化
                                          • 異步處理: 避免程序因?yàn)榈却硞€(gè)資源而一直阻塞,提升程序的并發(fā)處理能力. (將輪詢替換為事件通知)
                                          • 多線程代替多進(jìn)程: 減少上下文切換成本
                                          • 善用緩存: 加快程序處理速度
                                          • 系統(tǒng)優(yōu)化

                                            • CPU綁定: 將進(jìn)程綁定要1個(gè)/多個(gè)CPU上,提高CPU緩存命中率,減少CPU調(diào)度帶來的上下文切換
                                            • CPU獨(dú)占: CPU親和性機(jī)制來分配進(jìn)程
                                            • 優(yōu)先級(jí)調(diào)整:使用nice適當(dāng)降低非核心應(yīng)用的優(yōu)先級(jí)
                                            • 為進(jìn)程設(shè)置資源顯示: cgroups設(shè)置使用上限,防止由某個(gè)應(yīng)用自身問題耗盡系統(tǒng)資源
                                            • NUMA優(yōu)化: CPU盡可能訪問本地內(nèi)存
                                            • 中斷負(fù)載均衡: irpbalance,將中斷處理過程自動(dòng)負(fù)載均衡到各個(gè)CPU上
                                            • TPS、QPS、系統(tǒng)吞吐量的區(qū)別和理解

                                              • QPS(TPS)

                                              • 并發(fā)數(shù)

                                              • 響應(yīng)時(shí)間

                                                QPS(TPS)=并發(fā)數(shù)/平均相應(yīng)時(shí)間

                                              • 用戶請(qǐng)求服務(wù)器

                                              • 服務(wù)器內(nèi)部處理

                                              • 服務(wù)器返回給客戶

                                                QPS類似TPS,但是對(duì)于一個(gè)頁(yè)面的訪問形成一個(gè)TPS,但是一次頁(yè)面請(qǐng)求可能包含多次對(duì)服務(wù)器的請(qǐng)求,可能計(jì)入多次QPS

                                              • QPS (Queries Per Second)每秒查詢率,一臺(tái)服務(wù)器每秒能夠響應(yīng)的查詢次數(shù).

                                              • TPS (Transactions Per Second)每秒事務(wù)數(shù),軟件測(cè)試的結(jié)果.

                                              • 系統(tǒng)吞吐量, 包括幾個(gè)重要參數(shù):

                                                3內(nèi)存

                                                Linux內(nèi)存是怎么工作的

                                                內(nèi)存映射

                                                大多數(shù)計(jì)算機(jī)用的主存都是動(dòng)態(tài)隨機(jī)訪問內(nèi)存(DRAM),只有內(nèi)核才可以直接訪問物理內(nèi)存。Linux內(nèi)核給每個(gè)進(jìn)程提供了一個(gè)獨(dú)立的虛擬地址空間,并且這個(gè)地址空間是連續(xù)的。這樣進(jìn)程就可以很方便的訪問內(nèi)存(虛擬內(nèi)存)。

                                                虛擬地址空間的內(nèi)部分為內(nèi)核空間和用戶空間兩部分,不同字長(zhǎng)的處理器地址空間的范圍不同。32位系統(tǒng)內(nèi)核空間占用1G,用戶空間占3G。64位系統(tǒng)內(nèi)核空間和用戶空間都是128T,分別占內(nèi)存空間的最高和最低處,中間部分為未定義。

                                                并不是所有的虛擬內(nèi)存都會(huì)分配物理內(nèi)存,只有實(shí)際使用的才會(huì)。分配后的物理內(nèi)存通過內(nèi)存映射管理。為了完成內(nèi)存映射,內(nèi)核為每個(gè)進(jìn)程都維護(hù)了一個(gè)頁(yè)表,記錄虛擬地址和物理地址的映射關(guān)系。頁(yè)表實(shí)際存儲(chǔ)在CPU的內(nèi)存管理單元MMU中,處理器可以直接通過硬件找出要訪問的內(nèi)存。

                                                當(dāng)進(jìn)程訪問的虛擬地址在頁(yè)表中查不到時(shí),系統(tǒng)會(huì)產(chǎn)生一個(gè)缺頁(yè)異常,進(jìn)入內(nèi)核空間分配物理內(nèi)存,更新進(jìn)程頁(yè)表,再返回用戶空間恢復(fù)進(jìn)程的運(yùn)行。

                                                MMU以頁(yè)為單位管理內(nèi)存,頁(yè)大小4KB。為了解決頁(yè)表項(xiàng)過多問題Linux提供了多級(jí)頁(yè)表HugePage的機(jī)制。

                                                虛擬內(nèi)存空間分布

                                                用戶空間內(nèi)存從低到高是五種不同的內(nèi)存段:

                                                • 只讀段 代碼和常量等
                                                • 數(shù)據(jù)段 全局變量等
                                                • 動(dòng)態(tài)分配的內(nèi)存,從低地址開始向上增長(zhǎng)
                                                • 文件映射 動(dòng)態(tài)庫(kù)、共享內(nèi)存等,從高地址開始向下增長(zhǎng)
                                                • 包括局部變量和函數(shù)調(diào)用的上下文等,棧的大小是固定的。一般8MB

                                                  內(nèi)存分配與回收

                                                  分配

                                                  malloc對(duì)應(yīng)到系統(tǒng)調(diào)用上有兩種實(shí)現(xiàn)方式:

                                                  • brk() 針對(duì)小塊內(nèi)存(<128K),通過移動(dòng)堆頂位置來分配。內(nèi)存釋放后不立即歸還內(nèi)存,而是被緩存起來。
                                                  • **mmap()**針對(duì)大塊內(nèi)存(>128K),直接用內(nèi)存映射來分配,即在文件映射段找一塊空閑內(nèi)存分配。

                                                    前者的緩存可以減少缺頁(yè)異常的發(fā)生,提高內(nèi)存訪問效率。但是由于內(nèi)存沒有歸還系統(tǒng),在內(nèi)存工作繁忙時(shí),頻繁的內(nèi)存分配/釋放會(huì)造成內(nèi)存碎片。

                                                    后者在釋放時(shí)直接歸還系統(tǒng),所以每次mmap都會(huì)發(fā)生缺頁(yè)異常。在內(nèi)存工作繁忙時(shí),頻繁內(nèi)存分配會(huì)導(dǎo)致大量缺頁(yè)異常,使內(nèi)核管理負(fù)擔(dān)增加。

                                                    上述兩種調(diào)用并沒有真正分配內(nèi)存,這些內(nèi)存只有在首次訪問時(shí),才通過缺頁(yè)異常進(jìn)入內(nèi)核中,由內(nèi)核來分配

                                                    回收

                                                    內(nèi)存緊張時(shí),系統(tǒng)通過以下方式來回收內(nèi)存:

                                                    • 回收緩存:LRU算法回收最近最少使用的內(nèi)存頁(yè)面;

                                                    • 回收不常訪問內(nèi)存:把不常用的內(nèi)存通過交換分區(qū)寫入磁盤

                                                    • 殺死進(jìn)程:OOM內(nèi)核保護(hù)機(jī)制 (進(jìn)程消耗內(nèi)存越大oom_score越大,占用CPU越多oom_score越小,可以通過/proc手動(dòng)調(diào)整oom_adj)

                                                      echo -16 > /proc/$(pidof XXX)/oom_adj

                                                      登錄后復(fù)制

                                                      如何查看內(nèi)存使用情況

                                                      free來查看整個(gè)系統(tǒng)的內(nèi)存使用情況

                                                      top/ps來查看某個(gè)進(jìn)程的內(nèi)存使用情況

                                                      • VIRT 進(jìn)程的虛擬內(nèi)存大小
                                                      • RES 常駐內(nèi)存的大小,即進(jìn)程實(shí)際使用的物理內(nèi)存大小,不包括swap和共享內(nèi)存
                                                      • SHR 共享內(nèi)存大小,與其他進(jìn)程共享的內(nèi)存,加載的動(dòng)態(tài)鏈接庫(kù)以及程序代碼段
                                                      • %MEM 進(jìn)程使用物理內(nèi)存占系統(tǒng)總內(nèi)存的百分比

                                                        怎樣理解內(nèi)存中的Buffer和Cache?

                                                        buffer是對(duì)磁盤數(shù)據(jù)的緩存,cache是對(duì)文件數(shù)據(jù)的緩存,它們既會(huì)用在讀請(qǐng)求也會(huì)用在寫請(qǐng)求中

                                                        如何利用系統(tǒng)緩存優(yōu)化程序的運(yùn)行效率

                                                        緩存命中率

                                                        緩存命中率是指直接通過緩存獲取數(shù)據(jù)的請(qǐng)求次數(shù),占所有請(qǐng)求次數(shù)的百分比。命中率越高說明緩存帶來的收益越高,應(yīng)用程序的性能也就越好。

                                                        安裝bcc包后可以通過cachestat和cachetop來監(jiān)測(cè)緩存的讀寫命中情況。

                                                        安裝pcstat后可以查看文件在內(nèi)存中的緩存大小以及緩存比例

                                                        #首先安裝Go
                                                        export GOPATH=~/go
                                                        export PATH=~/go/bin:$PATH
                                                        go get golang.org/x/sys/unix
                                                        go ge github.com/tobert/pcstat/pcstat

                                                        登錄后復(fù)制

                                                        dd緩存加速

                                                        dd if=/dev/sda1 of=file bs=1M count=512 #生產(chǎn)一個(gè)512MB的臨時(shí)文件
                                                        echo 3 > /proc/sys/vm/drop_caches #清理緩存
                                                        pcstat file #確定剛才生成文件不在系統(tǒng)緩存中,此時(shí)cached和percent都是0
                                                        cachetop 5
                                                        dd if=file of=/dev/null bs=1M #測(cè)試文件讀取速度
                                                        #此時(shí)文件讀取性能為30+MB/s,查看cachetop結(jié)果發(fā)現(xiàn)并不是所有的讀都落在磁盤上,讀緩存命中率只有50%。
                                                        dd if=file of=/dev/null bs=1M #重復(fù)上述讀文件測(cè)試
                                                        #此時(shí)文件讀取性能為4+GB/s,讀緩存命中率為100%
                                                        pcstat file #查看文件file的緩存情況,100%全部緩存

                                                        登錄后復(fù)制

                                                        O_DIRECT選項(xiàng)繞過系統(tǒng)緩存

                                                        cachetop 5
                                                        sudo docker run --privileged --name=app -itd feisky/app:io-direct
                                                        sudo docker logs app #確認(rèn)案例啟動(dòng)成功
                                                        #實(shí)驗(yàn)結(jié)果表明每讀32MB數(shù)據(jù)都要花0.9s,且cachetop輸出中顯示1024次緩存全部命中

                                                        登錄后復(fù)制

                                                        但是憑感覺可知如果緩存命中讀速度不應(yīng)如此慢,讀次數(shù)時(shí)1024,頁(yè)大小為4K,五秒的時(shí)間內(nèi)讀取了1024*4KB數(shù)據(jù),即每秒0.8MB,和結(jié)果中32MB相差較大。說明該案例沒有充分利用緩存,懷疑系統(tǒng)調(diào)用設(shè)置了直接I/O標(biāo)志繞過系統(tǒng)緩存。因此接下來觀察系統(tǒng)調(diào)用.

                                                        strace -p $(pgrep app)
                                                        #strace 結(jié)果可以看到openat打開磁盤分區(qū)/dev/sdb1,傳入?yún)?shù)為O_RDONLY|O_DIRECT

                                                        登錄后復(fù)制

                                                        這就解釋了為什么讀32MB數(shù)據(jù)那么慢,直接從磁盤讀寫肯定遠(yuǎn)遠(yuǎn)慢于緩存。找出問題后我們?cè)倏窗咐脑创a發(fā)現(xiàn)flags中指定了直接IO標(biāo)志。刪除該選項(xiàng)后重跑,驗(yàn)證性能變化。

                                                        內(nèi)存泄漏,如何定位和處理?

                                                        對(duì)應(yīng)用程序來說,動(dòng)態(tài)內(nèi)存的分配和回收是核心又復(fù)雜的一個(gè)邏輯功能模塊。管理內(nèi)存的過程中會(huì)發(fā)生各種各樣的“事故”:

                                                        • 沒正確回收分配的內(nèi)存,導(dǎo)致了泄漏
                                                        • 訪問的是已分配內(nèi)存邊界外的地址,導(dǎo)致程序異常退出

                                                          內(nèi)存的分配與回收

                                                          虛擬內(nèi)存分布從低到高分別是只讀段,數(shù)據(jù)段,堆,內(nèi)存映射段,棧五部分。其中會(huì)導(dǎo)致內(nèi)存泄漏的是:

                                                          • 堆:由應(yīng)用程序自己來分配和管理,除非程序退出這些堆內(nèi)存不會(huì)被系統(tǒng)自動(dòng)釋放。
                                                          • 內(nèi)存映射段:包括動(dòng)態(tài)鏈接庫(kù)和共享內(nèi)存,其中 共享內(nèi)存由程序自動(dòng)分配和管理

                                                            內(nèi)存泄漏的危害比較大,這些忘記釋放的內(nèi)存,不僅應(yīng)用程序自己不能訪問,系統(tǒng)也不能把它們?cè)俅畏峙浣o其他應(yīng)用。 內(nèi)存泄漏不斷累積甚至?xí)谋M系統(tǒng)內(nèi)存.

                                                            如何檢測(cè)內(nèi)存泄漏

                                                            預(yù)先安裝systat,docker,bcc

                                                            sudo docker run --name=app -itd feisky/app:mem-leak
                                                            sudo docker logs app
                                                            vmstat 3

                                                            登錄后復(fù)制

                                                            可以看到free在不斷下降,buffer和cache基本保持不變。說明系統(tǒng)的內(nèi)存一致在升高。但并不能說明存在內(nèi)存泄漏。此時(shí)可以通過memleak工具來跟蹤系統(tǒng)或進(jìn)程的內(nèi)存分配/釋放請(qǐng)求。另外,搜索公眾號(hào)Linux就該這樣學(xué)后臺(tái)回復(fù)“git書籍”,獲取一份驚喜禮包。

                                                            /usr/share/bcc/tools/memleak -a -p $(pidof app)

                                                            登錄后復(fù)制

                                                            從memleak輸出可以看到,應(yīng)用在不停地分配內(nèi)存,并且這些分配的地址并沒有被回收。通過調(diào)用??吹绞莊ibonacci函數(shù)分配的內(nèi)存沒有釋放。定位到源碼后查看源碼來修復(fù)增加內(nèi)存釋放函數(shù)即可.

                                                            為什么系統(tǒng)的Swap變高

                                                            系統(tǒng)內(nèi)存資源緊張時(shí)通過內(nèi)存回收和OOM殺死進(jìn)程來解決。其中可回收內(nèi)存包括:

                                                            • 緩存/緩沖區(qū),屬于可回收資源,在文件管理中通常叫做文件頁(yè)
                                                              • 在應(yīng)用程序中通過fsync將臟頁(yè)同步到磁盤
                                                              • 交給系統(tǒng),內(nèi)核線程pdflush負(fù)責(zé)這些臟頁(yè)的刷新
                                                              • 被應(yīng)用程序修改過暫時(shí)沒寫入磁盤的數(shù)據(jù)(臟頁(yè)),要先寫入磁盤然后才能內(nèi)存釋放
                                                              • 內(nèi)存映射獲取的文件映射頁(yè),也可以被釋放掉,下次訪問時(shí)從文件重新讀取

                                                                對(duì)于程序自動(dòng)分配的堆內(nèi)存,也就是我們?cè)趦?nèi)存管理中的匿名頁(yè),雖然這些內(nèi)存不能直接釋放,但是Linux提供了Swap機(jī)制將不常訪問的內(nèi)存寫入到磁盤來釋放內(nèi)存,再次訪問時(shí)從磁盤讀取到內(nèi)存即可。

                                                                Swap原理

                                                                Swap本質(zhì)就是把一塊磁盤空間或者一個(gè)本地文件當(dāng)作內(nèi)存來使用,包括換入和換出兩個(gè)過程:

                                                                • 換出:將進(jìn)程暫時(shí)不用的內(nèi)存數(shù)據(jù)存儲(chǔ)到磁盤中,并釋放這些內(nèi)存
                                                                • 換入:進(jìn)程再次訪問內(nèi)存時(shí),將它們從磁盤讀到內(nèi)存中

                                                                  Linux如何衡量?jī)?nèi)存資源是否緊張?

                                                                  • 直接內(nèi)存回收 新的大塊內(nèi)存分配請(qǐng)求,但剩余內(nèi)存不足。此時(shí)系統(tǒng)會(huì)回收一部分內(nèi)存;

                                                                  • kswapd0 內(nèi)核線程定期回收內(nèi)存。為了衡量?jī)?nèi)存使用情況,定義了pages_min,pages_low,pages_high三個(gè)閾值,并根據(jù)其來進(jìn)行內(nèi)存的回收操作。

                                                                    • 剩余內(nèi)存 < pages_min,進(jìn)程可用內(nèi)存耗盡了,只有內(nèi)核才可以分配內(nèi)存

                                                                    • pages_min < 剩余內(nèi)存 < pages_low,內(nèi)存壓力較大,kswapd0執(zhí)行內(nèi)存回收,直到剩余內(nèi)存 > pages_high

                                                                    • pages_low < 剩余內(nèi)存 < pages_high,內(nèi)存有一定壓力,但可以滿足新內(nèi)存請(qǐng)求

                                                                    • 剩余內(nèi)存 > pages_high,說明剩余內(nèi)存較多,無(wú)內(nèi)存壓力

                                                                      pages_low = pages_min 5 / 4 pages_high = pages_min 3 / 2

                                                                      NUMA 與 SWAP

                                                                      很多情況下系統(tǒng)剩余內(nèi)存較多,但SWAP依舊升高,這是由于處理器的NUMA架構(gòu)。

                                                                      在NUMA架構(gòu)下多個(gè)處理器劃分到不同的Node,每個(gè)Node都擁有自己的本地內(nèi)存空間。在分析內(nèi)存的使用時(shí)應(yīng)該針對(duì)每個(gè)Node單獨(dú)分析

                                                                      numactl --hardware #查看處理器在Node的分布情況,以及每個(gè)Node的內(nèi)存使用情況

                                                                      登錄后復(fù)制

                                                                      內(nèi)存三個(gè)閾值可以通過/proc/zoneinfo來查看,該文件中還包括活躍和非活躍的匿名頁(yè)/文件頁(yè)數(shù)。

                                                                      當(dāng)某個(gè)Node內(nèi)存不足時(shí),系統(tǒng)可以從其他Node尋找空閑資源,也可以從本地內(nèi)存中回收內(nèi)存。通過/proc/sys/vm/zone_raclaim_mode來調(diào)整。

                                                                      • 0表示既可以從其他Node尋找空閑資源,也可以從本地回收內(nèi)存
                                                                      • 1,2,4表示只回收本地內(nèi)存,2表示可以會(huì)回臟數(shù)據(jù)回收內(nèi)存,4表示可以用Swap方式回收內(nèi)存。

                                                                        swappiness

                                                                        在實(shí)際回收過程中Linux根據(jù)/proc/sys/vm/swapiness選項(xiàng)來調(diào)整使用Swap的積極程度,從0-100,數(shù)值越大越積極使用Swap,即更傾向于回收匿名頁(yè);數(shù)值越小越消極使用Swap,即更傾向于回收文件頁(yè)。

                                                                        注意:這只是調(diào)整Swap積極程度的權(quán)重,即使設(shè)置為0,當(dāng)剩余內(nèi)存+文件頁(yè)小于頁(yè)高閾值時(shí),還是會(huì)發(fā)生Swap。

                                                                        Swap升高時(shí)如何定位分析

                                                                        free #首先通過free查看swap使用情況,若swap=0表示未配置Swap
                                                                        #先創(chuàng)建并開啟swap
                                                                        fallocate -l 8G /mnt/swapfile
                                                                        chmod 600 /mnt/swapfile
                                                                        mkswap /mnt/swapfile
                                                                        swapon /mnt/swapfile
                                                                        
                                                                        free #再次執(zhí)行free確保Swap配置成功
                                                                        
                                                                        dd if=/dev/sda1 of=/dev/null bs=1G count=2048 #模擬大文件讀取
                                                                        sar -r -S 1  #查看內(nèi)存各個(gè)指標(biāo)變化 -r內(nèi)存 -S swap
                                                                        #根據(jù)結(jié)果可以看出,%memused在不斷增長(zhǎng),剩余內(nèi)存kbmemfress不斷減少,緩沖區(qū)kbbuffers不斷增大,由此可知剩余內(nèi)存不斷分配給了緩沖區(qū)
                                                                        #一段時(shí)間之后,剩余內(nèi)存很小,而緩沖區(qū)占用了大部分內(nèi)存。此時(shí)Swap使用之間增大,緩沖區(qū)和剩余內(nèi)存只在小范圍波動(dòng)
                                                                        
                                                                        停下sar命令
                                                                        cachetop5 #觀察緩存
                                                                        #可以看到dd進(jìn)程讀寫只有50%的命中率,未命中數(shù)為4w+頁(yè),說明正式dd進(jìn)程導(dǎo)致緩沖區(qū)使用升高
                                                                        watch -d grep -A 15 ‘Normal’ /proc/zoneinfo #觀察內(nèi)存指標(biāo)變化
                                                                        #發(fā)現(xiàn)升級(jí)內(nèi)存在一個(gè)小范圍不停的波動(dòng),低于頁(yè)低閾值時(shí)會(huì)突然增大到一個(gè)大于頁(yè)高閾值的值

                                                                        登錄后復(fù)制

                                                                        說明剩余內(nèi)存和緩沖區(qū)的波動(dòng)變化正是由于內(nèi)存回收和緩存再次分配的循環(huán)往復(fù)。有時(shí)候Swap用的多,有時(shí)候緩沖區(qū)波動(dòng)更多。此時(shí)查看swappiness值為60,是一個(gè)相對(duì)中和的配置,系統(tǒng)會(huì)根據(jù)實(shí)際運(yùn)行情況來選去合適的回收類型.

                                                                        如何“快準(zhǔn)狠”找到系統(tǒng)內(nèi)存存在的問題

                                                                        內(nèi)存性能指標(biāo)

                                                                        系統(tǒng)內(nèi)存指標(biāo)

                                                                        • 已用內(nèi)存/剩余內(nèi)存
                                                                        • 共享內(nèi)存 (tmpfs實(shí)現(xiàn))
                                                                        • 可用內(nèi)存:包括剩余內(nèi)存和可回收內(nèi)存
                                                                        • 緩存:磁盤讀取文件的頁(yè)緩存,slab分配器中的可回收部分
                                                                        • 緩沖區(qū):原始磁盤塊的臨時(shí)存儲(chǔ),緩存將要寫入磁盤的數(shù)據(jù)

                                                                          進(jìn)程內(nèi)存指標(biāo)

                                                                          • 虛擬內(nèi)存:5大部分
                                                                          • 常駐內(nèi)存:進(jìn)程實(shí)際使用的物理內(nèi)存,不包括Swap和共享內(nèi)存
                                                                          • 共享內(nèi)存:與其他進(jìn)程共享的內(nèi)存,以及動(dòng)態(tài)鏈接庫(kù)和程序的代碼段
                                                                          • Swap內(nèi)存:通過Swap換出到磁盤的內(nèi)存。關(guān)注Linux中文社區(qū)

                                                                            缺頁(yè)異常

                                                                            • 可以直接從物理內(nèi)存中分配,次缺頁(yè)異常
                                                                            • 需要磁盤IO介入(如Swap),主缺頁(yè)異常。此時(shí)內(nèi)存訪問會(huì)慢很多

                                                                              內(nèi)存性能工具

                                                                              根據(jù)不同的性能指標(biāo)來找合適的工具:

                                                                              圖片來自: www.ctq6.cn

                                                                              內(nèi)存分析工具包含的性能指標(biāo):

                                                                              圖片來自: www.ctq6.cn

                                                                              如何迅速分析內(nèi)存的性能瓶頸

                                                                              通常先運(yùn)行幾個(gè)覆蓋面比較大的性能工具,如free,top,vmstat,pidstat等

                                                                              • 先用free和top查看系統(tǒng)整體內(nèi)存使用情況
                                                                              • 再用vmstat和pidstat,查看一段時(shí)間的趨勢(shì),從而判斷內(nèi)存問題的類型
                                                                              • 最后進(jìn)行詳細(xì)分析,比如內(nèi)存分配分析,緩存/緩沖區(qū)分析,具體進(jìn)程的內(nèi)存使用分析等

                                                                                常見的優(yōu)化思路:

                                                                                • 最好禁止Swap,若必須開啟則盡量降低swappiness的值
                                                                                • 減少內(nèi)存的動(dòng)態(tài)分配,如可以用內(nèi)存池,HugePage等
                                                                                • 盡量使用緩存和緩沖區(qū)來訪問數(shù)據(jù)。如用堆棧明確聲明內(nèi)存空間來存儲(chǔ)需要緩存的數(shù)據(jù),或者用Redis外部緩存組件來優(yōu)化數(shù)據(jù)的訪問
                                                                                • cgroups等方式來限制進(jìn)程的內(nèi)存使用情況,確保系統(tǒng)內(nèi)存不被異常進(jìn)程耗盡
                                                                                • /proc/pid/oom_adj調(diào)整核心應(yīng)用的oom_score,保證即使內(nèi)存緊張核心應(yīng)用也不會(huì)被OOM殺死
                                                                                  vmstat使用詳解

                                                                                  vmstat命令是最常見的Linux/Unix監(jiān)控工具,可以展現(xiàn)給定時(shí)間間隔的服務(wù)器的狀態(tài)值,包括服務(wù)器的CPU使用率,內(nèi)存使用,虛擬內(nèi)存交換情況,IO讀寫情況。可以看到整個(gè)機(jī)器的CPU,內(nèi)存,IO的使用情況,而不是單單看到各個(gè)進(jìn)程的CPU使用率和內(nèi)存使用率(使用場(chǎng)景不一樣)。

                                                                                  vmstat 2
                                                                                  procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
                                                                                   r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
                                                                                   1  0      0 1379064 282244 11537528    0    0     3   104    0    0  3  0 97  0  0
                                                                                   0  0      0 1372716 282244 11537544    0    0     0    24 4893 8947  1  0 98  0  0
                                                                                   0  0      0 1373404 282248 11537544    0    0     0    96 5105 9278  2  0 98  0  0
                                                                                   0  0      0 1374168 282248 11537556    0    0     0     0 5001 9208  1  0 99  0  0
                                                                                   0  0      0 1376948 282248 11537564    0    0     0    80 5176 9388  2  0 98  0  0
                                                                                   0  0      0 1379356 282256 11537580    0    0     0   202 5474 9519  2  0 98  0  0
                                                                                   1  0      0 1368376 282256 11543696    0    0     0     0 5894 8940 12  0 88  0  0
                                                                                   1  0      0 1371936 282256 11539240    0    0     0 10554 6176 9481 14  1 85  1  0
                                                                                   1  0      0 1366184 282260 11542292    0    0     0  7456 6102 9983  7  1 91  0  0
                                                                                   1  0      0 1353040 282260 11556176    0    0     0 16924 7233 9578 18  1 80  1  0
                                                                                   0  0      0 1359432 282260 11549124    0    0     0 12576 5495 9271  7  0 92  1  0
                                                                                   0  0      0 1361744 282264 11549132    0    0     0    58 8606 15079  4  2 95  0  0
                                                                                   1  0      0 1367120 282264 11549140    0    0     0     2 5716 9205  8  0 92  0  0
                                                                                   0  0      0 1346580 282264 11562644    0    0     0    70 6416 9944 12  0 88  0  0
                                                                                   0  0      0 1359164 282264 11550108    0    0     0  2922 4941 8969  3  0 97  0  0
                                                                                   1  0      0 1353992 282264 11557044    0    0     0     0 6023 8917 15  0 84  0  0
                                                                                  
                                                                                  # 結(jié)果說明
                                                                                  - r 表示運(yùn)行隊(duì)列(就是說多少個(gè)進(jìn)程真的分配到CPU),我測(cè)試的服務(wù)器目前CPU比較空閑,沒什么程序在跑,當(dāng)這個(gè)值超過了CPU數(shù)目,就會(huì)出現(xiàn)CPU瓶頸了。這個(gè)也和top的負(fù)載有關(guān)系,一般負(fù)載超過了3就比較高,超過了5就高,超過了10就不正常了,服務(wù)器的狀態(tài)很危險(xiǎn)。top的負(fù)載類似每秒的運(yùn)行隊(duì)列。如果運(yùn)行隊(duì)列過大,表示你的CPU很繁忙,一般會(huì)造成CPU使用率很高。
                                                                                  
                                                                                  - b 表示阻塞的進(jìn)程,這個(gè)不多說,進(jìn)程阻塞,大家懂的。
                                                                                  
                                                                                  - swpd 虛擬內(nèi)存已使用的大小,如果大于0,表示你的機(jī)器物理內(nèi)存不足了,如果不是程序內(nèi)存泄露的原因,那么你該升級(jí)內(nèi)存了或者把耗內(nèi)存的任務(wù)遷移到其他機(jī)器。
                                                                                  
                                                                                  - free   空閑的物理內(nèi)存的大小,我的機(jī)器內(nèi)存總共8G,剩余3415M。
                                                                                  
                                                                                  - buff   Linux/Unix系統(tǒng)是用來存儲(chǔ),目錄里面有什么內(nèi)容,權(quán)限等的緩存,我本機(jī)大概占用300多M
                                                                                  
                                                                                  - cache cache直接用來記憶我們打開的文件,給文件做緩沖,我本機(jī)大概占用300多M(這里是Linux/Unix的聰明之處,把空閑的物理內(nèi)存的一部分拿來做文件和目錄的緩存,是為了提高 程序執(zhí)行的性能,當(dāng)程序使用內(nèi)存時(shí),buffer/cached會(huì)很快地被使用。)
                                                                                  
                                                                                  - si  每秒從磁盤讀入虛擬內(nèi)存的大小,如果這個(gè)值大于0,表示物理內(nèi)存不夠用或者內(nèi)存泄露了,要查找耗內(nèi)存進(jìn)程解決掉。我的機(jī)器內(nèi)存充裕,一切正常。
                                                                                  
                                                                                  - so  每秒虛擬內(nèi)存寫入磁盤的大小,如果這個(gè)值大于0,同上。
                                                                                  
                                                                                  - bi  塊設(shè)備每秒接收的塊數(shù)量,這里的塊設(shè)備是指系統(tǒng)上所有的磁盤和其他塊設(shè)備,默認(rèn)塊大小是1024byte,我本機(jī)上沒什么IO操作,所以一直是0,但是我曾在處理拷貝大量數(shù)據(jù)(2-3T)的機(jī)器上看過可以達(dá)到140000/s,磁盤寫入速度差不多140M每秒
                                                                                  
                                                                                  - bo 塊設(shè)備每秒發(fā)送的塊數(shù)量,例如我們讀取文件,bo就要大于0。bi和bo一般都要接近0,不然就是IO過于頻繁,需要調(diào)整。
                                                                                  
                                                                                  - in 每秒CPU的中斷次數(shù),包括時(shí)間中斷
                                                                                  
                                                                                  - cs 每秒上下文切換次數(shù),例如我們調(diào)用系統(tǒng)函數(shù),就要進(jìn)行上下文切換,線程的切換,也要進(jìn)程上下文切換,這個(gè)值要越小越好,太大了,要考慮調(diào)低線程或者進(jìn)程的數(shù)目,例如在apache和nginx這種web服務(wù)器中,我們一般做性能測(cè)試時(shí)會(huì)進(jìn)行幾千并發(fā)甚至幾萬(wàn)并發(fā)的測(cè)試,選擇web服務(wù)器的進(jìn)程可以由進(jìn)程或者線程的峰值一直下調(diào),壓測(cè),直到cs到一個(gè)比較小的值,這個(gè)進(jìn)程和線程數(shù)就是比較合適的值了。系統(tǒng)調(diào)用也是,每次調(diào)用系統(tǒng)函數(shù),我們的代碼就會(huì)進(jìn)入內(nèi)核空間,導(dǎo)致上下文切換,這個(gè)是很耗資源,也要盡量避免頻繁調(diào)用系統(tǒng)函數(shù)。上下文切換次數(shù)過多表示你的CPU大部分浪費(fèi)在上下文切換,導(dǎo)致CPU干正經(jīng)事的時(shí)間少了,CPU沒有充分利用,是不可取的。
                                                                                  
                                                                                  - us 用戶CPU時(shí)間,我曾經(jīng)在一個(gè)做加密解密很頻繁的服務(wù)器上,可以看到us接近100,r運(yùn)行隊(duì)列達(dá)到80(機(jī)器在做壓力測(cè)試,性能表現(xiàn)不佳)。
                                                                                  
                                                                                  - sy 系統(tǒng)CPU時(shí)間,如果太高,表示系統(tǒng)調(diào)用時(shí)間長(zhǎng),例如是IO操作頻繁。
                                                                                  
                                                                                  - id 空閑CPU時(shí)間,一般來說,id + us + sy = 100,一般我認(rèn)為id是空閑CPU使用率,us是用戶CPU使用率,sy是系統(tǒng)CPU使用率。
                                                                                  
                                                                                  - wt 等待IO CPU時(shí)間

                                                                                  登錄后復(fù)制

                                                                                  pidstat 使用詳解

                                                                                  pidstat主要用于監(jiān)控全部或指定進(jìn)程占用系統(tǒng)資源的情況,如CPU,內(nèi)存、設(shè)備IO、任務(wù)切換、線程等。

                                                                                  使用方法:

                                                                                  • pidstat –d interval times 統(tǒng)計(jì)各個(gè)進(jìn)程的IO使用情況
                                                                                  • pidstat –u interval times 統(tǒng)計(jì)各個(gè)進(jìn)程的CPU統(tǒng)計(jì)信息
                                                                                  • pidstat –r interval times 統(tǒng)計(jì)各個(gè)進(jìn)程的內(nèi)存使用信息
                                                                                  • pidstat -w interval times 統(tǒng)計(jì)各個(gè)進(jìn)程的上下文切換
                                                                                  • p PID 指定PID

                                                                                    1、統(tǒng)計(jì)IO使用情況

                                                                                    pidstat -d 1 10
                                                                                    
                                                                                    03:02:02 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
                                                                                    03:02:03 PM     0       816      0.00    918.81      0.00  jbd2/vda1-8
                                                                                    03:02:03 PM     0      1007      0.00      3.96      0.00  AliYunDun
                                                                                    03:02:03 PM   997      7326      0.00   1904.95    918.81  java
                                                                                    03:02:03 PM   997      8539      0.00      3.96      0.00  java
                                                                                    03:02:03 PM     0     16066      0.00     35.64      0.00  cmagent
                                                                                    
                                                                                    03:02:03 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
                                                                                    03:02:04 PM     0       816      0.00   1924.00      0.00  jbd2/vda1-8
                                                                                    03:02:04 PM   997      7326      0.00  11156.00   1888.00  java
                                                                                    03:02:04 PM   997      8539      0.00      4.00      0.00  java

                                                                                    登錄后復(fù)制

                                                                                    • UID
                                                                                    • PID
                                                                                    • kB_rd/s: 每秒進(jìn)程從磁盤讀取的數(shù)據(jù)量 KB 單位 read from disk each second KB
                                                                                    • kB_wr/s: 每秒進(jìn)程向磁盤寫的數(shù)據(jù)量 KB 單位 write to disk each second KB
                                                                                    • kB_ccwr/s: 每秒進(jìn)程向磁盤寫入,但是被取消的數(shù)據(jù)量,This may occur when the task truncates some dirty pagecache.
                                                                                    • iodelay: Block I/O delay, measured in clock ticks
                                                                                    • Command: 進(jìn)程名 task name

                                                                                      2、統(tǒng)計(jì)CPU使用情況

                                                                                      # 統(tǒng)計(jì)CPU
                                                                                      pidstat -u 1 10
                                                                                      03:03:33 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
                                                                                      03:03:34 PM     0      2321    3.96    0.00    0.00    3.96     0  ansible
                                                                                      03:03:34 PM     0      7110    0.00    0.99    0.00    0.99     4  pidstat
                                                                                      03:03:34 PM   997      8539    0.99    0.00    0.00    0.99     5  java
                                                                                      03:03:34 PM   984     15517    0.99    0.00    0.00    0.99     5  java
                                                                                      03:03:34 PM     0     24406    0.99    0.00    0.00    0.99     5  java
                                                                                      03:03:34 PM     0     32158    3.96    0.00    0.00    3.96     2  ansible

                                                                                      登錄后復(fù)制

                                                                                      • UID
                                                                                      • PID
                                                                                      • %usr: 進(jìn)程在用戶空間占用 cpu 的百分比
                                                                                      • %system: 進(jìn)程在內(nèi)核空間占用 CPU 百分比
                                                                                      • %guest: 進(jìn)程在虛擬機(jī)占用 CPU 百分比
                                                                                      • %wait: 進(jìn)程等待運(yùn)行的百分比
                                                                                      • %CPU: 進(jìn)程占用 CPU 百分比
                                                                                      • CPU: 處理進(jìn)程的 CPU 編號(hào)
                                                                                      • Command: 進(jìn)程名

                                                                                        3、統(tǒng)計(jì)內(nèi)存使用情況

                                                                                        # 統(tǒng)計(jì)內(nèi)存
                                                                                        pidstat -r 1 10
                                                                                        Average:      UID       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
                                                                                        Average:        0         1      0.20      0.00  191256   3064   0.01  systemd
                                                                                        Average:        0      1007      1.30      0.00  143256  22720   0.07  AliYunDun
                                                                                        Average:        0      6642      0.10      0.00 6301904 107680   0.33  java
                                                                                        Average:      997      7326     10.89      0.00 13468904 8395848  26.04  java
                                                                                        Average:        0      7795    348.15      0.00  108376   1233   0.00  pidstat
                                                                                        Average:      997      8539      0.50      0.00 8242256 2062228   6.40  java
                                                                                        Average:      987      9518      0.20      0.00 6300944 1242924   3.85  java
                                                                                        Average:        0     10280      3.70      0.00  807372   8344   0.03  aliyun-service
                                                                                        Average:      984     15517      0.40      0.00 6386464 1464572   4.54  java
                                                                                        Average:        0     16066    236.46      0.00 2678332  71020   0.22  cmagent
                                                                                        Average:      995     20955      0.30      0.00 6312520 1408040   4.37  java
                                                                                        Average:      995     20956      0.20      0.00 6093764 1505028   4.67  java
                                                                                        Average:        0     23936      0.10      0.00 5302416 110804   0.34  java
                                                                                        Average:        0     24406      0.70      0.00 10211672 2361304   7.32  java
                                                                                        Average:        0     26870      1.40      0.00 1470212  36084   0.11  promtail

                                                                                        登錄后復(fù)制

                                                                                        • UID
                                                                                        • PID
                                                                                        • Minflt/s : 每秒次缺頁(yè)錯(cuò)誤次數(shù) (minor page faults),虛擬內(nèi)存地址映射成物理內(nèi)存地址產(chǎn)生的 page fault 次數(shù)
                                                                                        • Majflt/s : 每秒主缺頁(yè)錯(cuò)誤次數(shù) (major page faults), 虛擬內(nèi)存地址映射成物理內(nèi)存地址時(shí),相應(yīng) page 在 swap 中
                                                                                        • VSZ virtual memory usage : 該進(jìn)程使用的虛擬內(nèi)存 KB 單位
                                                                                        • RSS : 該進(jìn)程使用的物理內(nèi)存 KB 單位
                                                                                        • %MEM : 內(nèi)存使用率
                                                                                        • Command : 該進(jìn)程的命令 task name

                                                                                          4、查看具體進(jìn)程使用情況

                                                                                          pidstat -T ALL -r -p 20955 1 10
                                                                                          03:12:16 PM   UID       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
                                                                                          03:12:17 PM   995     20955      0.00      0.00 6312520 1408040   4.37  java
                                                                                          
                                                                                          03:12:16 PM   UID       PID minflt-nr majflt-nr  Command
                                                                                          03:12:17 PM   995     20955         0         0  java

                                                                                          登錄后復(fù)制

                                                                                          以上就是Linux 性能全方位調(diào)優(yōu)經(jīng)驗(yàn)總結(jié)的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注www.92cms.cn其它相關(guān)文章!

分享到:
標(biāo)簽:Linux 性能 經(jīng)驗(yàn)
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定