想讓你的程序更快更穩,可是系統常常出各類 bug,無從下手?Java 性能調優全攻略來啦!程序員
我有一個朋友,有一次他跟我說,他們公司的系統歷來沒有通過性能調優,功能測試完成後就上線了,線上也沒有出現過什麼性能問題呀,那爲何不少系統都要去作性能調優呢?正則表達式
當時我就回答了他一句,若是大家公司作的是 12306 網站,不作系統性能優化就上線,試試看會是什麼狀況。算法
若是是你,你會怎麼回答呢?今天,咱們就從這個話題聊起,但願能跟你一塊兒弄明白這幾個問題:咱們爲何要作性能調優?何時開始作?作性能調優是否是有標準可參考?sql
爲何要作 數據庫
一款線上產品若是沒有通過性能測試,那它就比如是一顆定時炸彈,你不知道它何時會出現問題,你也不清楚它能承受的極限在哪兒。有些性能問題是時間累積慢慢產生的,到了必定時間天然就爆炸了;而更多的性能問題是由訪問量的波動致使的,例如,活動或者公司產品用戶量上升;固然也有多是一款產品上線後就半死不活,一直沒有大訪問量,因此尚未引起這顆定時炸彈。編程
如今假設你的系統要作一次活動,產品經理或者老闆告訴你預計有幾十萬的用戶訪問量,詢問系統可否承受得住此次活動的壓力。若是你不清楚本身系統的性能狀況,也只能戰戰兢兢地回答老闆,有可能大概沒問題吧。設計模式
因此,要不要作性能調優,這個問題其實很好回答。全部的系統在開發完以後,多多少少都會有性能問題,咱們首先要作的就是想辦法把問題暴露出來,例如進行壓力測試、模擬可能的操做場景等等,再經過性能調優去解決這些問題。性能優化
好比,當你在用某一款 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 多線程編程基礎,積累項目經驗,並結合實際場景去處理相關問題。
瞭解了上面這些基本內容,咱們能夠獲得下面幾個指標,來衡量通常系統的性能。
一、響應時間
響應時間是衡量系統性能的重要指標之一,響應時間越短,性能越好,通常一個接口的響應時間是在毫秒級。在系統中,咱們能夠把響應時間自下而上細分爲如下幾種:
數據庫響應時間:數據庫操做所消耗的時間,每每是整個請求鏈中最耗時的;
服務端響應時間:服務端包括 Nginx 分發的請求所消耗的時間以及服務端程序執行所消耗的時間;
網絡響應時間:這是網絡傳輸時,網絡硬件須要對傳輸的請求進行解析等操做所消耗的時間;
客戶端響應時間:對於普通的 Web、App 客戶端來講,消耗時間是能夠忽略不計的,但若是你的客戶端嵌入了大量的邏輯處理,消耗的時間就有可能變長,從而成爲系統的瓶頸。
二、吞吐量
在測試中,咱們每每會比較注重系統接口的 TPS(每秒事務處理量),由於 TPS 體現了接口的性能,TPS 越大,性能越好。在系統中,咱們也能夠把吞吐量自下而上地分爲兩種:磁盤吞吐量和網絡吞吐量。咱們先來看磁盤吞吐量,磁盤性能有兩個關鍵衡量指標。
接下來看網絡吞吐量,這個是指網絡傳輸時沒有幀丟失的狀況下,設備可以接受的最大數據速率。網絡吞吐量不只僅跟帶寬有關係,還跟 CPU 的處理能力、網卡、防火牆、外部接口以及 I/O 等等緊密關聯。而吞吐量的大小主要由網卡的處理能力、內部程序算法以及帶寬大小決定。
三、計算機資源分配使用率
一般由 CPU 佔用率、內存使用率、磁盤 I/O、網絡 I/O 來表示資源使用率。這幾個參數比如一個木桶,若是其中任何一塊木板出現短板,任何一項分配不合理,對整個系統性能的影響都是毀滅性的。
四、負載承受能力
當系統壓力上升時,你能夠觀察,系統響應時間的上升曲線是否平緩。這項指標能直觀地反饋給你,系統所能承受的負載壓力極限。例如,當你對系統進行壓測時,系統的響應時間會隨着系統併發數的增長而延長,直到系統沒法處理這麼多請求,拋出大量錯誤時,就到了極限。
總結
經過今天的學習,咱們知道
可是在項目的開始階段,咱們沒有必要過早地介入性能優化,只需在編碼的時候保證其優秀、高效,以及良好的程序設計。
在完成項目後,咱們就能夠進行系統測試了,咱們能夠將如下性能指標,做爲性能調優的標準,響應時間、吞吐量、計算機資源分配使用率、負載承受能力。
回顧我本身的項目經驗,有電商系統、支付系統以及遊戲充值計費系統,用戶級都是千萬級別,且要承受各類大型搶購活動,因此我對系統的性能要求很是苛刻。除了經過觀察以上指標來肯定系統性能的好壞,還須要在更新迭代中,充分保障系統的穩定性。
這裏,給你延伸一個方法,就是將迭代以前版本的系統性能指標做爲參考標準,經過自動化性能測試,校驗迭代發版以後的系統性能是否出現異常,這裏就不只僅是比較吞吐量、響應時間、負載能力等直接指標了,還須要比較系統資源的 CPU 佔用率、內存使用率、磁盤 I/O、網絡 I/O 等幾項間接指標的變化。
歡迎工做一到五年的Java工程師朋友們加入Java程序員開發: 721575865
羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!