系統性能調優技術實戰

系統性能調優技術實戰

2013-02-28 13:37 李蒙強  博客園  字號:T | T
一鍵收藏,隨時查看,分享好友!

最近看了不少關於系統性能調優的文章,發現不少文章都是介紹某一方面的,例如專門數據庫方面的優化、前端頁面的優化等等都不是很全面,這裏結合我在工做中的一些實踐對系統性能調優技術來一個綜合性的分享。css

AD:2014WOT全球軟件技術峯會北京站 課程視頻發佈html

 

本文目錄以下:前端

一、概述
一、1 系統性能定義
一、2 目的意義
二、性能優化技術
二、1 前端優化
二、2 後端優化
三、總結

一、概述nginx

最近看了不少關於系統性能調優的文章,發現不少文章都是介紹某一方面的,例如專門數據庫方面的優化、前端頁面的優化等等都不是很全面,這裏結合我在工做中的一些實踐對系統性能調優技術來一個綜合性的分享。git

一、1 系統性能定義github

如上圖,性能就是吞吐量加延遲,這兩個相互矛盾又相互協調構成了一個系統性能的定義:算法

  • Throughput ,吞吐量。也就是每秒鐘能夠處理的請求數,任務數。
  • Latency, 系統延遲。也就是系統在處理一個請求或一個任務時的延遲。

通常來講,一個系統的性能受到這兩個條件的約束,缺一不可。好比,個人系統能夠頂得住一百萬的併發,可是系統的延遲是2分鐘以上,那麼,這個一百萬的負載毫無心義。系統延遲很短,可是吞吐量很低,一樣沒有意義。因此,一個好的系統的性能測試必然受到這兩個條件的同時做用。 有經驗的朋友必定知道,這兩個東西的一些關係:sql

  • Throughput越大,Latency會越差。由於請求量過大,系統太繁忙,因此響應速度天然會低。
  • Latency越好,能支持的Throughput就會越高。由於Latency短說明處理速度快,因而就能夠處理更多的請求。

一、2 目的意義數據庫

本文的目的是經過講解系統性能讓你們在後續的工做中可以帶着產品化的思路去優化本身的代碼包括先後臺、數據庫等,自測過程當中咱們能夠利用壓力性能測試pylot、Fiddler、單元測試等工具去發現系統的問題從而去優化提升系統的質量,這樣經過團隊的配合和努力來提升加強用戶的體驗從而提升咱們公司的競爭力!編程

二、性能優化技術

如下性能優化技術須要咱們在本身工做過程當中不斷積累和總結,在工做中配合一些專業的測試工具去發現性能的瓶頸,這裏把性能優化技術分爲兩塊分別是前端和後端的優化。

二、1 前端優化

2.1.1 負載均衡

經過DNS的負載均衡器(通常在路由器上根據路由的負載重定向)能夠把用戶的訪問均勻地分散在多個Web服務器上。這樣能夠減小Web服務器的請求負載。由於http的請求都是短做業,因此,能夠經過很簡單的負載均衡器來完成這一功能。最好是有CDN網絡讓用戶鏈接與其最近的服務器(CDN一般伴隨着分佈式存儲)。

CDN的全稱是Content Delivery Network,即內容分發網絡。其基本思路是儘量避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快、更穩定。

CDN的通俗理解就是網站加速,能夠解決跨運營商,跨地區,服務器負載能力太低,帶寬過少等帶來的網站打開速度慢等問題。

CDN的特色和優點:

一、本地Cache加速 提升了企業站點(尤爲含有大量圖片和靜態頁面站點)的訪問速度,並大大提升以上性質站點的穩定性

二、鏡像服務 消除了不一樣運營商之間互聯的瓶頸形成的影響,實現了跨運營商的網絡加速,保證不一樣網絡中的用戶都能獲得良好的訪問質量。

三、遠程加速 遠程訪問用戶根據DNS負載均衡技術智能自動選擇Cache服務器,選擇最快的Cache服務器,加快遠程訪問的速度

四、帶寬優化 自動生成服務器的遠程Mirror(鏡像)cache服務器,遠程用戶訪問時從cache服務器上讀取數據,減小遠程訪問的帶寬、分擔網絡流量、減輕原站點WEB服務器負載等功能。

2.1.2 減小請求和2.1.3縮減網頁

減小請求數

(1)系統某個頁面的加載每每伴隨着多個請求的發生,請求越多吞吐量越大,延遲就會變大,這裏就要考慮優化請求數了,咱們可使用Fiddler等工具查看某個網頁的請求數,以下圖,若是咱們的一個網頁引用了不少樣式和js,例如一個頁面引用了10個css和10個js,那麼咱們應該考慮把某些樣式和js合併起來;

