歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Yahoo Web 應用性能及linux內核優化黃金法則詳解

Yahoo Web 應用性能及linux內核優化黃金法則詳解

日期:2017/3/3 11:29:50   编辑:Linux內核
Web 應用性能優化黃金法則:先優化前端程序(front-end) 的性能,因為這是80% 或以上的最終用戶響應時間的花費所在。
法則1. 減少HTTP 請求次數
80%的最終用戶響應時間花在前端程序上,而其大部分時間則花在各種頁面元素,如圖像、樣式表、腳本和Flash等,的下載上。減少頁面元素將會減少HTTP請求次數。這是快速顯示頁面的關鍵所在。一種減少頁面元素個數的方法是簡化頁面設計。但是否存在其他方式,能做到既有豐富內容,又能獲得快速響應時間呢?以下是這樣一些技術:Image maps 組合多個圖片到一張圖片中。總文件大小變化不大,但減少了HTTP請求次數從而加快了頁面顯示速度。該方式只適合圖片連續的情況;同時坐標的定義是煩人又容易出錯的工作。CSS Sprites 是更好的方法。它可以組合頁面中的圖片到單個文件中,並使用CSS的background-image和background-position屬性來現實所需的部分圖片。Inline images使用data: URL scheme 來在頁面中內嵌圖片。這將增大HTML文件的大小。組合inline images到你的(緩存)樣式表是既能較少HTTP請求,又能避免加大HTML文件大小的方法。Combined files通過組合多個腳本文件到單一文件來減少HTTP請求次數。樣式表也可采用類似方法處理。這個方法雖然簡單,但沒有得到大規模的使用。10大美國網站每頁平均有7個腳本文件和2個樣式表。當頁面之間腳本和樣式表變化很大時,該方式將遇到很大的挑戰,但如果做到的話,將能加快響應時間。減少HTTP請求次數是性能優化的起點。這最提高首次訪問的效率起到很重要的作用。據Tenni Theurer的文章Browser Cache Usage - Exposed!描述,40-60%的日常訪問是首次訪問,因此為首次訪問者加快頁面訪問速度是用戶體驗的關鍵。
法則2. 使用CDN(Content Delivery Network, 內容分發網絡)
用戶離web server的遠近對響應時間也有很大影響。從用戶角度看,把內容部署到多個地理位置分散的服務器上將有效提高頁面裝載速度。但是該從哪裡開始呢?作為實現內容地理分布的第一步,不要試圖重構web應用以適應分布架構。改變架構將導致多個周期性任務,如同步session狀態,在多個server之間復制數據庫交易。這樣縮短用戶與內容距離的嘗試可能被應用架構改版所延遲,或阻止。
我們還記得80-90%的最終用戶響應時間花在下載頁面中的各種元素上,如圖像文件、樣式表、腳本和Flash等。與其花在重構系統這個困難的任務上,還不如先分布靜態內容。這不僅能大大減少響應時間,而且由於CDN的存在,分布靜態內容非常容易實現。
CDN是地理上分布的web server的集合,用於更高效地發布內容。通常基於網絡遠近來選擇給具體用戶服務的web server。
一些大型網站擁有自己的CDN,但是使用如Akamai Technologies, MirrorImage Internet, 或Limelight Networks 等CDN服務提供商的服務將是劃算的。在Yahoo!把靜態內容分布到CDN減少了用戶影響時間20%或更多。切換到CDN的代碼修改工作是很容易的,但能達到提高網站的速度。
法則3. 增加Expires Header
網頁內容正變得越來越豐富,這意味著更多的腳本文件、樣式表、圖像文件和Flash。首次訪問者將不得不面臨多次HTTP請求,但通過使用Expires header,您可以在客戶端緩存這些元素。這在後續訪問中避免了不必要的HTTP請求。Expires header最常用於圖像文件,但是它也應該用於腳本文件、樣式表和
Flash。
浏覽器(和代理)使用緩存來減少HTTP請求的次數和大小,使得網頁加速裝載。Web server通過Expires header告訴客戶端一個元素可以緩存的時間長度。
如果服務器是Apache的話,您可以使用ExpiresDefault基於當期日期來設置過期日期,如:ExpiresDefault “access plus 10 years” 設置過期時間為從請求時間開始計算的10年。
請記住,如果使用超長的過期時間,則當內容改變時,您必須修改文件名稱。
法則4. 壓縮頁面元素
通過壓縮HTTP響應內容可減少頁面響應時間。從HTTP/1.1開始,web客戶端在HTTP請求中通過Accept-Encoding頭來表明支持的壓縮類型,如:Accept-Encoding: gzip, deflate.
如果Web server檢查到Accept-Encoding頭,它會使用客戶端支持的方法來壓縮HTTP響應,會設置Content-Encoding頭,如:Content-Encoding: gzip。
Gzip是目前最流行及有效的壓縮方法。其他的方式如deflate,但它效果較差,也不夠流行。通過Gzip,內容一般可減少70%。如果是Apache,在1.3版本下需使用mod_gzip 模塊,而在2.x版本下,則需使用mod_deflate。
Web server根據文件類型來決定是否壓縮。大部分網站對HTML文件進行壓縮。但對腳本文件和樣式表進行壓縮也是值得的。實際上,對包括XML和JSON在內的任務文本信息進行壓縮都是值得的。圖像文件和PDF文件不應該被壓縮,因為它們本來就是壓縮格式保存的。對它們進行壓縮,不但浪費CPU,而且還可能增加文件的大小。
因此,對盡量多的文件類型進行壓縮是一種減少頁面大小和提高用戶體驗的簡
便方法。
法則5. 把樣式表放在頭上
我們發現把樣式表移到HEAD部分可以提高界面加載速度,因此這使得頁面元素可以順序顯示。
在很多浏覽器下,如IE,把樣式表放在document的底部的問題在於它禁止了網頁內容的順序顯示。浏覽器阻止顯示以免重畫頁面元素,那用戶只能看到空白頁了。Firefox不會阻止顯示,但這意味著當樣式表下載後,有些頁面元素可能需要重畫,這導致閃爍問題。
HTM L 規范 明確要求樣式表被定義在HEAD中,因此,為避免空白屏幕或閃爍問題,最好的辦法是遵循HTML規范,把樣式表放在HEAD中。
法則6. 把腳本文件放在底部
與樣式文件一樣,我們需要注意腳本文件的位置。我們需盡量把它們放在頁面的底部,這樣一方面能順序顯示,另方面可達到最大的並行下載。
浏覽器會阻塞顯示直到樣式表下載完畢,因此我們需要把樣式表放在HEAD部分。而對於腳本來說,腳本後面內容的順序顯示將被阻塞,因此把腳本盡量放在底部意味著更多內容能被快速顯示。
腳本引起的第二個問題是它阻塞並行下載數量。 HTTP/1. 1 規范 建議浏覽器每個主機的並行下載數不超過2個。因此如果您把圖像文件分布到多台機器的話,您可以達到超過2個的並行下載。但是當腳本文件下載時,浏覽器不會啟動其他的並行下載,甚至其他主機的下載也不啟動。
在某些情況下,不是很容易就能把腳本移到底部的。如,腳本使用document.write方法來插入頁面內容。同時可能還存在域的問題。不過在很多情況下,還是有一些方法的。
一個備選方法是使用延遲腳本(deferred script)。DEFER屬性表明腳本未包含document.write,指示浏覽器刻繼續顯示。不幸的是,Firefox不支持DEFER屬性。在IE中,腳本可能被延遲執行,但不一定得到需要的長時間延遲。不過從另外角度來說,如果腳本能被延遲執行,那它就可以被放在底部了。

