日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何回答性能优化的问题,才能打动阿里面试官?

發(fā)布時(shí)間:2024/8/23 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何回答性能优化的问题,才能打动阿里面试官? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


阿里妹導(dǎo)讀:日常工作中,我們多少都會(huì)遇到應(yīng)用的性能問(wèn)題。在阿里面試中,性能優(yōu)化也是常被問(wèn)到的題目,用來(lái)考察是否有實(shí)際的線上問(wèn)題處理經(jīng)驗(yàn)。面對(duì)這類問(wèn)題,阿里工程師齊光給出了詳細(xì)流程。來(lái)阿里面試前,先看看這篇文章哦。

性能問(wèn)題和Bug不同,后者的分析和解決思路更清晰,很多時(shí)候從應(yīng)用日志(文中的應(yīng)用指分布式服務(wù)下的單個(gè)節(jié)點(diǎn))即可直接找到問(wèn)題根源,而性能問(wèn)題,其排查思路更為復(fù)雜一些。

對(duì)應(yīng)用進(jìn)行性能優(yōu)化,是一個(gè)系統(tǒng)性的工程,對(duì)工程師的技術(shù)廣度和技術(shù)深度都有所要求。一個(gè)簡(jiǎn)單的應(yīng)用,它不僅包含了應(yīng)用代碼本身,還和容器(虛擬機(jī))、操作系統(tǒng)、存儲(chǔ)、網(wǎng)絡(luò)、文件系統(tǒng)等緊密相關(guān),線上應(yīng)用一旦出現(xiàn)了性能問(wèn)題,需要我們從多方面去考慮。

與此同時(shí),除了一些低級(jí)的代碼邏輯引發(fā)的性能問(wèn)題外,很多性能問(wèn)題隱藏的較深,排查起來(lái)會(huì)比較困難,需要我們對(duì)應(yīng)用的各個(gè)子模塊、應(yīng)用所使用的框架和組件的原理有所了解,同時(shí)掌握一定的性能優(yōu)化工具和經(jīng)驗(yàn)。

