###################################
方法與觀念的改變
###################################
錯誤導向:
我在網上會看到人們怎麼優化網站,就是用yslow這樣的工具來看,工具會告訴你要怎麼做,哪方面有問題,比如我寫在文檔裡面的像這樣的:
這裡會告訴你要開啟壓縮。
這裡大致反映出時間。
這些做法做都是正確的。只是這種都是花俏的工夫。把這些當成是優化的方向,方向不對。著力點錯了。結果發現網站速度沒明顯改善。因為方法錯誤了。基本是這種想法:先按照上面說的,把該做的做了吧。肯定有提高的。始終沒嘗試找網站速度慢的瓶頸在哪裡?
同學總結得很恰到:這些工夫無非是合並多個js,css文件。該壓縮的壓縮。能少占用帶寬資源。但是都非關鍵點。去優化關鍵點,留到後面優化。
什麼是瓶頸?
我以前沒想到比較通俗的方式解釋。通俗點,就是瓶口的大小。瓶子的口子大小就那麼多,已經決定了一次只能進那麼多量。假如發現一個方面就是限制最大的因素。把這個主要矛盾解決就ok了。假如數據庫是瓶頸就解決這個問題,假如磁盤速度是瓶頸著力點就解決這個。
一個形象的比方:一個木桶,有一塊最短的木板,就算把其他板塊加的再高,整體裝水不會多。木桶的瓶頸就是最短的這一塊。
技術上的例子:cpu用得再好,把二核的改為四核,php腳本速度提得再高(裝代碼加速器,去掉一些模塊),apache性能再好,內存提到到8g。數據庫優化到再牛逼。網絡口子就那麼多大,距離這麼遠,傳遞的數據量有限。就算你apache在0.01秒就能丟給數據給浏覽器。但是網絡影響,要請求圖片,css文件速度怎麼都快不了的。網絡是我們目前的瓶頸。cpu速度,內存等等目前都不是木桶的短板。優化在快也改善不了本質問題啊。
一根水管的管道就那麼點大,即使你在怎麼提高優化其他方面的,雖然有好處。但是仍然沒有明顯改善。
性能與優化的分析方法:主次矛盾。技術上就是說找到瓶頸所在。把瓶頸突破,其他問題都不會成為障礙了,整體就能達到預期目標。
我親身經歷的一個例子:技術經理是79年的。其實我們的網站訪問速度還不錯。而老板看到同行的網站網站怎麼快些。(人家才多少個技術,我們這麼多。應該要達到)。
技術經理把一些方法都嘗試了:研究同行的no-cache頭,唉,他們的怎麼有,而我們的沒有。好,我們也要像他們那樣做。我們還把代碼片段給緩存起來,花了不少時間。可惜,結果速度沒有明顯提高。有,也只是根據感覺:“哦,我剛才加了緩存控制後,發現服務器的負載低了點。但是怎麼又變高了呢。”。“我已經開啟了壓縮,怎麼沒明顯改善呢?”,其實,加服務器緩存控制,代碼判斷緩存。肯定是有效果的。但能提高多少?或者說目前這個不算瓶頸。就算你把其他的優化得再好。也沒提高整體。沒找到瓶頸所在,結果各自方法都試過了。還是沒用。白忙活。如果一開始能夠分析出瓶頸。著力點完全不同。
因為不是專業的運維人員,所以,我們不知道怎麼去分析性能瓶頸。只是根據感覺,這樣做可以提高點性能。先這樣做吧。
discuz的人說,“(技術經驗)價值連城”。我現在確實有這種感覺,經驗就是財富。別人與你非親非故,干嘛要把經驗告訴你呢?我們能看到的僅僅是網上的資料,書籍。這些我發現要形成自己的經驗才是關鍵。比如,大部分建議要apache開啟壓縮,合並js,css文件。基本上是參照國外人的這本書,我看過:《高性能網站建設指南》。
這上面說的這些都是正確的做法。
由於沒人傳遞一個分析方法。所以,一遇到網站性能問題,往往是先參照網上的,書籍的建議,把基本點做了。然後在考慮對策。比如我經理,仍然是憑著感覺去嘗試各種方法。如果一開始就能夠分析出瓶頸所在。就不會無效果了。他不是專業的運維,確實也沒這方面的分析經驗。只能是瞎耗費時間了。試10個方法都不會有突破。
我現在發現,這些都是一些小技巧。談不上解決瓶頸問題。書的標題就寫明了,針對前端工程師的。如果你按照上面的各種方法:壓縮js,壓縮css。控制緩存。發現自己網站的速度卻沒明顯改善。可能此時你網站的瓶頸在於數據庫或者說是帶寬,這方面瓶頸沒找到,或者不解決,一直感覺不到整體提高。
有些人會告訴我:先把基本點,也就是能做得做了吧。然後在考慮其他提高。這其實是道理。
我發現以前我真是這樣的。壓根就是沒有分析瓶頸的一種導向。比如,網站速度很慢,你說,我先把基本點做好:cpu,數據庫優化,內存。可惜這些都不是瓶頸。做了確實比不做好。但對問題沒效果。
後來發現:做有些事情,確實是要先把基本點做了。然後再去考慮。而有些事情,基本點做了根本影響不大。因為不是瓶頸。找到主要矛盾解決,其他的都不算問題,在慢慢優化。
誰都知道做了那些基本點有好處(看書,網上資料),但是有經驗的人才會告訴你真實的答案。我經理79年,做了至少8年技術。對於分析瓶頸方面並沒有經驗,只能是各種方式試一下.不見效果。
曾看過阿裡巴巴的簡朝陽的《myql性能調優與架構設計》,裡面分析優化sql,一個思想讓我印象深刻:分析一條sql,先分析出瓶頸所在。這樣能確定一個預期優化目標。如果沒分析清楚,感覺這樣能夠提高點。就把各種方式都嘗試了。結果還是沒優化。
我以前還真是這樣的:拿到一條sql要優化,我就憑著感覺,這樣做會好點,哪怕是能夠改善0.001s的速度都行。先這樣嘗試吧。然後沒明顯改善,又去用其他方式嘗試。如果這樣改寫下去,幾十次都沒達到速度提高。嘗試得頭暈都不會有改善。或者改善了也是碰對了。
比如說:拿到group by,反正根據網上group by如何優化,試一下。其實如果搞清楚group by的原理,對比一下查詢的數據量。發現它根本不是sql的瓶頸所在。嘗試了等於是浪費時間。
我注意到,合並js,壓縮是對的,但網易並沒這麼多,它的js文件內容我打開看,還是原始狀態的:
網易服務器雖然n多,性能非常好,帶寬雖然多。合並,壓縮js和css都是正確的做法,能提高速度,而他干嘛不做?如果一個事情是一個關鍵點,他們必須會做的。結論是,他們明白這個根本不是網站的瓶頸所在。糾結這些還不如去糾結關鍵點。
有些大網站,確實也對js,css壓縮合並了。合並js,css確實能夠提高。有好處。但我還從沒見過靠這種方式把網站速度達到一個質的提高。他們是:先把瓶頸突破,其他基本點後面在做,到時候可以做可不做。影響不明顯。
常常碰到這種的方向錯誤:
比如,數據庫去優化,修改字段之類的。雖然能夠提到速度,但是在數據量這麼小的情況下,竟然速度訪問慢。數據庫肯定不是瓶頸,這方面的改善無法都無法解決根本問題.結果速度還是慢。
比如,網上一直流傳php的代碼性能差異之比
例子1:
echo $a.$b.c;
有人認為這樣寫性能更高(確實是,省去了符號.進行逐次解析):
echo $a,$b,$c;
例子2:
echo "this is {$tile}"
優化成:'this is'.$title;//把變量放在""符號之外,是可以省去解析時間
無法說上面的優化是錯誤的,而且確實要承認那樣去優化性能會更高。但是真的要問,到底性能高多少呢?高0.0001s,這種優化有改善,但意義多大?
這種優化壓根就談不上瓶頸。假如:php把10萬條數據一次讀入到內存,發現卡死了。這就是php代碼處理的瓶頸(實質上是內存問題),此時優化代碼邏輯就可以解決根本問題。少操作些數據ok。想把內存提高不靠譜。
糾結,細扣一些花俏,影響不關鍵的方面。總不會有多大改善的。網上經常提到那種,php代碼優化的10個方法。人人奉為圭臬。扣得太細了。當瓶頸不在這裡的時候,優化不了多少。
php代碼的這種優化,我以前也是去糾結過。但是後來發現,沒有找到瓶頸所在,所做的工夫都是白費的。
別人其實也犯這種錯誤。
我遇到這樣一個例子:我以前上面分配一個優化後台某項統計數據的查詢。但是因為不懂得抓瓶頸問題。沒有明確的方向,我大體方向只是在優化sql查詢上做改善。其實方向是對的。瓶頸確實是在數據庫方面。但數據結構設計,再好硬件,sql優化再好,統計查詢都快不起來。
折騰了很久,同排一同事想幫助我,他的方向完全不同,他的著手點也是改善php代碼:他把php處理的循環方式改善一下,比如原來是怎麼循環的,改成另外一種循環方式。其他代碼也進行改善代碼。
其實通過這個事情,我發現沒有理解瓶頸所在,就在那個時候我明白了:同學告訴我,php的處理速度已經非常快了。整體看執行時間慢,它是一直在等待數據庫給予數據。所以腳本就很慢了。所以那麼大的數據查詢統計,也許像上面例子那樣去改善,糾結一些次要的東西。無論怎麼優化代碼,都解決不了統計查詢速度慢的問題。著力點要搞清楚為好。
服務器的php程序執行速度非常快,執行完後就發送數據了。服務器在美國,假如在中國訪問,距離這麼遠,再快也快不到哪裡去的。
也許就有疑惑了。這個網站也是在美國:http://digg.com/
怎麼訪問速度那麼快?
這個網站他肯定在中國部署了服務器的。比如阿裡巴巴想保證全國各地的用戶都能訪問他網站。他如果把服務器全部放在杭州,或者全部放在北京。南方的人訪問,光是距離也要那麼遠。根本不會有現在這個速度。所以,距離如果遠:服務器本身性能再高,速度也快不到哪裡去。所以先把腳本的執行時間統計出來,這樣便於確定服務器消耗。
ps:有那些cdn加速服務需求,單雙線機房之分。就是通過解決距離遠,時間延遲上的問題。
我在英國,訪問美國服務器。能快起來嗎?
看這個博客:blog.strabbit.com,服務器是美國的一個vps。看在中國訪問速度如何?
網站的訪問速度是一個多方面導致的因素。
我首先會去判斷程序執行的性能方面。做一個嚴格的執行時間統計。這麼做的作用是:確定瓶頸在數據庫響應數據,還是在程序執行性能, 還是在網絡帶寬因素?
我放一個統計腳本也是想統計出程序每次執行的准確時間。
統計的機制是這樣:
在程序執行開始執行時記錄一個時間,結束的時候定一個時間。結束時間減去開始時間。就是php腳本所執行的時間了。在並發訪問不多的情況下,腳本的執行時間會在穩定范圍內。
這樣做也是根據一次請求執行的原理來的:
1、浏覽器進行http請求
2、apache處理:
if(請求的為php腳本)
{
apache丟給php引擎處理
php執行生成html給apache,nginx等服務器》》
}
else
{
圖片,靜態html頁面,js等靜態內容.
直接從磁盤讀取文件結果給浏覽器
}
3、apache將html結果通過網絡發給浏覽器。浏覽器解析html,渲染出結果給用戶看。
把這個過程搞清楚了。定位問題就不會錯誤去估計:統計出php腳本時間。就明白apache多久才從php拿到html結果。
php程序的總時間大體反映出了:php向mysql獲取時間,和本身執行所花費的時間。
我注意過一點:php連接mysql請求數據。如果mysql負載高,響應不過來。那麼php程序就會處於一直等待mysql返回數據狀況(這就是時間耗費,常常導致在浏覽器請求頁面的時候速度很慢)。
所以,為什麼首先要統計出php的執行總時間了。假如:我請求index.php頁面,統計出php的腳本執行時間才0.05s(秒)。但是偏偏在浏覽器訪問的時候,發現速度慢的不行,一直看不到結果啊。根據上面的http請求過程和apache,php之間的關系。php腳本生成html結果早就給apache了(這個時候已經完全脫離php處理,php處理引擎任務完成,我只負責查詢數據庫最後生成html而已。執行到這裡的時候如果速度快.已經脫開數據庫性能,php腳本性能了)。
而index.php返回的html內容中可能包含其他http請求。像這樣的元素:
<scritp type="text/javascript" src="jquery.js"></script>,
<img src="http://piwik.shophairextensions.co.uk/piwik.php?idsite=1" alt="" />
<link rel="stylesheet" type="text/css" href="http://www.shophairextensions.co.uk/media/css/454f62d8439826741663bd9757fc0d3d.css" media="all" />
浏覽器渲染apahce返回的html結果後,如果遇到像上面的標簽,浏覽器就會繼續像服務器請求文件。
html結果早就能得到了。而我們看不到結果,因為數據沒有傳送完畢,服務器已經完成他該處理的事情了(處理完正在發送數據了)。網絡狀況的話,與服務器性能有什麼關系?所以經常發現這樣的情況:
圖一
圖二
浏覽器請求的時候,左下角一直顯示“正在傳送數據“。其實此時php解析早就完成了(此時稍微注意,偶爾查看浏覽器源碼。往往發現能夠看到html結果了,前提是html通過網絡已經完全傳到浏覽器端了)。或許網絡原因,一直停留在服務器與客戶端發送數據過程耗費時間。
如果顯示"正在等待響應....",那說明服務器還沒有給數據給浏覽器。可以做個試驗:
用個php文件,代碼裡面循環10萬次。看浏覽器怎麼反應
for($i=0;$i<100000;$i++){
for($j=0;$j<200;$i++){
}
}
搞清楚http請求的過程,定位就容易點。
第二張圖片:一直沒看到結果。頁面一片空白。能說是服務器性能不夠好嗎?能說瓶頸是要優化php腳本嗎?其實這個時候也已經生成好html了。服務器正在給客戶端發送數據,網絡原因,延遲。
浏覽器左下角:有時候顯示的是正在連接網站,可以分析出的意思不同。我常常遇到數據庫大數據量的時候,一條sql查詢了很久,響應出現問題,所以php就一直在等待數據。那麼apache,nginx根本沒得到php的處理結果(也就是說php腳本耗費時間太多,根本沒執行完)。此時在浏覽器看到是”正在服務器等待響應"。
腳本的執行時間大體上是固定的變化不會太多。所以能夠通過在php的開始的和結束的定時間參考php腳本的執行性能。
但並發訪問越多,腳本的處理速度就越會受到影響:
php腳本的執行時間統計往往能夠定位腳本處理,數據庫性能方面問題。比如,並發訪問大的情況下,假如1000個並發(如同時在0.001秒刻進行訪問,網站用戶多的時候,這種情況經常碰到,測試時是通過壓力測試工具才模擬得出來)。
運維常常設定一個類似於這樣的預期目標:模擬在10000並發的情況下,看看服務器負載情況,腳本響應時間要控制1s之內。而在浏覽器要保證2s以內看到整個頁面(頁面的附帶請求忽略掉)
##########################################
分析結果
##########################################
對浏覽器http請求,apache處理,php,mysql之間的關系越了解就越能確定原因所在。
注意到沒有:hairextensionsclipon.com,ebesthair.com這兩個網站都是加了php代碼加速器的.平均每次頁面的執行的時間是0.2-0.8s之間。但是如果發現,在
浏覽器是等待了4-5秒才完整顯示出結果的話。
就把這5秒減去0.8s。就能知道時間花費在哪裡了!能夠大致預估的。
可以做一個試驗:把首頁保存成一個靜態html文件。放到服務器上。然後在中國直接訪問這個靜態html。
這樣做的依據:靜態html是完全不需要php解析,數據庫消耗,這就可以把解析時間排除掉(我做php統計執行速度也是想做參考)。apache拿到靜態內容直接發給了浏覽器。所以可以完全測試出網絡傳輸速度如何!
要逼真的模擬,可以這樣做:打開首頁》》查看浏覽器源碼。把源碼保存起來成一個html文件。
這樣做的好處是,這個靜態頁面,其中也就包括一些js,css,圖片的加載。完全逼真模擬。
我們常常看到:訪問一個網站。浏覽器已經顯示出html效果了。但是布局卻是亂的(沒有css效果的那種,實際上就是css文件沒加載完)。或者圖片位置是空的。
往往需要等上一段時間頁面布局正常。什麼原因?
這裡能夠確定:html頁面結構(一個完整的html代碼,並不包括src屬性要載入圖片和js文件內容,style標簽要載入的css文件等)已經通過網絡完全發送到達浏覽器。浏覽器已經正常的解析了!只是style標簽要載入的css文件還沒達到而已。網絡速度延遲了。php要做的事情就是上面這一步:它給apache的結果就是html,apache會發給浏覽器解析,浏覽器解析才看到了最終的效果(所以js文件,css文件只要已經網絡傳輸到浏覽器端,執行都是耗費客戶端內存,cpu資源了)。
根據浏覽器的解析原理:比如訪問首頁,浏覽器拿到apache發給它完整的html代碼。才會進行解析,渲染出頁面的基本結構。是先渲染出整體結構,然後才會去加載頁面中需要的css文件,圖片,js文件。
所以這裡就裡問題就出來了:即使你網站的處理速度快到0.1s。但是帶寬不行,或者我這邊網絡速度慢,仍然會出現,浏覽器一直顯示“正在在傳送數據”。這個時候說明,php早就已經生成html結果給浏覽器了。通過觀看浏覽器的表象就能大致確定哪一段才是瓶頸所在了。比如,我曾經遇到下面情況就不是網絡原因:
在浏覽器訪問一個自己寫的php腳本,該腳本要對一個數據庫的數據進行更新。數據量太大了,php執行時間很長。浏覽器會一直顯示,正在等待響應,這個時候,連數據都沒傳遞到浏覽器。就是因為:php一直沒處理完,沒有給apache結果,apache也就一直等待中了。
我的建議是,apache緩存控制,js,css壓縮都是可以做的,這些確實可以占有網絡資源.但是這個放在後期去做。因為就像木桶一樣,你再怎麼做其他方面,忽視短板是無法提高的。結果速度還是慢。不信可以嘗試.現在你再怎麼提高,都突破不了網絡的限制。帶寬只有那麼多。如果在中國訪問,這麼遠,怎麼都快不了。
我觀察和分析了幾天,瓶頸就是:網絡原因(包括了帶寬,距離遠訪問)。網絡的速度最終影響了數據達到客戶端的耗時。
硬件:包括cpu,內存方面不是瓶頸。即便弄台獨立服務器也是一樣的.
數據庫:幾百萬條數據,如果是查詢單條商品都是0.00x秒級別的(因為是索引關聯速度很快)。我們才幾百條商品數據,數據量小的可憐.查詢慢不到哪裡。分析認為不是瓶頸。
程序:magento往往給人一種運行速度慢得像烏龜的印象。所以會錯誤認為這是瓶頸。把模塊優化一下。magento在本地電腦確實慢,統計的時候執行了5s-6s。但是pc機子與服務器硬件配置上是不同的:
其實,cpu的處理速度很快,內存的速度已經非常快了。一般性能最大瓶頸就是i/0能力(磁盤,這也就是為什麼需要memcached之類的東西)。磁盤的讀取數據快慢起到決定作用,延遲.尤其是大訪問,並發訪問的時候影響就更明顯了。服務器的硬盤轉度比pc快很多。一般為10000轉/分鐘-15000/分鐘。pc機一般5400/分。轉速越快,i/0能力就越好,給用戶反應就是拿數據越快.
所以,統計發現,magento放到服務器上,往往執行時間很短了.雖然服務器的cput,內存比pc機都要配置高。但並不是因為cpu,內存的緣故而速度快.
注意到沒有,加了代碼加速器腳本執行時間很短了.包括查詢數據庫到最後給html給apache。總時間不超過1s(有時為0.2s)。如果再優化確實有空間。但為後期做的事情。不是解決速度的瓶頸。
方案:
一,主機距離部署近點訪問客戶所在國家。針對英國客戶為主的,購買主機就一定要部署在該國。部署在美國怎麼訪問都快不了。浪費財力。
我們訪問digg.com,其雖然在美國,但是速度快。那肯定是在中國附近部署的服務器(cdn加速服務)。很多國外網站是在新加坡部署。
二,提高帶寬資源。向空間服務商加錢就可以加帶寬。
關於這點,如果主機部署較遠,即使你帶寬再多,恐怕不會快到哪裡去:
國與國之間的網絡肯定要比本國內各個省份之間的網絡繁忙得多。畢竟是一國所有向外數據的通道。比如中國與美國網絡通信,是通過東部海底光纜聯系的。意味著整個中國通向美國的數據訪問都是經過同一道線路的。
三、服務器在美國,美國人也訪問慢的話。與這種情況類似:假如在南方城市長沙,訪問服務器在北京的網站。速度慢往往是距離遠的導致傳輸數據時間變長導
致的。因為在並發量不大的情況下(我們網站的並發訪問量小之又小),php腳本執行的的時間是穩定的范圍.所以,與服務器性能關系不大.
如果考慮購買cdn(內容分發)加速。在臨近用戶訪問地部署節點,圖片,css,js進行。雖然有效。但經過綜合權衡,問過一個有經驗朋友,這樣做還不如把錢投入到帶
寬增加上。這樣花錢也花在刀刃上為好。
附:總結的測試網絡帶寬速度的技巧
一、看ping值。快的一般是幾十毫秒。
二、丟一個文件,靜態文件,放到服務器上。打開浏覽器訪問,看下載時間。
比如,放一個100m的文件放到vps上,直接下載,看每秒多少k的速度。
一般一個網頁預算200k。按照每秒多少k計算,就能確定一個網頁網絡達到客戶端需要多長時間。實際中是要加上服務器腳本的執行時間。
三,因為我在中國,訪問美國的vps肯定受到網絡距離的影響較大。假如客戶是美國人,如果想測試美國人訪問自己的vps速度如何。通過一些工具網站的測試工具往往不靠譜.一要保證該網站與vps在同一國.不能工具網站在加拿大,而訪問美國的vps.跨國了,這種方式無法得到真實可靠的數據.
可以准確測試的方式:登錄到所在某國所在電腦的遠程桌面,然後在遠程桌面上訪問vps上的網站,看用了多長時間.
或者:一台服務器在a國,取一台a國所在的另外一台vps,在vps上寫一個php腳本去vps上下載數據,統計時間長短.也可以使用shell命令,wgets,會告訴你網頁傳輸總時間。