天天看點

阿裡巴巴java性能調優實戰:如何制定性能調優标準?

如何制定性能調優标準?

我有一個朋友,有一次他跟我說,他們公司的系統從來沒有經過性能調優,功能測試完成後 就上線了,線上也沒有出現過什麼性能問題呀,那為什麼很多系統都要去做性能調優呢? 當時我就回答了他一句,如果你們公司做的是 12306 網站,不做系統性能優化就上線,試 試看會是什麼情況。

如果是你,你會怎麼回答呢?今天,我們就從這個話題聊起,希望能跟你一起弄明白這幾個問題。

1.我們為什麼要做性能調優?

2.什麼時候開始做?

3.做性能調優是不是有标準可參考?

為什麼要做性能調優?

一款線上産品如果沒有經過性能測試,那它就好比是一顆定時炸彈,你不知道它什麼時候會出現問題,你也不清楚它能承受的極限在哪兒。

有些性能問題是時間累積慢慢産生的,到了一定時間自然就爆炸了;

而更多的性能問題是由 通路量的波動導緻的,例如,活動或者公司産品使用者量上升;當然也有可能是一款産品上線 後就半死不活,一直沒有大通路量,是以還沒有引發這顆定時炸彈。

現在假設你的系統要做一次活動,産品經理或者老闆告訴你預計有幾十萬的使用者通路量,詢 問系統能否承受得住這次活動的壓力。

如果你不清楚自己系統的性能情況,也隻能戰戰兢兢 地回答老闆,有可能大概沒問題吧。 是以,要不要做性能調優,這個問題其實很好回答。所有的系統在開發完之後,多多少少都 會有性能問題,我們首先要做的就是想辦法把問題暴露出來,例如進行壓力測試、模拟可能 的操作場景等等,再通過性能調優去解決這些問題。 比如,當你在用某一款 App 查詢某一條資訊時,需要等待十幾秒鐘;在搶購活動中,無法 進入活動頁面等等。你看,系統響應就是展現系統性能最直接的一個參考因素。 那如果系統線上上沒有出現響應問題,我們是不是就不用去做性能優化了呢?

再給你講一個 故事吧。 曾經我的前前東家系統研發部門來了一位大神,為什麼叫他大神,因為在他來公司的一年時 間裡,他隻做了一件事情,就是把伺服器的數量縮減到了原來的一半,系統的性能名額,反 而還提升了。 好的系統性能調優不僅僅可以提高系統的性能,還能為公司節省資源。這也是我們做性能調 優的最直接的目的。

什麼時候開始介入調優?

解決了為什麼要做性能優化的問題,那麼新的問題就來了:如果需要對系統做一次全面的性 能監測和優化,我們從什麼時候開始介入性能調優呢?是不是越早介入越好?

其實,在項目開發的初期,我們沒有必要過于在意性能優化,這樣反而會讓我們疲于性能優 化,不僅不會給系統性能帶來提升,還會影響到開發進度,甚至獲得相反的效果,給系統帶來新的問題。

我們隻需要在代碼層面保證有效的編碼,比如,減少磁盤 I/O 操作、降低競争鎖的使用以 及使用高效的算法等等。遇到比較複雜的業務,我們可以充分利用設計模式來優化業務代碼。

例如,設計商品價格的時候,往往會有很多折扣活動、紅包活動,我們可以用裝飾模式去設計這個業務。

在系統編碼完成之後,我們就可以對系統進行性能測試了。這時候,産品經理一般會提供線上預期資料,我們在提供的參考平台上進行壓測,通過性能分析、統計工具來統計各項性能 名額,看是否在預期範圍之内。

在項目成功上線後,我們還需要根據線上的實際情況,依照日志監控以及性能統計日志,來 觀測系統性能問題,一旦發現問題,就要對日志進行分析并及時修複問題。

有哪些參考因素可以展現系統的性能?

上面我們講到了在項目研發的各個階段性能調優是如何介入的,其中多次講到了性能名額, 那麼性能名額到底有哪些呢?

在我們了解性能名額之前,我們先來了解下哪些計算機資源會成為系統的性能瓶頸。

CPU:有的應用需要大量計算,他們會長時間、不間斷地占用 CPU 資源,導緻其他資源無 法争奪到 CPU 而響應緩慢,進而帶來系統性能問題。例如,代碼遞歸導緻的無限循環,正 則表達式引起的回溯,JVM 頻繁的 FULL GC,以及多線程程式設計造成的大量上下文切換等, 這些都有可能導緻 CPU 資源繁忙。

記憶體:Java 程式一般通過 JVM 對記憶體進行配置設定管理,主要是用 JVM 中的堆記憶體來存儲 Java 建立的對象。系統堆記憶體的讀寫速度非常快,是以基本不存在讀寫性能瓶頸。但是由 于記憶體成本要比磁盤高,相比磁盤,記憶體的存儲空間又非常有限。是以當記憶體空間被占滿, 對象無法回收時,就會導緻記憶體溢出、記憶體洩露等問題。

磁盤 I/O:磁盤相比記憶體來說,存儲空間要大很多,但磁盤 I/O 讀寫的速度要比記憶體慢, 雖然目前引入的 SSD 固态硬碟已經有所優化,但仍然無法與記憶體的讀寫速度相提并論。

網絡:網絡對于系統性能來說,也起着至關重要的作用。如果你購買過雲服務,一定經曆 過,選擇網絡帶寬大小這一環節。帶寬過低的話,對于傳輸資料比較大,或者是并發量比較 大的系統,網絡就很容易成為性能瓶頸。