法則7. 避免CSS表達式

CSS表達式是功能強大的(同時也是危險的)用於動態設置CSS屬性的方式。IE,從版本5開始支持CSS表達式,如backgourd-color: expression((new Date()).getHours()%2?”#B8D4FF”:”#F08A00”),即背景色每個小時切換一次。
CSS表達式的問題是其執行次數超過大部分人的期望。不僅頁面顯示和resize時計算表達式,而且當頁面滾屏,甚至當鼠標在頁面上移動時都會重新計算表達式。
一種減少CSS表達式執行次數的方法是一次性表達式,即當第一次執行時就以明確的數值代替表達式。如果必須動態設置的話,可使用事件處理函數代替。如果您必須使用CSS表達式的話,請記住它們可能被執行上千次,從而影響頁面性能。
我們的應用:
目前CSS的維護工作主要由UI人員負責,他們已經盡量在避免這種情況了。

法則8. 把JavaScript和CSS放到外部文件中

上述很多性能優化法則都基於外部文件進行優化。現在,我們必須問一個問題:JavaScript和CSS應該包括在外部文件,還是在頁面文件中?
在現實世界中,使用外部文件會加快頁面顯示速度,因為外部文件會被浏覽器緩存。如果內置JavaScript和CSS在頁面中雖然會減少HTTP請求次數,但增大了頁面的大小。另外一方面,使用外部文件,會被浏覽器緩存,則頁面大小會減小,同時又不增加HTTP請求次數。
因此,一般來說,外部文件是更可行的方式。唯一的例外是內嵌方式對主頁更有效,如Yahoo!和My Yahoo!都使用內嵌方式。一般來說,在一個session中,主頁訪問此時較少,因此內嵌方式可以取得更快的用戶響應時間。
我們的應用:
外貿、E網打盡、K計劃:ext2的代碼作了很好的引導,目前前端開發人員都非常注意客戶端模塊的封裝、重用,盡量以外部JS的方式提高代碼的重用度,當然也要注意不要引入過多的外部資源,因為這違反了法則1。
目前CSS的封裝也不錯,但是主要是針對IE系列的解決方案,可以考慮引入YAML、blueprint等CSS框架,輕松解決浏覽器兼容性問題。

法則9. 減少DNS查詢次數

DNS用於映射主機名和IP地址,一般一次解析需要20~120毫秒。為達到更高的性能,DNS解析通常被多級別地緩存,如由ISP或局域網維護的caching server,本地機器操作系統的緩存(如windows上的DNS Client Service),浏覽器。IE的缺省DNS緩存時間為30分鐘,Firefox的缺省緩沖時間是1分鐘。
減少主機名可減少DNS查詢的次數,但可能造成並行下載數的減少。避免DNS查詢可減少響應時間,而減少並行下載數可能增加響應時間。一個可行的折中是把內容分布到至少2個,最多4個不同的主機名上。
我們的應用:
外貿:為了繞開浏覽器對下載線程數的限制,我們對靜態資源啟用了多域名,但是這麼做違反了該法則。不過,對windows IE來說,DNS的緩存可以緩解該問題。

法則10. 最小化JavaScript代碼

最小化JavaScript代碼指在JS代碼中刪除不必要的字符,從而降低下載時間。兩個流行的工具是#JSMin 和YUI Compressor。
混淆是最小化於源碼的備選方式。象最小化一樣,它通過刪除注釋和空格來減少源碼大小,同時它還可以對代碼進行混淆處理。作為混淆的一部分,函數名和變量名被替換成短的字符串,這使得代碼更緊湊,同時也更難讀,使得難於被反向工程。Dojo Compressor (ShrinkSafe)是最常見的混淆工具。
最小化是安全的、直白的過程,而混淆則更復雜,而且容易產生問題。從對美國10大網站的調查來看,通過最小化,文件可減少21%,而混淆則可減少25%。
除了最小化外部腳本文件外,內嵌的腳本代碼也應該被最小化。即使腳本根據法則4被壓縮後傳輸,最小化腳本刻減少文件大小5%或更高。
我們的應用:
我們沒有直接使用JS壓縮,但是我們用的許多組件例如ext2、jquery等,已經在為我們實踐該法則。

法則11. 避免重定向

重定向功能是通過301和302這兩個HTTP狀態碼完成的,如:
HTTP/1.1 301 Moved Permanently
Location:
' target='_blank'>http://example.com/newuri
      Content-Type: text/html

浏覽器自動重定向請求到Location指定的URL上,重定向的主要問題是降低了用戶體驗。
A已經為我們考慮了這個問題,有興趣的同學可以看看線上環境的Apache配置文件:httpd.conf。

法則12. 刪除重復的腳本文件

在一個頁面中包含重復的JS腳本文件會影響性能,即它會建立不必要的HTTP請求和額外的JS執行。
不必要的HTTP請求發生在IE下,而Firefox不會產生多余的HTTP請求。額外的JS執行,不管在IE下,還是在Firefox下,都會發生。
一個避免重復的腳本文件的方式是使用模板系統來建立腳本管理模塊。除了防止重復的腳本文件外,該模塊還可以實現依賴性檢查和增加版本號到腳本文件名中,從而實現超長的過期時間。
我們的應用:
舊版本的Xplatform中這個問題比較嚴重,不過相信新版的XCube不會重蹈覆轍。

法則13. 配置ETags

ETags是用於確定浏覽器緩存中元素是否與Web server中的元素相匹配的機制,它是比last-modified date更靈活的元素驗證機制。ETag是用於唯一表示元素版本的字符串,它需被包括在引號中。Web server首先在response中指定ETag:
HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: "10c24bc-4ab-457e1c1f"
Content-Length: 12195
後來,如果浏覽器需要驗證某元素,它使用If-None-Match頭回傳ETag給Web server,如果ETag匹配,則服務器返回304代碼,從而節省了下載時間:
GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
HTTP/1.1 304 Not Modified

ETags的問題在於它們是基於服務器唯一性的某些屬性構造的,如Apache1.3和2.x,其格式是inode-size-timestamp,而在IIS5.0和6.0下,其格式是Filetimestamp:ChangeNumber。這樣同一個元素在不同的web server上,其ETag是不一樣的。這樣在多Web server的環境下,浏覽器先從server1請求某元素,後來向server2驗證該元素,由於ETag不同,所以緩存失效,必須重新下載。
因此,如果您未用到ETags系統提供的靈活的驗證機制,最好刪除ETag。刪除ETag會減少http response及後續請求的HTTP頭的大小。微軟支持文章描述了如何刪除ETags,而在Apache下,只要在配置文件中設置FileETag none即可。
我們的應用:
E網打盡:自定義ETag的生成策略,以盡量減少探頭規則的生成次數。由於不是采用服務器默認的ETag,不存在該問題。
其他產品線:要注意了,這點大家都沒有關注過吧,趕快檢查一下Apache中的配置。

法則14. 緩存Ajax

性能優化法則同樣適用於web 2.0應用。提高Ajax的性能最重要的方式是使得其response可緩存,就象“法則3增加Expires Header”討論的那樣。以下其他法則同樣適用於Ajax,當然法則3是最有效的方式:
法則4. 壓縮頁面元素
法則9. 減少DNS查詢次數
法則10. 最小化腳本文件
法則11. 避免重定向
法則13. 配置ETags.
我們的應用:
更多情況下,我們倒不希望Ajax請求被緩存,此時為每個Ajax請求的url附加一個時間戳就可以了。
Linux內核調優參數
調優的目的:
1. 根據不同的角色調優的方法是不一樣的;
2. 找到性能瓶頸以及緩解這個瓶頸(CPU,內存,IO調度、網絡、使用的應用程序);
3. 通常做兩種調優:
response time:Web服務器,用戶感受度好
throughput:文件服務器,拷貝的速度

硬件方面,主要要調優的對象:
CPU	
Memory
Storage
Networking

內核方面參數詳解:
#接收套接字緩沖區大小的默認值(以字節為單位)。
net.core.rmem_default = 262144
#接收套接字緩沖區大小的最大值(以字節為單位)。
net.core.rmem_max = 16777216
#發送套接字緩沖區大小的默認值(以字節為單位)。
net.core.wmem_default = 262144
#發送套接字緩沖區大小的最大值(以字節為單位)。
net.core.wmem_max = 16777216
#用來限制監聽(LISTEN)隊列最大數據包的數量,超過這個數量就會導致鏈接超時或者觸發重傳機制。
net.core.somaxconn = 262144
#當網卡接收數據包的速度大於內核處理的速度時,會有一個隊列保存這些數據包。這個參數表示該隊列的最大值。
net.core.netdev_max_backlog = 262144
#表示系統中最多有多少TCP套接字不被關聯到任何一個用戶文件句柄上。如果超過這裡設置的數字,連接就會復位並輸出警告信息。這個限制僅僅是為了防止簡單的DoS攻擊。此值不能太小。
net.ipv4.tcp_max_orphans = 262144
#表示那些尚未收到客戶端確認信息的連接(SYN消息)隊列的長度,默認為1024,加大隊列長度為262144,可以容納更多等待連接的網絡連接數。
net.ipv4.tcp_max_syn_backlog = 262144
#表示系統同時保持TIME_WAIT套接字的最大數量。如果超過此數,TIME_WAIT套接字會被立刻清除並且打印警告信息。之所以要設定這個限制,純粹為了抵御那些簡單的DoS攻擊,不過,過多的TIME_WAIT套接字也會消耗服務器資源,甚至死機。
net.ipv4.tcp_max_tw_buckets = 10000
#表示允許系統打開的端口范圍。
net.ipv4.ip_local_port_range = 1024 65500
#以下兩參數可解決生產場景中大量連接的服務器中TIME_WAIT過多問題。
#表示開啟TCP連接中TIME_WAIT套接字的快速回收,默認為0,表示關閉。
net.ipv4.tcp_tw_recycle = 1
#表示允許重用TIME_WAIT狀態的套接字用於新的TCP連接,默認為0,表示關閉。
net.ipv4.tcp_tw_reuse = 1
#當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉。
net.ipv4.tcp_syncookies = 1
#表示系統允許SYN連接的重試次數。為了打開對端的連接,內核需要發送一個SYN並附帶一個回應前面一個SYN的ACK包。也就是所謂三次握手中的第二次握手。這個設置決定了內核放棄連接之前發送SYN+ACK包的數量。
net.ipv4.tcp_synack_retries = 1
#表示在內核放棄建立連接之前發送SYN包的數量。
net.ipv4.tcp_syn_retries = 1
#減少處於FIN-WAIT-2連接狀態的時間,使系統可以處理更多的連接。
net.ipv4.tcp_fin_timeout = 30
#這個參數表示當keepalive啟用時,TCP發送keepalive消息的頻度。默認是2小時,若將其設置得小一些,可以更快地清理無效的連接。
net.ipv4.tcp_keepalive_time = 600
#探測消息未獲得響應時,重發該消息的間隔時間(秒)。系統默認75秒。
net.ipv4.tcp_keepalive_intvl = 30
#在認定連接失效之前,發送多少個TCP的keepalive探測包。系統默認值是9。這個值乘以tcp_keepalive_intvl之後決定了,一個連接發送了keepalive探測包之後可以有多少時間沒有回應。
net.ipv4.tcp_keepalive_probes = 3
#確定TCP棧應該如何反映內存使用,每個值的單位都是內存頁(通常是4KB)。第一個值是內存使用的下限;第二個值是內存壓力模式開始對緩沖區使用應用壓力的上限;第三個值是內存使用的上限。在這個層次上可以將報文丟棄,從而減少對內存的使用。示例中第一個值為786432*4/1024/1024=3G,第二個值為1048576*4/1024/1024=4G,第三個值為1572864*4/1024/1024=6G。
net.ipv4.tcp_mem = 786432 1048576 1572864
#此參數限制並發未完成的異步請求數目,應該設置避免I/O子系統故障。
fs.aio-max-nr = 1048576
#該參數決定了系統中所允許的文件句柄最大數目,文件句柄設置代表linux系統中可以打開的文件的數量。
fs.file-max = 6815744
#第一列,表示每個信號集中的最大信號量數目。
#第二列,表示系統范圍內的最大信號量總數目。
#第三列,表示每個信號發生時的最大系統操作數目。
#第四列,表示系統范圍內的最大信號集總數目。
#(第一列)*(第四列)=(第二列)
kernel.sem = 250 32000 100 128
#表示盡量使用內存,減少使用磁盤swap交換分區,內存速度明顯高於磁盤一個數量級。
vm.swappiness = 0
Copyright © Linux教程網 All Rights Reserved