網站性能越來越差怎么辦?
作者:晉城網站建設 日期:2012-02-16
又是新的一年,在此建站學全體編輯人員提前給您拜年了
新的一年里你的老板或客戶是否曾和你抱怨公司的網站性能愈來愈差?網站開發很多人都會的,現在的社會技術人員是不缺的,但同樣的一個畫面,背后的性能卻可能是天差地遠,更惶論多人同時上線的企業網站,而程序員的身價也因此有所差別。本文提供一些改善網站性能的點子,從硬件、軟件、程序技巧的層面都有,也歡迎大家分享自己的經驗或秘技。
(1) 重新調整或重新設計 DB schema、索引 (index)
一個在線系統的性能不佳,主要原因都是來自于數據庫規劃及 SQL 語句層面,至于 .NET 程序撰寫不良都還在其次。
先將數據庫適度地做正規化,如:一個 Table 中,避免把常用的字段、很少用的字段,都塞在同一個表中,而影響數據掃描的速度。
應該將很少用的字段,另切割出來成為另一個表。
----------------------------------------------
(2) 改寫 SQL 語句,注意 index 是否在查詢時有真的被用到
* 同樣的功能,一個不良的「關聯子查詢」和良好的「獨立子查詢」,之間的 SQL 性能差距,是不到一秒鐘和好幾分鐘以上的差距。
* 一些 SQL 關鍵詞,只要一出現在 SQL 語句中,就可能造成表的「索引 (index)」完全失效或部分失效,變成要整個表去逐行逐列地掃描,
例如: NOT、NOT IN、!=、<>、OR ...等關鍵詞,
還有「LIKE '%關鍵詞'」的模糊查詢,也會造成索引失效,但「LIKE '關鍵詞%'」就不會造成索引失效。
----------------------------------------------
(3) 使用 Native 的 DataProvider
放棄 OleDb,改用 ADO.NET Native 的 DataProvider,如: SqlClient、OracleClient。但若您公司堅持要用 Sybase 這種從 2003 年之后,就不曾更新 DB driver 的數據庫,就只好繼續用性能不佳的 OleDb 去聯機了。
據版工我用 Visual Studio 內建的 stress test 工具,測試 OleDb 和 SqlClient 的性能差距,模擬 30 人同時上線,用瀏覽器擷取一萬筆數據,兩者的速度就差了一秒鐘;且當數據庫的數據越多,或越多人同時上線時,性能差距會更明顯。
----------------------------------------------
(4) 用程序或軟件做緩存
用程序做緩存,如 ASP.NET 從 1.x 時代,就已內建的 Cache (緩存) 機制;或用一些第三方的輔助軟件、Framework,這方面若有其它網友知道好用的軟件,亦懇請留言告知。
----------------------------------------------
(5) 用硬件做快取或緩沖、砸錢加裝 AP Server
ITHome - 游戲基地網頁效能提升的關鍵人物
以下引用自原文:
種種缺失使得網站的使用人數銳減。面對網站一堆問題,陳xx也決定要將網站再次大幅度調整,將之前的網頁程序,以及 SQL 查詢語句全部重寫,他們花了三個月的時間執行。
陳xx還在原本的網頁服務器,與數據庫服務器的架構中,加入一組應用程序服務器,作為網頁服務器 cache 數據的來源。
改版之后的新網站,搜尋速度提升許多,先前每日的統計數據中,處理速度超過 3 秒的數據超過 50 萬筆;而改版后,每星期超過 3 秒的查詢不到 10 筆,而這少數反應速度不夠快的查詢,也多是內部作業執行大量批處理導致的。
由于原本使用的 L4 Switch 較為老舊,負載量比較差,因此陳xx選擇將它汰換新的設備,加強負載量;恰好那時正好準備將應用服務器的架構上線,就藉此機會將網絡架構更新。陳xx說,這樣的架構搭配負載較強的 L4 交換器,強化網站的處理性能,并憑借此抵御網絡攻擊。在此之后,網站依然會受到零星攻擊,但都不會對造成太大影響。
----------------------------------------------
(6) 用硬件做快取或緩沖、砸錢加裝 AP Server
數字之墻 - 網站外銷的個人實踐(二)運營
以下引用自原文:
全盛時期,來自美國 blog 的流量每天達 80 萬次。這個數字其實不高,對程序高手來說是小菜一碟,但筆者是半吊子工程師,知識有限也因此可能程序寫得不好,頻頻被主機供貨商發信警告,要求改善網站系統性能。最后,我決定開發 cache system。
cache system 緩存系統上線后,將數據庫讀寫,從每天 80 萬次降低到每天 16 萬次。這期間也請高手朋友幫忙進行數據庫結構優化,幫助很大。筆者在過程中學習到,一個良好的「緩存系統 (cache system)」對于提供 Widget 功能的網站來說非常重要。
…中間略…
能夠做到隨時搬遷整個網站到另一家主機供貨商,除了程序本身的調整外,還要歸功于網站管理軟件的盛行。在此要推薦的一套稱為 Plesk 的網站管理軟件。有的主機供貨商會直接幫你安裝 Plesk ,免費或另外付費。 Plesk 的所有管理功能都是透過 Web 界面,方便到無以復加,大大降低對技術能力的要求。
除了 Plesk 以外,網站管理軟件還有其它選擇。還有 WHM 加上 cPanel 的組合,也是常見的網站管理解決方案。不過筆者還是比較偏好使用 Plesk,畢竟使用起來容易,也難怪他們的市場占有率一直是獨大。只是,功力高的工程師可能會喜歡 WHM + cPanel,因為彈性比較大。不論選擇哪一種,都可以幫助你節省許多時間。
----------------------------------------------
(7) 加裝實體機器做 Loading Balance (負載平衡)。一些 Server OS 亦內建此類設定功能。
----------------------------------------------
(8) 程序技巧 - ADO.NET
能用 DataReader 就不要用 DataSet / DataTable,前者讀取速度快又不耗內存;后者雖較有彈性,但速度較慢又會每個使用者消耗許多內存。若您連 DropDownList 控件的數據來源,都用 SqlDataSource 控件的默認值 - DataSet,則當頁面里塞了一堆下拉選單時,性能當然會受影響。
但前提是程序員對 ADO.NET 要有一定程度的了解,若只會用 Visual Studio 透過圖形界面,拖拉 TableAdapter、DataTable、.xsd 就免談了。
若為 DataTable 建立 Primary Key,DataTable 會建立一個索引,追蹤新增到 DataTable 中的數據是否符合此條件約束 (constraint)。ADO.NET 2.0 會使用 algorithm 的「紅黑樹算法 (Red-Black Tree,是一種「平衡樹」算法) 去處理索引,讓 DataTable 的數據量大時,較方便維護索引;但缺點是建立索引時會降低一些性能。
此外,數據庫的訪問和撈值,應該盡量在一次 DB connection 做完,一個 connection 可搭配多個 DbCommand 對象使用,不用每次都一個 DbConnection 配一個 DbCommand。
----------------------------------------------
(9) 程序技巧 - .NET 語法
* 避免一些書上教的,把 DataTable 或大量數據,直接塞進 Session 里,此舉在真正要上線的系統必死無疑。Session 在多人同時上線時,內存的消耗是很可觀的,因為 Session 是每個用戶各存一份在服務器的內存里,而非像「緩存 (cache)」是所有的用戶共享服務器的一塊內存。在很多 ASP.NET 的需求中,可用 HiddenField 控件或 ViewState 取代 Session。
* 能用「泛型 (Generics)」就不要用舊版的寫法,Generics 除了安全外,亦可避免 .NET 類型在 Boxing / Unboxing 轉型時影響性能,例如:
能用 List<string> 就不要用舊的 ArrayList,能用 Dictionary<TKey,TValue> 就不要用 Hashtable 或跑雙層的循環 (loop),因 ArrayList、Hashtable 的 element 屬于 object 類,在存儲或檢索如 int 等「值類型 (Value Type)」時,會引發 Boxing / Unboxing。
在大多數的情況下,List、Dictionary 等泛型類,擁有較佳的效率,而且是類型安全的。
當然上述前提,是系統要用 .NET 開發,還在靠 ASP 或非 OOP 語言硬撐的舊系統就免談了。
----------------------------------------------
(10) 程序技巧 - 數據庫「事務 (Transaction)」
您是否知道 SQL Server 的默認「事務隔離等級 (Isolation Level)」,是「ReadCommitted」,當您在寫 ADO.NET 用了 SqlTransaction 時,默認是當某個人在修改某一筆記錄時,其它所有讀取這一筆記錄的人,都會被「鎖定 (lock)」住,造成其它全部用戶的瀏覽器都在等待中,無法做其它工作。
而 oracle 事務的特性,是絕不會有類似無法讀取的情形,至少會用類似 SQL Server 2005 新增的「快照隔離 (Snapshot Isolation)」,讓用戶至少能先讀取到未 Commit 或 Rollback 的記錄,而不用呆坐在瀏覽器前面傻等。
不過 SQL Server 2005 的「快照隔離」默認未啟用。用 SQL Server 開發的系統,若怕用戶被鎖定的問題,可視 project 需求,改用最寬松的「ReadUncommitted」事務隔離等級,其特性為不會造成任何鎖定,但可能會造成 Dirty Read。SQL Server 有下列七種「事務隔離等級」,有興趣的網友可去查詢 ADO.NET 書籍或 MSDN Library:
Chaos
ReadCommitted // SQL Server 默認值
ReadUncommitted // 最寬松,會有 Dirty Read
RepeatableRead
Serializable // 最嚴,會有大量的鎖定
Snapshot
Unspecified
----------------------------------------------
(11) ASP.NET 分頁
GridView + SqlDataSource 的默認行為,就是每次換頁或排序時,不管數據庫有幾筆記錄都全部重撈一次;當數據庫有一百萬筆數據,就在每個用戶換頁時,都一百萬筆全部重撈出來,此舉消耗了大量的 Web server/ AP server 內存、數據庫系統資源、網絡頻寬,結果網站性能可想而知。
很多企業內的小型網站,為了省錢,隨便外包給低價搶標的工作室,或沒經驗的學生和 SOHO 族,可能因此埋下了恐怖的后遺癥。最可怕的是這些未爆彈,在開發期間和系統剛上線、數據量還很少時,都感覺不出來,有如癌癥一樣,會在將來忽然爆發。
----------------------------------------------
(12) ASP.NET AJAX 的 UpdatePanel 控件不是萬能的
以下引用自 MSDN Magazine:
不論好壞,UpdatePanel 控件都是 ASP.NET AJAX 社區所喜愛的。我說“好”,是因為 UpdatePanel 使部分頁面呈現變得相當簡單,而說“壞”,是因為它的簡便和易用性是以效率和令人啼笑皆非的帶寬為代價的。
UpdatePanel 可以為一般的網頁帶來 AJAX 神奇的好處,但是它不能提供我們與 AJAX 正常關聯的高效性。例如,您是否知道,當 UpdatePanel 控件對服務器執行異步 AJAX 回調以更新其內容時,這個請求包含了常規 ASP.NET 回發所包含的一切,其中還包括 ViewState 呢?具有太多 ViewState 的頁面會降低性能,并且具有太多 ViewState 的頁面在 ASP.NET 應用程序中都太常見。
如果您準備使用 UpdatePanel 控件,您需要清楚您在準備干什么。在許多情況下,從性能的角度而言,應用程序最好是不使用 UpdatePanel,而是使用對 WebMethods 或頁面方法的異步調用。
…中間略…
當您使用 UpdatePanel 在一個頁面上執行無閃爍更新時,您可能會認為您在進行高效構建。畢竟,UpdatePanel 使用的是 AJAX,不是嗎?不幸的是,如果您在 UpdatePanel 更新時檢驗一下網絡中的通信,您會發現您根本就沒有保存什么東西,至少是在發送的時候沒有保存。通常在回發期間傳送到服務器的 ViewState 數據(與其他數據)也會在 UpdatePanel 回調期間傳送。事實上,來自 UpdatePanel 的異步 XML-HTTP 請求中所增長的數據,幾乎與在標準 ASP .NET 回發中增長的數據相同。下面是有關 ASP.NET AJAX 不可告人的秘密:UpdatePanel 雖易于使用,但是通信效率不高。
幾乎沒有什么辦法可讓您提高 UpdatePanel 的效率,但是您可以放棄使用 UpdatePanel,并轉而使用 ASP.NET AJAX 的其他功能來更新頁面內容,它不僅同樣流暢,而且更加高效。它只需要多一點點力氣,但是最后的結果往往讓人覺得是值得付出的,因為您可以大大降低在客戶端與服務器之間傳輸的數據量。
----------------------------------------------
(13) Design Patterns
雖然「設計模式」不是為解決性能問題而誕生的,但可適度防止沒經驗的新人做出蠢事。多學一些 .NET 技術敵營注重的系統架構、OOAD、Design Patterns 和相關的 Framework,對提升自己的身價和薪資也有幫助。