(2)Css Sprites:有不少圖片咱們其實能夠用一張圖片來代替的,通常須要跟美工或UI設計器配合一塊兒來作的,美工或UI設計師去設計出來以後告訴咱們圖片中具體元素的位置或者封裝在css中,研發這邊直接調用便可。

異步

系統某個頁面中若是有一個請求的響應超過0.5秒以上或者請求的響應量大於300KB的話咱們應該考慮進行異步請求,還有就是一些服務的調用這些儘可能不要用同步,一阻塞整個網站的體驗會很是差;

CSS/JS壓縮

能夠藉助一些開源的壓縮工具,像開源的yuicompressor,發佈或發包時把js和css都壓縮一下,這樣js和css文件就會很是小了;

GZIP壓縮

使用GZIP壓縮能夠下降服務器發送的字節數,能讓客戶感受到網頁的速度更 快也減小了對帶寬的使用狀況;

IIS裏面也能夠設置GZIP壓縮,能夠壓縮應用程序文件和靜態文件,具體百度。

精簡代碼

最高效的程序就是不執行任何代碼的程序,因此,代碼越少性能就越高。關於代碼級優化的技術大學裏的教科書有不少示例了。如:減小循環的層數,減小遞歸,在循環中少聲明變量,少作分配和釋放內存的操做,儘可能把循環體內的表達式抽到循環外,條件表達的中的多個條件判斷的次序,儘可能在程序啓動時把一些東西準備好,注意函數調用的開銷(棧上開銷),注意面嚮對象語言中臨時對象的開銷,當心使用異常。

開源框架

如今開源的好東西太多了,關鍵是你要有一雙慧眼,向你們推薦開源中國社區、github、codeplex,我發現如今比較厲害的開發者就是一個很牛逼的模仿者,消化掉成爲本身的其實就是一種創新;

2.1.4 優化查詢

(1)SQL語句的優化

關於SQL語句的優化,首先也是要使用工具,好比:MySQL SQL Query Analyzer,Oracle SQL Performance Analyzer,或是微軟SQL Query Analyzer,基本上來講,全部的RMDB都會有這樣的工具,來讓你查看你的應用中的SQL的性能問題。 還可使用explain來看看SQL語句最終Execution Plan會是什麼樣的。

還有一點很重要,數據庫的各類操做須要大量的內存,因此服務器的內存要夠,優其應對那些多表查詢的SQL語句,那是至關的耗內存。

下面我根據我有限的數據庫SQL的知識說幾個會有性能問題的SQL:

全表檢索。好比:select * from user where lastname = 「xxxx」,這樣的SQL語句基本上是全表查找,線性複雜度O(n),記錄數越多,性能也越差(如:100條記錄的查找要50ms,一百萬條記錄須要5分鐘)。對於這種狀況,咱們能夠有兩種方法提升性能:一種方法是分表,把記錄數降下來,另外一種方法是建索引(爲lastname建索引)。索引就像是key-value的數據結構同樣,key就是where後面的字段,value就是物理行號,對索引的搜索複雜度是基本上是O(log(n)) ——用B-Tree實現索引(如:100條記錄的查找要50ms,一百萬條記錄須要100ms)。

索引。對於索引字段,最好不要在字段上作計算、類型轉換、函數、空值判斷、字段鏈接操做,這些操做都會破壞索引本來的性能。固然,索引通常都出如今Where或是Order by字句中,因此對Where和Order by子句中的子段最好不要進行計算操做,或是加上什麼NOT之類的,或是使用什麼函數。

多表查詢。關係型數據庫最多的操做就是多表查詢,多表查詢主要有三個關鍵字,EXISTS,IN和JOIN(關於各類join,能夠參看圖解SQL的Join一文)。基原本說,現代的數據引擎對SQL語句優化得都挺好的,JOIN和IN/EXISTS在結果上有些不一樣,但性能基本上都差很少。有人說,EXISTS的性能要好於IN,IN的性能要好於JOIN,我各人以爲,這個還要看你的數據、schema和SQL語句的複雜度,對於通常的簡單的狀況來講,都差很少,因此千萬不要使用過多的嵌套,千萬不要讓你的SQL太複雜,寧肯使用幾個簡單的SQL也不要使用一個巨大無比的嵌套N級的SQL。還有人說,若是兩個表的數據量差很少,Exists的性能可能會高於In,In可能會高於Join,若是這兩個表一大一小,那麼子查詢中,Exists用大表,In則用小表。這個,我沒有驗證過,放在這裏讓你們討論吧。另,有一篇關於SQL Server的文章你們能夠看看《IN vs JOIN vs EXISTS》。