本文總結(jié)了我們?cè)谶M(jìn)行性能優(yōu)化時(shí)常用的一些工具及技巧,目的是希望通過(guò)一個(gè)全面的視角,去感知性能優(yōu)化的整體脈絡(luò)。本文主要分為下面三個(gè)部分:

  • 第一部分會(huì)介紹性能優(yōu)化的一些背景知識(shí)。
  • 第二部分會(huì)介紹性能優(yōu)化的通用流程以及常見(jiàn)的一些誤區(qū)。
  • 第三部分會(huì)從系統(tǒng)層和業(yè)務(wù)層的角度,介紹高效的性能問(wèn)題定位工具和高頻性能瓶頸點(diǎn)分布。
  • 本文中提到的線程、堆、垃圾回收等名詞,如無(wú)特別說(shuō)明,指的是 Java 應(yīng)用中的相關(guān)概念。

    1.性能優(yōu)化的背景

    前面提到過(guò),應(yīng)用出現(xiàn)性能問(wèn)題和應(yīng)用存在缺陷是不一樣的,后者大多數(shù)是由于代碼的質(zhì)量問(wèn)題導(dǎo)致,會(huì)導(dǎo)致應(yīng)用功能性的缺失或出現(xiàn)風(fēng)險(xiǎn),一經(jīng)發(fā)現(xiàn),會(huì)被及時(shí)修復(fù)。而性能問(wèn)題,可能是由多方面的因素共同作用的結(jié)果:代碼質(zhì)量一般、業(yè)務(wù)發(fā)展太快、應(yīng)用架構(gòu)設(shè)計(jì)不合理等,這些問(wèn)題處理起來(lái)一般耗時(shí)較長(zhǎng)、分析鏈路復(fù)雜,大家都不愿意干,因此可能會(huì)被一些臨時(shí)性的補(bǔ)救手段所掩蓋,如:系統(tǒng)水位高或者單機(jī)的線程池隊(duì)列爆炸,那就集群擴(kuò)容增加機(jī)器;內(nèi)存占用高/高峰時(shí)段 OOM,那就重啟分分鐘解決......

    臨時(shí)性的補(bǔ)救措施只是在給應(yīng)用埋雷,同時(shí)也只能解決部分問(wèn)題。譬如,在很多場(chǎng)景下,加機(jī)器也并不能解決應(yīng)用的性能問(wèn)題,如對(duì)時(shí)延比較敏感的一些應(yīng)用必須把單機(jī)的性能優(yōu)化到極致,與此同時(shí),加機(jī)器這種方式也造成了資源的浪費(fèi),長(zhǎng)期來(lái)看是得不償失的。對(duì)應(yīng)用進(jìn)行合理的性能優(yōu)化,可在應(yīng)用穩(wěn)定性、成本核算獲得很大的收益。

    上面我們闡述了進(jìn)行性能優(yōu)化的必要性。假設(shè)現(xiàn)在我們的應(yīng)用已經(jīng)有了性能問(wèn)題(eg. CPU 水位比較高),準(zhǔn)備開(kāi)始進(jìn)行優(yōu)化工作了,在這個(gè)過(guò)程中,潛在的痛點(diǎn)會(huì)有哪些呢?下面列出一些較為常見(jiàn)的:

  • 對(duì)性能優(yōu)化的流程不是很清晰。初步定為一個(gè)疑似瓶頸點(diǎn)后,就興高采烈地吭哧吭哧開(kāi)始干,最終解決的問(wèn)題其實(shí)只是一個(gè)淺層次的性能瓶頸,真實(shí)的問(wèn)題的根源并未觸達(dá);
  • 對(duì)性能瓶頸點(diǎn)的分析思路不是很清晰。CPU、網(wǎng)絡(luò)、內(nèi)存......這么多的性能指標(biāo),我到底該關(guān)注什么,應(yīng)該從哪一塊兒開(kāi)始入手?
  • 對(duì)性能優(yōu)化的工具不了解。遇到問(wèn)題后,不清楚該用哪個(gè)工具,不知道通過(guò)工具得到的指標(biāo)代表什么。
  • 2.性能優(yōu)化的流程

    在性能優(yōu)化這個(gè)領(lǐng)域,并沒(méi)有一個(gè)嚴(yán)格的流程定義,但是對(duì)于絕大多數(shù)的優(yōu)化場(chǎng)景,我們可以將其過(guò)程抽象為下面四個(gè)步驟。

  • 準(zhǔn)備階段:主要工作是是通過(guò)性能測(cè)試,了解應(yīng)用的概況、瓶頸的大概方向,明確優(yōu)化目標(biāo);
  • 分析階段:通過(guò)各種工具或手段,初步定位性能瓶頸點(diǎn);
  • 調(diào)優(yōu)階段:根據(jù)定位到的瓶頸點(diǎn),進(jìn)行應(yīng)用性能調(diào)優(yōu);
  • 測(cè)試階段:讓調(diào)優(yōu)過(guò)的應(yīng)用進(jìn)行性能測(cè)試,與準(zhǔn)備階段的各項(xiàng)指標(biāo)進(jìn)行對(duì)比,觀測(cè)其是否符合預(yù)期,如果瓶頸點(diǎn)沒(méi)有消除或者性能指標(biāo)不符合預(yù)期,則重復(fù)步驟2和3。
  • 下圖即為上述四個(gè)階段的簡(jiǎn)要流程。

    2.1 通用流程詳解

    在上述通用流程的四個(gè)步驟當(dāng)中,步驟2和3我們會(huì)在接下來(lái)兩個(gè)部分重點(diǎn)進(jìn)行介紹。首先我們來(lái)看一下,在準(zhǔn)備階段和測(cè)試階段,我們需要做一些什么。

    | 2.1.1 準(zhǔn)備階段

    準(zhǔn)備階段是非常關(guān)鍵的一步,不能省略。

    首先,需要對(duì)我們進(jìn)行調(diào)優(yōu)的對(duì)象進(jìn)行詳盡的了解,所謂知己知彼,百戰(zhàn)不殆。

  • 對(duì)性能問(wèn)題進(jìn)行粗略評(píng)估,過(guò)濾一些因?yàn)榈图?jí)的業(yè)務(wù)邏輯導(dǎo)致的性能問(wèn)題。譬如,線上應(yīng)用日志級(jí)別不合理,可能會(huì)在大流量時(shí)導(dǎo)致 CPU 和磁盤的負(fù)載飆高,這種情況調(diào)整日志級(jí)別即可;
  • 了解應(yīng)用的的總體架構(gòu),比如應(yīng)用的外部依賴和核心接口有哪些,使用了哪些組件和框架,哪些接口、模塊的使用率較高,上下游的數(shù)據(jù)鏈路是怎么樣的等;
  • 了解應(yīng)用對(duì)應(yīng)的服務(wù)器信息,如服務(wù)器所在的集群信息、服務(wù)器的 CPU/內(nèi)存信息、安裝的 Linux 版本信息、服務(wù)器是容器還是虛擬機(jī)、所在宿主機(jī)混部后是否對(duì)當(dāng)前應(yīng)用有干擾等;
  • 其次,我們需要獲取基準(zhǔn)數(shù)據(jù),然后結(jié)合基準(zhǔn)數(shù)據(jù)和當(dāng)前的一些業(yè)務(wù)指標(biāo),確定此次性能優(yōu)化的最終目標(biāo)。

  • 使用基準(zhǔn)測(cè)試工具獲取系統(tǒng)細(xì)粒度指標(biāo)。可以使用若干 Linux 基準(zhǔn)測(cè)試工具(eg. jmeter、ab、loadrunnerwrk、wrk等),得到文件系統(tǒng)、磁盤 I/O、網(wǎng)絡(luò)等的性能報(bào)告。除此之外,類似 GC、Web 服務(wù)器、網(wǎng)卡流量等信息,如有必要也是需要了解記錄的;
  • 通過(guò)壓測(cè)工具或者壓測(cè)平臺(tái)(如果有的話),對(duì)應(yīng)用進(jìn)行壓力測(cè)試,獲取當(dāng)前應(yīng)用的宏觀業(yè)務(wù)指標(biāo),譬如:響應(yīng)時(shí)間、吞吐量、TPS、QPS、消費(fèi)速率(對(duì)于有 MQ 的應(yīng)用)等。壓力測(cè)試也可以省略,可以結(jié)合當(dāng)前的實(shí)際業(yè)務(wù)和過(guò)往的監(jiān)控?cái)?shù)據(jù),去統(tǒng)計(jì)當(dāng)前的一些核心業(yè)務(wù)指標(biāo),如午高峰的服務(wù) TPS。
  • | 2.1.2 測(cè)試階段

    進(jìn)入到這一階段,說(shuō)明我們已經(jīng)初步確定了應(yīng)用性能瓶頸的所在,而且已經(jīng)進(jìn)行初步的調(diào)優(yōu)了。檢測(cè)我們調(diào)優(yōu)是否有效的方式,就是在仿真的條件下,對(duì)應(yīng)用進(jìn)行壓力測(cè)試。注意:由于 Java 有 JIT(just-in-time compilation)過(guò)程,因此壓力測(cè)試時(shí)可能需要進(jìn)行前期預(yù)熱。

    如果壓力測(cè)試的結(jié)果符合了預(yù)期的調(diào)優(yōu)目標(biāo),或者與基準(zhǔn)數(shù)據(jù)相比,有很大的改善,則我們可以繼續(xù)通過(guò)工具定位下一個(gè)瓶頸點(diǎn),否則,則需要暫時(shí)排除這個(gè)瓶頸點(diǎn),繼續(xù)尋找下一個(gè)變量。

    2.2 注意事項(xiàng)

    在進(jìn)行性能優(yōu)化時(shí),了解下面這些注意事項(xiàng)可以讓我們少走一些彎路。

  • 性能瓶頸點(diǎn)通常呈現(xiàn) 2/8 分布,即80%的性能問(wèn)題通常是由20%的性能瓶頸點(diǎn)導(dǎo)致的,2/8 原則也意味著并不是所有的性能問(wèn)題都值得去優(yōu)化;
  • 性能優(yōu)化是一個(gè)漸進(jìn)、迭代的過(guò)程,需要逐步、動(dòng)態(tài)地進(jìn)行。記錄基準(zhǔn)后,每次改變一個(gè)變量,引入多個(gè)變量會(huì)給我們的觀測(cè)、優(yōu)化過(guò)程造成干擾;
  • 不要過(guò)度追求應(yīng)用的單機(jī)性能,如果單機(jī)表現(xiàn)良好,則應(yīng)該從系統(tǒng)架構(gòu)的角度去思考; 不要過(guò)度追求單一維度上的極致優(yōu)化,如過(guò)度追求 CPU 的性能而忽略了內(nèi)存方面的瓶頸;
  • 選擇合適的性能優(yōu)化工具,可以使得性能優(yōu)化取得事半功倍的效果;
  • 整個(gè)應(yīng)用的優(yōu)化,應(yīng)該與線上系統(tǒng)隔離,新的代碼上線應(yīng)該有降級(jí)方案。
  • 3.瓶頸點(diǎn)分析工具箱

    性能優(yōu)化其實(shí)就是找出應(yīng)用存在性能瓶頸點(diǎn),然后設(shè)法通過(guò)一些調(diào)優(yōu)手段去緩解。性能瓶頸點(diǎn)的定位是較困難的,快速、直接地定位到瓶頸點(diǎn),需要具備下面兩個(gè)條件:

  • 恰到好處的工具;
  • 一定的性能優(yōu)化經(jīng)驗(yàn)。
  • 工欲善其事,必先利其器,我們?cè)撊绾芜x擇合適的工具呢?不同的優(yōu)化場(chǎng)景下,又該選擇那些工具呢?

    首選,我們來(lái)看一下大名鼎鼎的「性能工具(Linux Performance Tools-full)圖」,想必很多工程師都知道,它出自系統(tǒng)性能專家 Brendan Gregg。該圖從 Linux 內(nèi)核的各個(gè)子系統(tǒng)出發(fā),列出了我們?cè)趯?duì)各個(gè)子系統(tǒng)進(jìn)行性能分析時(shí),可使用的工具,涵蓋了監(jiān)測(cè)、分析、調(diào)優(yōu)等性能優(yōu)化的方方面面。除了這張全景圖之外,Brendan Gregg 還單獨(dú)提供了基準(zhǔn)測(cè)試工具(Linux Performance Benchmark Tools)圖、性能監(jiān)測(cè)工具(Linux Performance Observability Tools)圖等,更詳細(xì)的內(nèi)容請(qǐng)參考 Brendan Gregg 的網(wǎng)站說(shuō)明。

    上面這張圖非常經(jīng)典,是我們做性能優(yōu)化時(shí)非常好的參考資料,但事實(shí)上,我們?cè)趯?shí)際運(yùn)用的時(shí)候,會(huì)發(fā)現(xiàn)可能它并不是最合適的,原因主要有下面兩點(diǎn):

    1)對(duì)分析經(jīng)驗(yàn)要求較高。上面這張圖其實(shí)是從 Linux 系統(tǒng)資源的角度去觀測(cè)性能指標(biāo)的,這要求我們對(duì) Linux 各個(gè)子系統(tǒng)的功能、原理要有所了解。舉例:遇到性能問(wèn)題了,我們不會(huì)拿每個(gè)子系統(tǒng)下的工具都去試一遍,大多數(shù)情況是:我們懷疑某個(gè)子系統(tǒng)有問(wèn)題,然后根據(jù)這張圖上列舉的工具,去觀測(cè)或者驗(yàn)證我們的猜想,這無(wú)疑拔高了對(duì)性能優(yōu)化經(jīng)驗(yàn)的要求;

    2)適用性和完整性不是很好。我們?cè)诜治鲂阅軉?wèn)題時(shí),從系統(tǒng)底層自底向上地分析是較低效的,大多數(shù)時(shí)候,從應(yīng)用層面去分析會(huì)更加有效。性能工具(Linux Performance Tools-full)圖只是從系統(tǒng)層一個(gè)角度給出了工具集,如果從應(yīng)用層開(kāi)始分析,我們可以使用哪些工具?哪些點(diǎn)是我們首先需要關(guān)注的?

    鑒于上面若干痛點(diǎn),下面給出了一張更為實(shí)用的「性能優(yōu)化工具圖譜」,該圖分別從系統(tǒng)層、應(yīng)用層(含組件層)的角度出發(fā),列舉了我們?cè)诜治鲂阅軉?wèn)題時(shí)首先需要關(guān)注的各項(xiàng)指標(biāo)(其中?標(biāo)注的是最需要關(guān)注的),這些點(diǎn)是最有可能出現(xiàn)性能瓶頸的地方。需要注意的是,一些低頻的指標(biāo)或工具,在圖中并沒(méi)有列出來(lái),如 CPU 中斷、索引節(jié)點(diǎn)使用、I/O事件跟蹤等,這些低頻點(diǎn)的排查思路較復(fù)雜,一般遇到的機(jī)會(huì)也不多,在這里我們聚焦最常見(jiàn)的一些就可以了。

    對(duì)比上面的性能工具(Linux Performance Tools-full)圖,下圖的優(yōu)勢(shì)在于:把具體的工具同性能指標(biāo)結(jié)合了起來(lái),同時(shí)從不同的層次去描述了性能瓶頸點(diǎn)的分布,實(shí)用性和可操作性更強(qiáng)一些。系統(tǒng)層的工具分為CPU、內(nèi)存、磁盤(含文件系統(tǒng))、網(wǎng)絡(luò)四個(gè)部分,工具集同性能工具(Linux Performance Tools-full)圖中的工具基本一致。組件層和應(yīng)用層中的工具構(gòu)成為:JDK 提供的一些工具 + Trace 工具 + dump 分析工具 + Profiling 工具等。

    這里就不具體介紹這些工具的具體用法了,我們可以使用 man 命令得到工具詳盡的使用說(shuō)明,除此之外,還有另外一個(gè)查詢命令手冊(cè)的方法:info。info 可以理解為 man 的詳細(xì)版本,如果 man 的輸出不太好理解,可以去參考 info 文檔,命令太多,記不住也沒(méi)必要記住。

    上面這張圖該如何使用?

    首先,雖然從系統(tǒng)、組件、應(yīng)用兩個(gè)三個(gè)角度去描述瓶頸點(diǎn)的分布,但在實(shí)際運(yùn)行時(shí),這三者往往是相輔相成、相互影響的。系統(tǒng)是為應(yīng)用提供了運(yùn)行時(shí)環(huán)境,性能問(wèn)題的本質(zhì)就是系統(tǒng)資源達(dá)到了使用的上限,反映在應(yīng)用層,就是應(yīng)用/組件的各項(xiàng)指標(biāo)開(kāi)始下降;而應(yīng)用/組件的不合理使用和設(shè)計(jì),也會(huì)加速系統(tǒng)資源的耗盡。因此,分析瓶頸點(diǎn)時(shí),需要我們結(jié)合從不同角度分析出的結(jié)果,抽出共性,得到最終的結(jié)論。

    其次,建議先從應(yīng)用層入手,分析圖中標(biāo)注的高頻指標(biāo),抓出最重要的、最可疑的、最有可能導(dǎo)致性能的點(diǎn),得到初步的結(jié)論后,再去系統(tǒng)層進(jìn)行驗(yàn)證。這樣做的好處是:很多性能瓶頸點(diǎn)體現(xiàn)在系統(tǒng)層,會(huì)是多變量呈現(xiàn)的,譬如,應(yīng)用層的垃圾回收(GC)指標(biāo)出現(xiàn)了異常,通過(guò) JDK 自帶的工具很容易觀測(cè)到,但是體現(xiàn)在系統(tǒng)層上,會(huì)發(fā)現(xiàn)系統(tǒng)當(dāng)前的 CPU 利用率、內(nèi)存指標(biāo)都不太正常,這就給我們的分析思路帶來(lái)了困擾。

    最后,如果瓶頸點(diǎn)在應(yīng)用層和系統(tǒng)層均呈現(xiàn)出多變量分布,建議此時(shí)使用 ZProfiler、JProfiler 等工具對(duì)應(yīng)用進(jìn)行 Profiling,獲取應(yīng)用的綜合性能信息(注:Profiling 指的是在應(yīng)用運(yùn)行時(shí),通過(guò)事件(Event-based)、統(tǒng)計(jì)抽樣(Sampling Statistical)或植入附加指令(Byte-Code instrumentation)等方法,收集應(yīng)用運(yùn)行時(shí)的信息,來(lái)研究應(yīng)用行為的動(dòng)態(tài)分析方法)。譬如,可以對(duì) CPU 進(jìn)行抽樣統(tǒng)計(jì),結(jié)合各種符號(hào)表信息,得到一段時(shí)間內(nèi)應(yīng)用內(nèi)的代碼熱點(diǎn)。

    下面介紹在不同的分析層次,我們需要關(guān)注的核心性能指標(biāo),同時(shí),也會(huì)介紹如何初步根據(jù)這些指標(biāo),判斷系統(tǒng)或應(yīng)用是否存在性能瓶頸點(diǎn),至于瓶頸點(diǎn)的確認(rèn)、瓶頸點(diǎn)的成因、調(diào)優(yōu)手段,將會(huì)在下一部分展開(kāi)。

    3.1 CPU&&線程

    和 CPU 相關(guān)的指標(biāo)主要有以下幾個(gè)。常用的工具有 top、 ps、uptime、 vmstat、 pidstat等。

  • CPU利用率(CPU Utilization)
  • CPU 平均負(fù)載(Load Average)
  • 上下文切換次數(shù)(Context Switch)
  • top - 12:20:57 up 25 days, 20:49, 2 users, load average: 0.93, 0.97, 0.79

    Tasks: 51 total, 1 running, 50 sleeping, 0 stopped, 0 zombie
    %Cpu(s): 1.6 us, 1.8 sy, 0.0 ni, 89.1 id, 0.1 wa, 0.0 hi, 0.1 si, 7.3 st
    KiB Mem : 8388608 total, 476436 free, 5903224 used, 2008948 buff/cache
    KiB Swap: 0 total, 0 free, 0 used. 0 avail Mem

    PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

    119680 admin 20 0 600908 72332 5768 S 2.3 0.9 52:32.61 obproxy
    65877 root 20 0 93528 4936 2328 S 1.3 0.1 449:03.61 alisentry_cli

    第一行顯示的內(nèi)容:當(dāng)前時(shí)間、系統(tǒng)運(yùn)行時(shí)間以及正在登錄用戶數(shù)。load average 后的三個(gè)數(shù)字,依次表示過(guò)去 1 分鐘、5 分鐘、15 分鐘的平均負(fù)載(Load Average)。平均負(fù)載是指單位時(shí)間內(nèi),系統(tǒng)處于可運(yùn)行狀態(tài)(正在使用 CPU 或者正在等待 CPU 的進(jìn)程,R 狀態(tài))和不可中斷狀態(tài)(D 狀態(tài))的平均進(jìn)程數(shù),也就是平均活躍進(jìn)程數(shù),CPU 平均負(fù)載和 CPU 使用率并沒(méi)有直接關(guān)系。

    第三行的內(nèi)容表示 CPU 利用率,每一列的含義可以使用 man 查看。CPU 使用率體現(xiàn)了單位時(shí)間內(nèi) CPU 使用情況的統(tǒng)計(jì),以百分比的方式展示。計(jì)算方式為:CPU 利用率 = 1 - (CPU 空閑時(shí)間)/ CPU 總的時(shí)間。需要注意的是,通過(guò)性能分析工具得到的 CPU 的利用率其實(shí)是某個(gè)采樣時(shí)間內(nèi)的 CPU 平均值。注:top 工具顯示的的 CPU 利用率是把所有 CPU 核的數(shù)值加起來(lái)的,即 8 核 CPU 的利用率最大可以到達(dá)800%(可以用 htop 等更新一些的工具代替 top)。

    使用 vmstat 命令,可以查看到「上下文切換次數(shù)」這個(gè)指標(biāo),如下表所示,每隔1秒輸出1組數(shù)據(jù):

    $ 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 0 0 504804 0 1967508 0 0 644 33377 0 1 2 2 88 0 9

    上表的 cs(context switch) 就是每秒上下文切換的次數(shù),按照不同場(chǎng)景,CPU 上下文切換還可以分為中斷上下文切換、線程上下文切換和進(jìn)程上下文切換三種,但是無(wú)論是哪一種,過(guò)多的上下文切換,都會(huì)把 CPU 時(shí)間消耗在寄存器、內(nèi)核棧以及虛擬內(nèi)存等數(shù)據(jù)的保存和恢復(fù)上,從而縮短進(jìn)程真正運(yùn)行的時(shí)間,導(dǎo)致系統(tǒng)的整體性能大幅下降。vmstat 的輸出中 us、sy 分別用戶態(tài)和內(nèi)核態(tài)的 CPU 利用率,這兩個(gè)值也非常具有參考意義。

    vmstat 的輸只給出了系統(tǒng)總體的上下文切換情況,要想查看每個(gè)進(jìn)程的上下文切換詳情(如自愿和非自愿切換),需要使用 pidstat,該命令還可以查看某個(gè)進(jìn)程用戶態(tài)和內(nèi)核態(tài)的 CPU 利用率。

    CPU 相關(guān)指標(biāo)異常的分析思路是什么?

    1)CPU 利用率:如果我們觀察某段時(shí)間系統(tǒng)或應(yīng)用進(jìn)程的 CPU利用率一直很高(單個(gè) core 超過(guò)80%),那么就值得我們警惕了。我們可以多次使用 jstack 命令 dump 應(yīng)用線程棧查看熱點(diǎn)代碼,非 Java 應(yīng)用可以直接使用 perf 進(jìn)行 CPU 采采樣,離線分析采樣數(shù)據(jù)后得到 CPU 執(zhí)行熱點(diǎn)(Java 應(yīng)用需要符號(hào)表進(jìn)行堆棧信息映射,不能直接使用 perf得到結(jié)果)。

    2)CPU 平均負(fù)載:平均負(fù)載高于 CPU 數(shù)量 70%,意味著系統(tǒng)存在瓶頸點(diǎn),造成負(fù)載升高的原因有很多,在這里就不展開(kāi)了。需要注意的是,通過(guò)監(jiān)控系統(tǒng)監(jiān)測(cè)平均負(fù)載的變化趨勢(shì),更容易定位問(wèn)題,有時(shí)候大文件的加載等,也會(huì)導(dǎo)致平均負(fù)載瞬時(shí)升高。如果 1 分鐘/5 分鐘/15 分鐘的三個(gè)值相差不大,那說(shuō)明系統(tǒng)負(fù)載很平穩(wěn),則不用關(guān)注,如果這三個(gè)值逐漸降低,說(shuō)明負(fù)載在漸漸升高,需要關(guān)注整體性能;

    3)CPU 上下文切換:上下文切換這個(gè)指標(biāo),并沒(méi)有經(jīng)驗(yàn)值可推薦(幾十到幾萬(wàn)都有可能),這個(gè)指標(biāo)值取決于系統(tǒng)本身的 CPU 性能,以及當(dāng)前應(yīng)用工作的情況。但是,如果系統(tǒng)或者應(yīng)用的上下文切換次數(shù)出現(xiàn)數(shù)量級(jí)的增長(zhǎng),就有很大概率說(shuō)明存在性能問(wèn)題,如非自愿上下切換大幅度上升,說(shuō)明有太多的線程在競(jìng)爭(zhēng) CPU。

    上面這三個(gè)指標(biāo)是密切相關(guān)的,如頻繁的 CPU 上下文切換,可能會(huì)導(dǎo)致平均負(fù)載升高。如何根據(jù)這三者之間的關(guān)系進(jìn)行應(yīng)用調(diào)優(yōu),將在下一部分介紹。

    CPU 上的的一些異動(dòng),通常也可以從線程上觀測(cè)到,但需要注意的是,線程問(wèn)題并不完全和 CPU 相關(guān)。與線程相關(guān)的指標(biāo),主要有下面幾個(gè)(均都可以通過(guò) JDK 自帶的 jstack 工具直接或間接得到):

  • 應(yīng)用中的總的線程數(shù);
  • 應(yīng)用中各個(gè)線程狀態(tài)的分布;
  • 線程鎖的使用情況,如死鎖、鎖分布等;
  • 關(guān)于線程,可關(guān)注的異常有:

    1)線程總數(shù)是否過(guò)多。過(guò)多的線程,體現(xiàn)在 CPU 上就是導(dǎo)致頻繁的上下文切換,同時(shí)線程過(guò)多也會(huì)消耗內(nèi)存,線程總數(shù)大小和應(yīng)用本身和機(jī)器配置相關(guān);

    2)線程的狀態(tài)是否異常。觀察 WAITING/BLOCKED 線程是否過(guò)多(線程數(shù)設(shè)置過(guò)多或鎖競(jìng)爭(zhēng)劇烈),結(jié)合應(yīng)用內(nèi)部鎖使用的情況綜合分析;

    3)結(jié)合 CPU 利用率,觀察是否存在大量消耗 CPU 的線程。

    3.2 內(nèi)存&&堆

    和內(nèi)存相關(guān)的指標(biāo)主要有以下幾個(gè),常用的分析工具有:top、free、vmstat、pidstat 以及 JDK 自帶的一些工具。

  • 系統(tǒng)內(nèi)存的使用情況,包括剩余內(nèi)存、已用內(nèi)存、可用內(nèi)存、緩存/緩沖區(qū);
  • 進(jìn)程(含 Java 進(jìn)程)的虛擬內(nèi)存、常駐內(nèi)存、共享內(nèi)存;
  • 進(jìn)程的缺頁(yè)異常數(shù),包含主缺頁(yè)異常和次缺頁(yè)異常;
  • Swap 換入和換出的內(nèi)存大小、Swap 參數(shù)配置;
  • JVM 堆的分配,JVM 啟動(dòng)參數(shù);
  • JVM 堆的回收,GC 情況。
  • 使用 free 可以查看系統(tǒng)內(nèi)存的使用情況和 Swap 分區(qū)的使用情況,top 工具可以具體到每個(gè)進(jìn)程,如我們可以用使用 top 工具查看 Java 進(jìn)程的常駐內(nèi)存大小(RES),這兩個(gè)工具結(jié)合起來(lái),可用覆蓋大多數(shù)內(nèi)存指標(biāo)。下面是使用 free命令的輸出:

    $free -h

    total used free shared buff/cache available

    Mem: 125G 6.8G 54G 2.5M 64G 118G

    Swap: 2.0G 305M 1.7G

    上述輸出各列的具體含義在這里不在贅述,也比較容易理解。重點(diǎn)介紹下 swap 和 buff/cache 這兩個(gè)指標(biāo)。

    Swap 的作用是把一個(gè)本地文件或者一塊磁盤空間作為內(nèi)存來(lái)使用,包括換出和換入兩個(gè)過(guò)程。Swap 需要讀寫磁盤,所以性能不是很高,事實(shí)上,包括 ElasticSearch 、Hadoop 在內(nèi)絕大部分 Java 應(yīng)用都建議關(guān)掉 Swap,這是因?yàn)閮?nèi)存的成本一直在降低,同時(shí)這也和 JVM 的垃圾回收過(guò)程有關(guān):JVM在 GC 的時(shí)候會(huì)遍歷所有用到的堆的內(nèi)存,如果這部分內(nèi)存被 Swap 出去了,遍歷的時(shí)候就會(huì)有磁盤 I/O 產(chǎn)生。Swap 分區(qū)的升高一般和磁盤的使用強(qiáng)相關(guān),具體分析時(shí),需要結(jié)合緩存使用情況、swappiness 閾值以及匿名頁(yè)和文件頁(yè)的活躍情況綜合分析。

    buff/cache 是緩存和緩沖區(qū)的大小。緩存(cache):是從磁盤讀取的文件的或者向磁盤寫文件時(shí)的臨時(shí)存儲(chǔ)數(shù)據(jù),面向文件。使用 cachestat 可以查看整個(gè)系統(tǒng)緩存的讀寫命中情況,使用 cachetop 可以觀察每個(gè)進(jìn)程緩存的讀寫命中情況。緩沖區(qū)(buffer)是寫入磁盤數(shù)據(jù)或從磁盤直接讀取的數(shù)據(jù)的臨時(shí)存儲(chǔ),面向塊設(shè)備。free 命令的輸出中,這兩個(gè)指標(biāo)是加在一起的,使用 vmstat 命令可以區(qū)分緩存和緩沖區(qū),還可以看到 Swap 分區(qū)換入和換出的內(nèi)存大小。

    了解到常見(jiàn)的內(nèi)存指標(biāo)后,常見(jiàn)的內(nèi)存問(wèn)題又有哪些?總結(jié)如下:

  • 系統(tǒng)剩余內(nèi)存/可用不足(某個(gè)進(jìn)程占用太多、系統(tǒng)本身內(nèi)存不足),內(nèi)存溢出;
  • 內(nèi)存回收異常:內(nèi)存泄漏(進(jìn)程在一段時(shí)間內(nèi)內(nèi)存使用持續(xù)走高)、GC 頻率異常;
  • 緩存使用過(guò)大(大文件讀取或?qū)懭?#xff09;、緩存命中率不高;
  • 缺頁(yè)異常過(guò)多(頻繁的 I/O 讀);
  • Swap 分區(qū)使用異常(使用過(guò)大);
  • 內(nèi)存相關(guān)指標(biāo)異常后,分析思路是怎么樣的?

  • 使用 free/top 查看內(nèi)存的全局使用情況,如系統(tǒng)內(nèi)存的使用、Swap 分區(qū)內(nèi)存使用、緩存/緩沖區(qū)占用情況等,初步判斷內(nèi)存問(wèn)題存在的方向:進(jìn)程內(nèi)存、緩存/緩沖區(qū)、Swap 分區(qū);
  • 觀察一段時(shí)間內(nèi)存的使用趨勢(shì)。如通過(guò) vmstat 觀察內(nèi)存使用是否一直在增長(zhǎng);通過(guò) jmap 定時(shí)統(tǒng)計(jì)對(duì)象內(nèi)存分布情況,判斷是否存在內(nèi)存泄漏,通過(guò) cachetop 命令,定位緩沖區(qū)升高的根源等;
  • 根據(jù)內(nèi)存問(wèn)題的類型,結(jié)合應(yīng)用本身,進(jìn)行詳細(xì)分析。
  • 舉例:使用 free 發(fā)現(xiàn)緩存/緩沖區(qū)占用不大,排除緩存/緩沖區(qū)對(duì)內(nèi)存的影響后 -> 使用 vmstat 或者 sar 觀察一下各個(gè)進(jìn)程內(nèi)存使用變化趨勢(shì) -> 發(fā)現(xiàn)某個(gè)進(jìn)程的內(nèi)存時(shí)候用持續(xù)走高 -> 如果是 Java 應(yīng)用,可以使用 jmap / VisualVM / heap dump 分析等工具觀察對(duì)象內(nèi)存的分配,或者通過(guò) jstat 觀察 GC 后的應(yīng)用內(nèi)存變化 -> 結(jié)合業(yè)務(wù)場(chǎng)景,定位為內(nèi)存泄漏/GC參數(shù)配置不合理/業(yè)務(wù)代碼異常等。

    3.3 磁盤&&文件

    在分析和磁盤相關(guān)的問(wèn)題時(shí),通常是將其和文件系統(tǒng)同時(shí)考慮的,下面不再區(qū)分。和磁盤/文件系統(tǒng)相關(guān)的指標(biāo)主要有以下幾個(gè),常用的觀測(cè)工具為 iostat和 pidstat,前者適用于整個(gè)系統(tǒng),后者可觀察具體進(jìn)程的 I/O。

  • 磁盤 I/O 利用率:是指磁盤處理 I/O 的時(shí)間百分比;
  • 磁盤吞吐量:是指每秒的 I/O 請(qǐng)求大小,單位為 KB;
  • I/O 響應(yīng)時(shí)間,是指 I/O 請(qǐng)求從發(fā)出到收到響應(yīng)的間隔,包含在隊(duì)列中的等待時(shí)間和實(shí)際處理時(shí)間;
  • IOPS(Input/Output Per Second):每秒的 I/O 請(qǐng)求數(shù);
  • I/O 等待隊(duì)列大小,指的是平均 I/O 隊(duì)列長(zhǎng)度,隊(duì)列長(zhǎng)度越短越好;
  • 使用 iostat 的輸出界面如下:

    $iostat -dx

    Linux 3.10.0-327.ali2010.alios7.x86_64 (loginhost2.alipay.em14) 10/20/2019?x86_64?(32 CPU)

    Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
    sda 0.01 15.49 0.05 8.21 3.10 240.49 58.92 0.04 4.38 2.39 4.39 0.09 0.07

    上圖中 %util ,即為磁盤 I/O 利用率,同 CPU 利用率一樣,這個(gè)值也可能超過(guò) 100%(存在并行 I/O);rkB/s 和 wkB/s分別表示每秒從磁盤讀取和寫入的數(shù)據(jù)量,即吞吐量,單位為 KB;磁盤 I/O處理時(shí)間的指標(biāo)為 r_await 和 w_await 分別表示讀/寫請(qǐng)求處理完成的響應(yīng)時(shí)間,svctm 表示處理 I/O 所需要的平均時(shí)間,該指標(biāo)已被廢棄,無(wú)實(shí)際意義。r/s + w/s 為 IOPS 指標(biāo),分別表示每秒發(fā)送給磁盤的讀請(qǐng)求數(shù)和寫請(qǐng)求數(shù);aqu-sz 表示等待隊(duì)列的長(zhǎng)度。

    pidstat 的輸出大部分和 iostat 類似,區(qū)別在于它可以實(shí)時(shí)查看每個(gè)進(jìn)程的 I/O 情況。

    如何判斷磁盤的指標(biāo)出現(xiàn)了異常?

  • 當(dāng)磁盤 I/O 利用率長(zhǎng)時(shí)間超過(guò) 80%,或者響應(yīng)時(shí)間過(guò)大(對(duì)于 SSD,從 0.0x 毫秒到 1.x 毫秒不等,機(jī)械磁盤一般為5ms~10ms),通常意味著磁盤 I/O 存在性能瓶頸;
  • 如果 %util 很大,而 rkB/s 和 wkB/s 很小,一般是因?yàn)榇嬖谳^多的磁盤隨機(jī)讀寫,最好把隨機(jī)讀寫優(yōu)化成順序讀寫,(可以通過(guò) strace 或者 blktrace 觀察 I/O 是否連續(xù)判斷是否是順序的讀寫行為,隨機(jī)讀寫應(yīng)可關(guān)注 IOPS 指標(biāo),順序讀寫可關(guān)注吞吐量指標(biāo));
  • 如果 avgqu-sz 比較大,說(shuō)明有很多 I/O 請(qǐng)求在隊(duì)列中等待。一般來(lái)說(shuō),如果單塊磁盤的隊(duì)列長(zhǎng)度持續(xù)超過(guò)2,一般認(rèn)為該磁盤存在 I/O 性能問(wèn)題。
  • 3.4 網(wǎng)絡(luò)

    網(wǎng)絡(luò)這個(gè)概念涵蓋的范圍較廣,在應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、網(wǎng)絡(luò)接口層都有不同的指標(biāo)去衡量。這里我們討論的「網(wǎng)絡(luò)」,特指應(yīng)用層的網(wǎng)絡(luò),通常使用的指標(biāo)如下:

  • 網(wǎng)絡(luò)帶寬:表示鏈路的最大傳輸速率;
  • 網(wǎng)絡(luò)吞吐:表示單位時(shí)間內(nèi)成功傳輸?shù)臄?shù)據(jù)量大小;
  • 網(wǎng)絡(luò)延時(shí):表示從網(wǎng)絡(luò)請(qǐng)求發(fā)出后直到收到遠(yuǎn)端響應(yīng),所需要的時(shí)間;
  • 網(wǎng)絡(luò)連接數(shù)和錯(cuò)誤數(shù);
  • 一般來(lái)說(shuō),應(yīng)用層的網(wǎng)絡(luò)瓶頸有如下幾類:

  • 集群或機(jī)器所在的機(jī)房的網(wǎng)絡(luò)帶寬飽和,影響應(yīng)用 QPS/TPS 的提升;
  • 網(wǎng)絡(luò)吞吐出現(xiàn)異常,如接口存在大量的數(shù)據(jù)傳輸,造成帶寬占用過(guò)高;
  • 網(wǎng)絡(luò)連接出現(xiàn)異常或錯(cuò)誤;
  • 網(wǎng)絡(luò)出現(xiàn)分區(qū)。
  • 帶寬和網(wǎng)絡(luò)吞吐這兩個(gè)指標(biāo),一般我們會(huì)關(guān)注整個(gè)應(yīng)用的,通過(guò)監(jiān)控系統(tǒng)可直接得到,如果一段時(shí)間內(nèi)出現(xiàn)了明顯的指標(biāo)上升,說(shuō)明存在網(wǎng)絡(luò)性能瓶頸。對(duì)于單機(jī),可以使用 sar 得到網(wǎng)絡(luò)接口、進(jìn)程的網(wǎng)絡(luò)吞吐。

    使用 ping 或者 hping3 可以得到是否出現(xiàn)網(wǎng)絡(luò)分區(qū)、網(wǎng)絡(luò)具體時(shí)延。對(duì)于應(yīng)用,我們更關(guān)注整個(gè)鏈路的時(shí)延,可以通過(guò)中間件埋點(diǎn)后輸出的 trace 日志得到鏈路上各個(gè)環(huán)節(jié)的時(shí)延信息。

    使用 netstat、ss 和 sar 可以獲取網(wǎng)絡(luò)連接數(shù)或網(wǎng)絡(luò)錯(cuò)誤數(shù)。過(guò)多網(wǎng)絡(luò)鏈接造成的開(kāi)銷是很大的,一是會(huì)占用文件描述符,二是會(huì)占用緩存,因此系統(tǒng)可以支撐的網(wǎng)絡(luò)鏈接數(shù)是有限的。

    3.5 工具總結(jié)

    可以看到的是,在分析 CPU、內(nèi)存、磁盤等的性能指標(biāo)時(shí),有幾種工具是高頻出現(xiàn)的,如 top、vmstat、pidstat,這里稍微總結(jié)一下:

  • CPU:top、vmstat、pidstat、sar、perf、jstack、jstat;
  • 內(nèi)存:top、free、vmstat、cachetop、cachestat、sar、jmap;
  • 磁盤:top、iostat、vmstat、pidstat、du/df;
  • 網(wǎng)絡(luò):netstat、sar、dstat、tcpdump;
  • 應(yīng)用:profiler、dump分析。
  • 上述的很多工具,大部分是用于查看系統(tǒng)層指標(biāo)的,在應(yīng)用層,除了有 JDK 提供的一系列工具,一些商用的產(chǎn)品如 gceasy.io(分析 GC 日志)、fastthread.io(分析線程 dump 日志)也是不錯(cuò)的。

    排查 Java 應(yīng)用的線上異常或者分析應(yīng)用代碼瓶頸,可以使用阿里開(kāi)源的 Arthas ,這個(gè)工具非常強(qiáng)大,下面簡(jiǎn)單介紹下。

    Arthas 主要面向線上應(yīng)用實(shí)時(shí)診斷,解決的是類似「線上應(yīng)用異常了,需要在線進(jìn)行分析和定位」的問(wèn)題,當(dāng)然,Arthas 提供的一些方法調(diào)用追蹤工具,對(duì)我們排查諸如「慢查詢」等問(wèn)題,也是非常有幫助的。Arthas 提供的主要功能有:

  • 獲取線程統(tǒng)計(jì),如線程持有的鎖統(tǒng)計(jì)、CPU 利用率統(tǒng)計(jì)等;
  • 類加載信息、動(dòng)態(tài)類加載、方法加載信息;
  • 調(diào)用棧追蹤,調(diào)用耗時(shí)統(tǒng)計(jì);
  • 方法調(diào)用參數(shù)、結(jié)果檢測(cè);
  • 系統(tǒng)配置、應(yīng)用配置信息;
  • 反編譯加載類;
  • ....
  • 需要注意的是,性能工具只是解決性能問(wèn)題的手段,我們了解常用工具的一般用法即可,不要在工具學(xué)習(xí)上投入過(guò)多精力。


    原文鏈接
    本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。

    總結(jié)

    以上是生活随笔為你收集整理的如何回答性能优化的问题,才能打动阿里面试官?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。