如何提高網站的訪問速度 - 從30秒到3秒的改變

作者:henry3 (通往牛B的路上一路狂奔)  

2006年10月份,我開始對web開發產生了興趣,並決定自己也嘗試開發一個網站。在此之前,我做過3年的java application的開發,對web開發應該算一無所知。在比較了java,php,ror,和python後,我選擇了基於python的web框架 - django 。到目前爲止,我還認爲這是一個明智的決定。Django高效的開發效率讓我僅僅用一個月的業餘時間,就基本完成了網站的開發。這是一個網絡書籤的網站,我加上了一些有意思的特性,讓網站顯得有些與衆不同。

我購買了域名和Dreamhost 的主機空間。Dreamhost支持django,並且第一年的費用只有180元人民幣。2006年11月份,http://www.hpbookmarks.com 上線了。網友們發來了善意的評論,“很有創意”,“點意思”,“一些feature很不錯”。同時,還有一個非常一致的意見就是,“訪問速度太慢了”。其實,當時的情況不只是訪問速度慢,而且是相當不穩定。很多時候是幾個小時網站無法訪問。當時,我並沒有在意,因爲我有兩個自以爲“合理”的解釋。第一,我用的是國外最便宜的虛擬主機,國內訪問慢是很正常的。第二,django的還處於0.95的狀態,效率和穩定性方面有問題也正常。

但是,我慢慢發現上面的解釋不過是自己騙自己的藉口。很多用dreamhost的網站,訪問起來也很快。而且django也已經被成功應用在許多大型的網站。我開始認真考慮提高網站速度的問題了。畢竟,速度慢的網站很可能在第一次就失去的用戶,他們可以永遠不會再來了。終於,我進行了下面一步一步的優化工作,並且取得了一個看起來還不錯的結果。

第一步,用Ajax提高用戶體驗

由於我的網站上鍊接字體的大小是根據點擊次數決定,所以每次點擊都要提交到服務器端並記錄次數,再在客戶端打開網站鏈接。這在localhost測試的時候沒有發現問題,但是部署到服務器上,會感到明顯的等待。解決辦法就是用Ajax。用戶點擊網站鏈接後就直接打開,再通過Ajax將點擊的事件提交到服務器端記錄。這樣用戶感覺不到任何延時。

第二步,將邏輯移到客戶端的javascript中

在開始的時候,“網站標籤高亮”和“手氣不錯”的功能都是提交到服務器端操作,然後返回結果的。後來,我發現其實很多邏輯是可以移到客戶端,由 javascript來實現的。Javascript非常強大,可以完成很多複雜的邏輯。將邏輯移到客戶端的javascript中,可以很有效的減少和服務器通訊的次數,獲得更好的訪問速度。

第三步,解決進程的<defunct>

由於採用的是fastCGI的方式,我配置了django.fcgi。可是,我發現系統進程中,有大量的django.fcgi進程被標記爲< defunct>(失去功能)。這些<defunct>進程會導致服務器有時無法正常訪問。我開始嘗試用命令來kill掉這些進程,但是很快發現這無法從根本上解決問題。後來,我看到一個老外在blog上提到一個解決方案,將django.fcgi改名爲dispatch.fcgi。原來,dispatch.fcgi是一個dreamhost的系統進程,它的健壯性是可以得到保障的。果然,我將django.fcgi改名爲 dispatch.fcgi後,<defunct>的現象再沒有出現。

第四步,優化SQL語句

SQL語句的執行通常也是一個很花費時間的操作。經過檢查,我發現我的一條SQL語句,是一個嵌套三層的子表查詢。而這條SQL還必須是一個Raw SQL,即不能採用django的OR Maping。這意味着不能被cache緩存,每次都是真刀真槍的執行。更失敗的是,經過我的分析,這條SQL完全可以不執行。這是一次設計上的失誤,標
準的over design(過渡設計)。當時,我是想通過數據庫得到一個最精確的統計值。後來發現,這個值完全可以用一個近似的常量代替。優化SQL,尤其是避免不必要的SQL執行,帶來的效果是非常明顯的。

第五步,儘量減少頁面大小

隨着添加網站越來越多,有一天我發現django生成的首頁已經達到了80k。我很清楚這是一個非常不能被接受的數字。我開始檢查頁面,很快發現了線索。第一,因爲偷懶,頁面中很多layout是用空格(&nbsp;)實現的。第二,因爲爲了增加代碼可讀行,調試方便,每行生成的頁面都增加換行符 (/n)。第三,最糟糕的是,大量的用了
inline css。就是將css style直接嵌入標記塊中。於是,我立即動手,用css的align解決layout,去掉/n,將inline css抽象到獨立的css文件中。這樣下來,在不更改任何內容的情況下,80k變成了57k。

第六步,用gzip進行頁面壓縮

當我興高采烈的把頁面優化結果貼到了smth bbs上,卻被直接潑了盆涼水。原來百分之二十幾的優化結果,實在太一般了。ylsdd給我了一個很重要的線索,deflate。原來apache的 deflate模塊可以把文件進行gzip壓縮,壓縮後的文件傳到瀏覽器後再被解壓。主流的瀏覽器都支持這種gzip的解壓操作。於是,我在apache 的配置文
件中加入了Add OutputFilter DEFAULT html css js的語句。經過測試,css,js這些文本文件的壓縮後都只有原來尺寸的25%。這裏,和大家分享一個網站http://www.port80software.com/products/httpzip/compresscheck 它的作用是檢測你的網站是否被壓縮,以及壓縮比率等。

第七步,迴歸靜態頁面

新的問題又來了。原來deflate只支持靜態文件的壓縮。而我的首頁是django動態生成的,deflate模塊沒有進行壓縮。我突然想到,網站的首頁爲什麼不能是靜態頁面呢?於是,我增加了一個runtime的api,這個api提供的是和原來一樣由django動態生成的頁面。我又寫了一個 python的程序,通過urllib2模塊下載這個動態生成的頁面,並保存爲index.html。我將網站的root映射到index.html這個靜態頁面。最後,通過linux crontab定義一個行爲,每五分鐘執行一下這個python程序,生成新的index.html。值得一提的是,由於網絡原因,python程序不一定每次都能準確完整的下載動態生成的頁面。所以我們必須再進行一個校驗算法。當頁面大小要超過一定數字,頁面中出現某個校驗字符串的情況下,才保存 index.html。這樣,每次用戶提交的訪問,不是由服務器端動態生成頁面,極大的節省了服務器端的開銷。而靜態頁面又可以有效的被deflate壓縮。最後結果,首頁被壓縮爲13k,爲原來的22%。唯一的區別就是,新提交和推薦的網站不能立即出現在首頁。但是我認爲,這應該是可以被接受的。

至此,網站的優化工作基本完成。網站的訪問速度從原來30秒以上,縮短到3秒左右,應該說算是一個飛躍。雖然,3秒的速度也不是非常快,但是,考慮到虛擬主機等客觀原因,這個結果我還是滿意的。原來感覺我的網站很慢的朋友們,也可以再試試。

以上的優化方案出自我的個人經驗,並不一定適合所有網站。但是,它告訴我們一個事實。影響網站訪問速度的不僅僅是服務器配置,網絡帶寬。也許,你糟糕的設計,低效率的方案也是致命的因素。應當注意的是,優化工作也不能匆匆上手。一定要仔細研究,具體情況具體分析,得到統計數據,找到真正的問題所在,再開始優化。相信自己,提高網站的訪問速度並不是不可能。畢竟,Nothing is Impossible。祝大家成功。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章