異常:Java 應用中,抛出異常需要建構異常棧,對異常進行捕獲和處理,這個過程非常消 耗系統性能。如果在高并發的情況下引發異常,持續地進行異常處理,那麼系統的性能就會 明顯地受到影響。

資料庫:大部分系統都會用到資料庫,而資料庫的操作往往是涉及到磁盤 I/O 的讀寫。大 量的資料庫讀寫操作,會導緻磁盤 I/O 性能瓶頸,進而導緻資料庫操作的延遲性。對于有 大量資料庫讀寫操作的系統來說,資料庫的性能優化是整個系統的核心。

鎖競争:在并發程式設計中,我們經常會需要多個線程,共享讀寫操作同一個資源,這個時候為 了保持資料的原子性(即保證這個共享資源在一個線程寫的時候,不被另一個線程修改), 我們就會用到鎖。鎖的使用可能會帶來上下文切換,進而給系統帶來性能開銷。JDK1.6 之 後,Java 為了降低鎖競争帶來的上下文切換,對 JVM 内部鎖已經做了多次優化,例如,新 增了偏向鎖、自旋鎖、輕量級鎖、鎖粗化、鎖消除等。而如何合理地使用鎖資源,優化鎖資 源,就需要你了解更多的作業系統知識、Java 多線程程式設計基礎,積累項目經驗,并結合實 際場景去處理相關問題。 了解了上面這些基本内容,我們可以得到下面幾個名額,來衡量一般系統的性能。

響應時間:響應時間是衡量系統性能的重要名額之一,響應時間越短,性能越好,一般一個接口的響應 時間是在毫秒級。在系統中,我們可以把響應時間自下而上細分為以下幾種:

阿裡巴巴java性能調優實戰:如何制定性能調優标準?

資料庫響應時間:資料庫操作所消耗的時間,往往是整個請求鍊中最耗時的。

服務端響應時間:服務端包括 Nginx 分發的請求所消耗的時間以及服務端程式執行所消耗的時間。

網絡響應時間:這是網絡傳輸時,網絡硬體需要對傳輸的請求進行解析等操作所消耗的時間。

用戶端響應時間:對于普通的 Web、App 用戶端來說,消耗時間是可以忽略不計的,但如果你的用戶端嵌入了大量的邏輯處理,消耗的時間就有可能變長,進而成為系統的瓶頸。

吞吐量

在測試中,我們往往會比較注重系統接口的 TPS(每秒事務處理量),因為 TPS 展現了接 口的性能,TPS 越大,性能越好。在系統中,我們也可以把吞吐量自下而上地分為兩種: 磁盤吞吐量和網絡吞吐量。

我們先來看磁盤吞吐量,磁盤性能有兩個關鍵衡量名額。

IOPS(Input/Output Per Second),即每秒的輸入輸出量(或讀寫次數),這種 是指機關時間内系統能處理的 I/O 請求數量,I/O 請求通常為讀或寫資料操作請求,關注的 是随機讀寫性能。适應于随機讀寫頻繁的應用,如小檔案存儲(圖檔)、OLTP 資料庫、郵件伺服器。

資料吞吐量:這種是指機關時間内可以成功傳輸的資料量。對于大量順序讀寫頻繁 的應用,傳輸大量連續資料,例如,電視台的視訊編輯、視訊點播 VOD(Video On Demand),資料吞吐量則是關鍵衡量名額。

網絡吞吐量:這個是指網絡傳輸時沒有幀丢失的情況下,裝置能夠接受的最大資料 速率。網絡吞吐量不僅僅跟帶寬有關系,還跟 CPU 的處理能力、網卡、防火牆、外部接口 以及 I/O 等緊密關聯。而吞吐量的大小主要由網卡的處理能力、内部程式算法以及帶寬大小決定。

計算機資源配置設定使用率

通常由 CPU 占用率、記憶體使用率、磁盤 I/O、網絡 I/O 來表示資源使用率。這幾個參數好 比一個木桶,如果其中任何一塊木闆出現短闆,任何一項配置設定不合理,對整個系統性能的影響都是毀滅性的。

總結

通過今天的學習,我們知道性能調優可以使系統穩定,使用者體驗更佳,甚至在比較大的系統中,還能幫公司節約資源。

但是在項目的開始階段,我們沒有必要過早地介入性能優化,隻需在編碼的時候保證其優秀、高效,以及良好的程式設計。

在完成項目後,我們就可以進行系統測試了,我們可以将以下性能名額,作為性能調優的标準,響應時間、吞吐量、計算機資源配置設定使用率、負載承受能力。

回顧我自己的項目經驗,有電商系統、支付系統以及遊戲充值計費系統,使用者級都是千萬級别,且要承受各種大型搶購活動,是以我對系統的性能要求非常苛刻。除了通過觀察以上指 标來确定系統性能的好壞,還需要在更新疊代中,充分保障系統的穩定性。

這裡,給你延伸一個方法,就是将疊代之前版本的系統性能名額作為參考标準,通過自動化 性能測試,校驗疊代發版之後的系統性能是否出現異常,這裡就不僅僅是比較吞吐量、響應 時間、負載能力等直接名額了,還需要比較系統資源的 CPU 占用率、記憶體使用率、磁盤 I/O、網絡 I/O 等幾項間接名額的變化。