JOIN操做。有人說,Join表的順序會影響性能,只要Join的結果集是同樣,性能和join的次序無關。由於後臺的數據庫引擎會幫咱們優化的。Join有三種實現算法,嵌套循環,排序歸併,和Hash式的Join。(MySQL只支持第一種)。

  • 嵌套循環,就好像是咱們常見的多重嵌套循環。注意,前面的索引說過,數據庫的索引查找算法用的是B-Tree,這是O(log(n))的算法,因此,整個算法復法度應該是O(log(n)) * O(log(m)) 這樣的。
  • Hash式的Join,主要解決嵌套循環的O(log(n))的複雜,使用一個臨時的hash表來標記。
  • 排序歸併,意思是兩個表按照查詢字段排好序,而後再合併。固然,索引字段通常是排好序的。

仍是那句話,具體要看什麼樣的數據,什麼樣的SQL語句,你才知道用哪一種方法是最好的。

部分結果集。咱們知道MySQL裏的Limit關鍵字,Oracle裏的rownum,SQL Server裏的Top都是在限制前幾條的返回結果。這給了咱們數據庫引擎不少能夠調優的空間。通常來講,返回top n的記錄數據須要咱們使用order by,注意在這裏咱們須要爲order by的字段創建索引。有了被建索引的order by後,會讓咱們的select語句的性能不會被記錄數的所影響。使用這個技術,通常來講咱們前臺會以分頁方式來顯現數據,Mysql用的是OFFSET,SQL Server用的是FETCH NEXT,這種Fetch的方式其實並很差是線性複雜度,因此,若是咱們可以知道order by字段的第二頁的起始值,咱們就能夠在where語句裏直接使用>=的表達式來select,這種技術叫seek,而不是fetch,seek的性能比fetch要高不少。

字符串。正如我前面所說的,字符串操做對性能上有很是大的惡夢,因此,能用數據的狀況就用數字,好比:時間,工號,等。

全文檢索。千萬不要用Like之類的東西來作全文檢索,若是要玩全文檢索,能夠嘗試使用Sphinx。

其它。

  • 不要select *,而是明確指出各個字段,若是有多個表,必定要在字段名前加上表名,不要讓引擎去算。
  • 不要用Having,由於其要遍歷全部的記錄。性能差得不能再差。
  • 儘量地使用UNION ALL  取代  UNION。
  • 索引過多,insert和delete就會越慢。而update若是update多數索引,也會慢,可是若是隻update一個,則只會影響一個索引表。

(2)DBCC DBREINDEX重建索引

優化實戰

2.1.5 靜態化

靜態化一些不常變的頁面和數據,並gzip一下。使用nginx的sendfile功能可讓這些靜態文件直接在內核心態交換,能夠極大增長性能。

通常咱們能夠作一個靜態文件管理功能,能夠把咱們網站的一些欄目直接經過請求/響應的方式在服務器上直接生成靜態文件,固然這裏能夠設置一個時間頻率,用戶直接訪問靜態頁面訪問效率確定很是高!

2.1.6 緩存

一般,應用程序能夠將那些頻繁訪問的數據,以及那些須要大量處理時間來建立的數據存儲在內存中,從而提升性能;它包括應用程序緩存和頁輸出緩存;

通常咱們大部分用的是應用程序緩存

緩存的應用場景主要有:

OutputCache

咱們能夠用Fiddler找出一些內容幾乎不會改變的頁面,給它們設置OutputCache指令便可;

對於設置過OutputCache的頁面來講,瀏覽器在收到這類頁面的響應後,會將頁面響應內容緩存起來。 只要在指定的緩存時間以內,且用戶沒有強制刷新的操做,那麼就根本不會再次請求服務端, 而對於來自其它的瀏覽器發起的請求,若是緩存頁已生成,那麼就能夠直接從緩存中響應請求,加快響應速度。 所以,OutputCache指令對於性能優化來講,是頗有意義的(除非全部頁面頁面都在頻繁更新)。

應用程序緩存

應用程序緩存提供了一種編程方式,可經過鍵/值對將任意數據存儲在內存中,這裏提供一個asp.net對緩存有效封裝的例子,見緩存機制理解及C#開發使用。

緩存能夠用來緩存動態頁面,也能夠用來緩存查詢的數據。緩存一般有那麼幾個問題:

1)緩存的更新。也叫緩存和數據庫的同步。有這麼幾種方法,一是緩存time out,讓緩存失效,重查,二是,由後端通知更新,一量後端發生變化,通知前端更新。前者實現起來比較簡單,但實時性不高,後者實現起來比較複雜 ,但實時性高。

2)緩存的換頁。內存可能不夠,因此,須要把一些不活躍的數據換出內存,這個和操做系統的內存換頁和交換內存很類似。FIFO、LRU、LFU都是比較經典的換頁算法。

3)緩存的重建和持久化。緩存在內存,系統總要維護,因此,緩存就會丟失,若是緩存沒了,就須要重建,若是數據量很大,緩存重建的過程會很慢,這會影響生產環境,因此,緩存的持久化也是須要考慮的。

 

【編輯推薦】

相關文章
相關標籤/搜索