asp.net的10個提升性能或擴展性的秘密(一)

簡介

Asp.net有很多值得你挖掘的「秘密」,當你發現了它們,將會給你網站的性能和可擴展性帶來巨大提升!例如,對於Membership以及Profile提供程序有一些秘密的瓶頸,它們很容易被解決,從而使認證和授權更加快速。另外,asp.net的http管線可以為每一個請求作處理,防止執行了某些不必要的代碼而遭受攻擊。不只是這些,asp.net工作進程能夠突破默認限制,從而完全發揮它的威力。在瀏覽器端(不是在伺服器端)的頁面分段輸出緩存能顯著減少由於請求訪問所需要佔用的大量下載時間。在需要的用戶界面上的載入能夠給你的網站帶來快速而平穩的體驗。最後,內容分發網路(CDN)以及對HTTP緩存頭的正確使用能夠使你的網站得到快速響應。

在這篇文章中,你將學習這些技術,給你的asp.net應用程序性能和可擴展性帶來巨大的提升。下面是接下來將要討論的技術:

  • Asp.net管線優化
  • Asp.net進程配置優化
  • Asp.net網站上線之前你必須要做的事
  • 內容分發網路(CDN)
  • 瀏覽器端緩存Ajax調用
  • 最大限度地正確使用瀏覽器緩存
  • 在需要的UI上逐步載入以提供快速平滑的體驗
  • 優化asp.net 2.0Profile 提供程序
  • 怎樣在不「下線」站點的情況下查詢asp.net 2.0的Membership表
  • 防止拒絕服務攻擊
  • 上面的技術都能夠在任何的asp.net網站中實現,特別是那些使用了asp.net 2.0的Membership以及Profile 提供程序的網站。

    Asp.net管線優化

    有一些asp.net默認的HttpModules被設置在請求管線中,它們會參與每一個請求。例如,SessionStateModule會處理每一個請求,轉換會話cookie然後給HttpContext載入適當的session。不是所有的這些模塊都總是被需要的。例如,如果你沒有使用Membership 以及 Profile provider,你就不需要FormsAuthentication模塊。如果你沒有對你的用戶使用Windows認證,你就不需要WindowsAuthentication模塊。這些模塊只是被安置在管線之內,對每一個請求執行某些不是必須要的代碼。

    這些默認模塊被定義在machine.config文件中(位於$WINDOWS$Microsoft.NETFramework$VERSION$CONFIG directory)

    你可以從你的web應用程序中通過在web.config文件中加入<remove>節點移除這些默認的modules。

    上面的配置非常適合那些使用資料庫並基於Forms認證,並且不需要任何Session支持的網站。所以,所有上面這些模塊都能夠被安全地移除。

    Asp.net進程配置優化

    Asp.net進程模型配置定義了一些進程級別的屬性,例如asp.net使用了多少線程數,在超時之前它會阻塞線程多久,允許多少請求 等待I/O工作完成等。這些默認的配置在很多情況下有太多的限制。現在,硬體已經變得相當便宜,技嘉科技的雙核RAM伺服器已經變成了非常普遍的選擇。所以,進程模型配置可以配置得讓asp.net線程使用更多的系統資源,並為每一個伺服器提供更好的擴展性。

    一個通常的asp.net的安裝將按如下的配置創建一個machine.config:

    你需要修改這個自動配置,為不同的屬性使用一些特殊值來自定義asp.net工作進程的工作。例如:

    這裡除了以下的一些值,其他值都是默認值:

  • maxWorkerThreads-對每個進程來說20是默認值。在一個雙核計算機上,將會給asp.net分配40個線程。這意味著asp.net一台雙核機器上一次能夠並行處理40個請求在。我將它增加到100,給予asp.net每個進程更多的線程。如果你有一個不是CPU密集型應用程序,可以很容易地處理更多地請求量,那麼你可以增加該值。特別是如果你的Web應用程序使用許多Web Service調用或者下載/上傳的許多數據沒有給CPU帶來壓力的話。當asp.net運行超過它允許的工作線程數,它將會停止處理更多到來的請求。請求被放進一個隊列中,並保持等待知道一個工作線程被釋放。當你的站點開始遭受比你預期的更多的攻擊時,通常會發生這樣的情況。如果遇到這種情況,如果你的CPU有空閑,給每個進程(asp.net進程)增加工作線程數。
  • maxIOThreads-對每個進程來說20是默認值。在一個雙核計算機上,將會給asp.net分配40個線程來進行I/O操作。這意味著在一台雙核伺服器上asp.net一次可以並行處理40個I/O請求。I/O請求可能是文件的讀寫、資料庫操作、Web Service的調用Web應用程序內部生成的Http請求等。所以,你可以將它設置為100,如果你的伺服器有足夠的系統資源來處理更多的I/O請求的話。特別是,當你的Web應用程序經常下載或上傳數據,並行調用許多外部的webservice時,效率提升會很明顯。
  • minWorkerThreads-當可用的asp.net工作線程數下降到該值以下時,asp.net開始將即將到來的請求壓入隊列。所以你可以將該值設置為一個很低的數字來增加可被處理的當前請求的數目。然而,不要將它設置地過低,因為Web應用程序代碼可能需要做某些後台處理以及某些並行處理需要一定數量的空閑工作線程。
  • minIOThreads-與minWorkerThreads相同,但這個值涉及的是I/O線程數。但是,你可以給它設置一個比minWorkerThreads更低得數字,因為沒有發生在I/O線程上並行處理的情況。
  • momoryLimit-指定允許使用內存大小的最大值,是與系統總內存的百分比。它是在asp.net在啟動一個新進程和重新分配正在處理的請求之前工作進程可以消耗的內存大小。如果只有你的Web應用程序允許在一個「專用的盒子里」並且沒有其他的進程需要RAM,你可以設置它為一個很高的值,比如80。但是,如果你有一個內存泄露的應用程序總是不斷泄露內存,最好將它設置為一個低一點的值,以便泄露內存的進程可以在它變得無法處理之前儘快被徹底回收。特別是,當你正在使用一個COM組件並且它產生內存泄露時,就會遇到這種情況。
  • 除了processModel節點,還有一個非常重要的節點——system.net,你可以指定給一個IP它能外發請求數的最大值。

    默認值為2,它太低了。這意味著你不能從你的Web應用程序到一個IP建立超過兩個同時連接。那些需要獲取外部內容的站點很大程度上都受到這個默認配置的制約。這裡我將它設置為100,如果你的Web應用程序需要對特定伺服器有很多調用需求的話,你可以考慮設這一個甚至更高的值。

    Asp.net網站上線之前你必須要做的事

    如果你正在使用Asp.net 2.0的Membership Provider,你應該對你的web.config做一些調整:

  • 在ProfileProvider中加入applicationname屬性。如果你沒有加入一個特別的名稱,ProfileProvider將使用一個GUID。所以,在你的本地機器上,你將有一個GUID而在發布的伺服器上又將有另外一個GUID。如果你拷貝你本地資料庫到發布伺服器,你將不能重用在你本地資料庫中以存在的記錄,並且asp.net將在發布伺服器上創建一個新的應用程序。你需要在這裡加入它:
  • 無論什麼時候一個頁面的請求完成之後,ProfileProvider將自動地保存profile。所以,這可能導致你資料庫的一個不必要的更新,它有很顯著的性能損失!關閉自動保存並且在你的代碼中使用Profile.Save()明確地完成。
  • Role Manager一直查詢著資料庫來獲取用戶的角色。這同樣也有顯著的性能損失。你可以讓Role Manager緩存角色信息到cookie中來避免它。但是它也會為那些沒有很多角色的用戶分配差不多2KB的Cookie,但這也不是一種常見的場景。所以,你可以很安全地在cookie中存儲角色信息。
  • 上面的三個設置主要是為了高訪問量的網站。

    內容分發網路

    來自瀏覽器的每一個請求都是通過了跨越世界的骨幹網到達你的伺服器的。請求需要經過一定數量的國家、大陸、海洋才傳遞給你的伺服器,所以它會變得很慢。例如,如果你將你的伺服器架在USA,並且一些人在澳大利亞瀏覽你的網站,每一個請求都從地球的一端到另一段才能到達你的伺服器,然後再返回給瀏覽器。如果你的站點有很大數量的靜態文件,像圖片、CSS、Javascript。為它們發送請求,跨越世界去下載它們,將會花費大量的時間。如果你能夠在澳大利亞架設一台伺服器,並且重定向用戶到你在澳大利亞的伺服器上去,那每一個這樣的請求將比到達美國花費更少的時間。不僅網路延遲會更小,數據傳輸的路由也將更為快速,因此靜態內容將能夠以更快的速度下載。

    註:由於本節與asp.net技術無關,牽扯到網路規劃,所以不作討論,僅僅給出一張示意圖:

    在瀏覽器上緩存AJAX調用

    瀏覽器能緩存圖片,JS文件,CSS文件到硬碟上。它同時也能緩存XML HTTP調用,如果調用是Http GET的話。緩存是基於URL的。如果是相同的URL,再次請求時,它被緩存到計算機上,然後響應從緩存去載入,而不是從伺服器。基本上,瀏覽器能緩存任何的HttpGet請求調用,並返回基於該URL的緩存數據。如果你像HttpGet請求一樣發出XML HTTP請求,並且伺服器返回某些特殊響應頭,指示瀏覽器緩存響應數據。在未來再次調用的時候,響應將會直接從緩存返回數據。因此節省了網路往返延時和下載時間。

    我們緩存了用戶的狀態,那樣當用戶在接下來的一些天再次訪問網站,用戶從瀏覽器的緩存中直接獲取緩存過的頁面,而不是從伺服器獲得。因此第二次載入會變得非常快。我們也緩存了頁面的某些部分,這取決於用戶的操作。當用戶再次執行相同的操作,一個緩存的結果就被直接從本地緩存載入,因此省去了網路往返的時間。

    如果你在請求的響應期間返回Expires頭,瀏覽器將緩存XML HTTP響應。有兩個響應頭你需要隨著響應返回來讓瀏覽器緩存響應數據:

    這指示瀏覽器緩存響應數據知道2030年1月。儘管你發起攜帶相同參數的相同的XML HTTP請求,你也將僅會從你本地計算機中獲得緩存後的響應數據。當然還有一個更合理的方式來控制瀏覽器緩存。例如,有些請求頭指示瀏覽器緩存60秒,但在60秒之後會重新連接伺服器並獲得一個刷新的數據。當瀏覽器本地緩存超過60秒時它也將防止代理返回緩存的響應數據。

    讓我們通過一個asp.net web service調用來輸出這樣的響應頭。

    這將導致請求頭變成如下的形式:

    Expires頭被正確地設置了。但起決定作用的還是Cache-control。你可以看到max-age被設置為0,它將防止瀏覽器做任何形式的緩存。如果你確信想要防止緩存,你應該設置這樣的一個cache-control頭。看起來就好像事情都是實時發生的。

    輸出就像下面一樣,沒有緩存:

    Asp.net 2.0有一個Bug——你不能改變max-age頭。因為max-age被設置為0,asp.net 2.0設置Cache-control為私有的。因為max-age=0意味著不需要緩存。所以,沒有辦法讓asp.net 2.0返回緩存了響應的適當的頭。這是由於asp.net Ajax 框架它在執行發出一個請求前可以攔截對Web Services的調用以及默認地不正確地設置max-age為0。

    「黑客」時刻到來!在反編譯HttpCachePolicy類(Context.Response.Cache對象所屬的類)的源碼後,我發現如下的代碼:

    不管怎樣,this._maxAge將會被設置為0,並且檢查——if (!this._isMaxAgeSet || (delta < this._maxAge))也將組織設置一個更大的值。由於這個原因,我們需要繞開SetMaxAge方法,直接設置_maxAge的值。當然,這需要用到「反射」機制:

    這將返回下面的頭:

    現在,max-age被設置為60,因此瀏覽器將緩存響應60秒。如果你在60秒內再次發出相同的請求。它將返回相同的響應。這裡有個輸出測試,顯示了從伺服器返回的日期/時間:

    在一分鐘之後,緩存失效,瀏覽器向伺服器再次發出一個請求。客戶端代碼如下:

    還有另一個問題有待解決:在web.config中,你將看到asp.net ajax將看到:

    這將阻止我們設置Response對象的_maxAge對象,因為它要求反射。所以你將不得不刪除該項設置,或者將值改為:Full。

    未完,待續。。。

    Asp.net有很多值得你挖掘的「秘密」,當你發現了它們,將會給你網站的性能和可擴展性帶來巨大提升!例如,對於Membership以及Profile提供程序有一些秘密的瓶頸,它們很容易被解決,從而使認證和授權更加快速。另外,asp.net的http管線可以為每一個請求作處理,防止執行了某些不必要的代碼而遭受攻擊。不只是這些,asp.net工作進程能夠突破默認限制,從而完全發揮它的威力。在瀏覽器端(不是在伺服器端)的頁面分段輸出緩存能顯著減少由於請求訪問所需要佔用的大量下載時間。在需要的用戶界面上的載入能夠給你的網站帶來快速而平穩的體驗。最後,內容分發網路(CDN)以及對HTTP緩存頭的正確使用能夠使你的網站得到快速響應。

    在這篇文章中,你將學習這些技術,給你的asp.net應用程序性能和可擴展性帶來巨大的提升。下面是接下來將要討論的技術:

  • Asp.net管線優化
  • Asp.net進程配置優化
  • Asp.net網站上線之前你必須要做的事
  • 內容分發網路(CDN)
  • 瀏覽器端緩存Ajax調用
  • 最大限度地正確使用瀏覽器緩存
  • 在需要的UI上逐步載入以提供快速平滑的體驗
  • 優化asp.net 2.0Profile 提供程序
  • 怎樣在不「下線」站點的情況下查詢asp.net 2.0的Membership表
  • 防止拒絕服務攻擊
  • 註:以上只有黑色字體的項被翻譯!

    上面的技術都能夠在任何的asp.net網站中實現,特別是那些使用了asp.net 2.0的Membership以及Profile 提供程序的網站。

    最大限度地正確使用瀏覽器緩存

    使用統一的URL

    瀏覽器基於內容緩存URL。當URL發生改變時,瀏覽器會從伺服器獲取該URL的一個新版本。URL可以通過查詢參數來改變。例如,/default.aspx被緩存在客戶端瀏覽器,如果你請求/default.aspx?123,它將從伺服器重新獲取內容。如果你正確地設置了用於緩存的響應頭,該請求的響應也能夠被緩存到瀏覽器。在那種情況下,改變請求參數,都將從伺服器返回新的內容。所以,當你想獲得緩存的響應時你需要確信你在各處都使用了統一的URL。一個通常的錯誤是,有時www子域會被URL忽略。比如,www.pageflakes.com/default.aspx是不同於pageflakes.com/default.aspx的。它們將會被分開緩存。

    更長時間地緩存靜態內容

    靜態文件可以被緩存更長時間,比如一個月。如果你覺得你應該緩存兩天,這樣當你改變文件時,用戶將在不久能獲取到,你的想法是錯誤的!如果你更新了一個通過Expires頭緩存的文件,新用戶將可以直接獲取最新的文件,而老用戶在你本地瀏覽器失效日期之前,將一直只能看到老文件。所以,一旦你正在使用Expires頭來緩存靜態文件,你應該使用一個儘可能大的值。

    例如,如果你已經設置了一個Expires頭來緩存一個文件三天,一個用戶今天獲得了文件,並且在接下來的三天內它都將存儲在緩存中。另一個用戶在明天獲得了該文件,並緩存它在明天過後的三天。如果你在後天修改了文件,第一個用戶將在第四天看到,第二個用戶將在第五天看到。所以,不同的用戶將看到不同版本的文件。結果是,你不需要通過設置一個很小的失效日期來使得所有的用戶都在不久之後獲得新版本。你將不得不修改文件的URL來確保每一個用戶立刻獲得相同的最新文件。

    你可以通過IIS 管理器來設置靜態文件的Expires頭。在後面你將學到如何來設置。

    使用緩存友好的文件目錄結構

    將緩存內容存儲在一個公共目錄下。例如,存儲你站點所有的圖片到static文件來代替將圖片分開放置到不同的子目錄下。這將有助於你使用統一的URL。例如,在任何地方你都可以這樣寫:/static/images/somefile.gif。

    重用公共圖片文件

    有時,我們將公共的圖片文件放在幾個不同的虛擬目錄中,這樣我們能夠寫很短的路徑來引用文件。例如,你在根目錄、一些子目錄和CSS文件夾下都有一個indicator.gif。你這麼做因為你不需要當心不同的路徑,並且你可以僅僅使用文件名來作為虛擬URL。但,這很不利於緩存。每一個這種文件的拷貝在瀏覽器上都是被獨立緩存的。所以,你應該收集解決方案內所有的圖片文件,然後將它們放置到一個相同的文件中,並使用相同的路徑來引用它們。

    當你希望緩存失效時,改變文件名稱

    當你希望改變一個靜態文件時,不要僅僅更新文件,因為它已經被緩存到用戶的瀏覽器中去了。你需要改變文件的名稱,並改變對其的所有引用,來確保瀏覽器下載新文件。你也可以在資料庫中存儲文件名,或者存儲在配置文件中然後使用數據動態綁定到URL中(比如在請求後面追加版本號)。

    在訪問靜態文件時使用一個版本號

    如果你不想你的文件因為存在同一文件的多個拷貝而雜亂,你可以使用查詢參數來對相同的文件標識不同的版本。例如,一個GIF文件可以被這樣訪問:/static/images/indicator.gif?v=1。當你想改變這個indicator.gif文件時,你可以覆蓋相同的文件,然後更新所有對該文件的引用為:/static/images/indicator.gif?v=2。這種方式你可以再次更新相同的文件,並且僅需要更新版本號。

    存儲可緩存的文件到一個不同的域名下

    將靜態文件放到一個不同的域名下總是一個不錯的注意。首先,瀏覽器能兩個並發的連接來下載靜態文件。另一個好處是你不需要給靜態文件發送cookies。當你將靜態文件作為你Web應用程序的一部分並和其他文件放置在同一個域名下,瀏覽器需要給它發送所有的asp.net Cookies以及你Web 應用程序產生的所有其他的cookies。這使得請求頭部變得很大(其實沒有必要)並且浪費了帶寬。你不需要發送那些cookies來訪問這些靜態文件。所以,如果你將這些靜態文件放置到另一個域名下,那些cookies將不會發送。例如,將靜態文件放置在www.staticcontent.com域名下,而你的Web站點運行在www.dropthings.com。這裡所謂的其他的域名,並不一定需要是另外一個完整的web站點。它可以僅僅是和當前Web 應用程序共享路徑的一個別名。

    SSL不能被緩存,所以最小程度地使用SSL

    任何涉及到SSL的內容都不能被緩存。所以,你需要將那些靜態文本放置到SSL外部。另外,你應該嘗試限制只在那些安全的頁面(例如登陸頁面,付款頁面)上使用SSL。站點其他的頁面採用通常的HTTP請求。SSL會加密請求與相應內容,並因此給伺服器帶來額外負載。加密內容也比通常文件的內容更大並因此在傳輸過程中會佔用更多的帶寬。

    HTTP POST請求將永遠無法緩存

    緩存僅僅發生在HTTP GET 請求上。HTTP POST 請求永遠不會被緩存。所以,你想緩存的任何形式的AJAX調用都需要是HTTP GET形式的請求。

    生成Content-Length響應頭部

    當你正在通過Web Service或者HTTP Handlers動態產生內容時,確保你設置了Content-Length頭部。當瀏覽器通過查看Content-Length頭部知道需要下載多少位元組時,它能夠對更快速地下載數據有多種優化方式。當這個頭是當前連接的頭部時,瀏覽器能夠更有效地使用持續連接。這可以避免瀏覽器為每一個請求都打開一個新的連接。當沒有Content-Length頭部時,瀏覽器不知道它將從伺服器接受多少位元組數據,因此連接一直被打開著,從服務端獲取數據直到連接被關閉。因此,你錯失了「持續」連接的優勢,它能夠大大地減少對一些像CSS、JS、圖片等小文件的下載時間。(關於持續連接,請查看我之前的Comet系列的文章)

    怎樣在IIS上配置靜態文件緩存

    在IIS管理器上,Web站點屬性窗口有個」HTTP 頭」的選項卡,在那裡你可以為所有的IIS處理的請求定義Expires頭。你可以定義是否直接讓內容失效或者在一定的天數或者特定的日期之後失效。第二個選項(Expires after)使用的是「滑動過期」,而不是「絕對過期」。這非常得有用,因為它作用在每一個請求上。無論什麼時候,某個人請求一個靜態文件,IIS將基於該項計算失效日期。

    對於那些被asp.net處理的動態頁面,通過handler可以修改Expires頭部並且覆寫IIS默認的設置。

    基於需求的頁面漸進載入以提昇平滑的用戶體驗

    一個好的解決方案是,動態載入HTML片段以及需要的Javascript。在dropthings這個項目中,我在下面的截圖中顯示了如何做它:

    當你點擊「Help」鏈接的時候,它動態載入幫助的內容。這段HTML不是作為default.aspx頁面的一部分來解析的。因此和help相關的內容不影響站點本身的載入性能。而僅僅當用戶點擊「Help」 鏈接時才會動態載入。當用戶再次點擊」Help」鏈接,它可以直接從瀏覽器的緩存里讀取。

    它的原理是向一個*.aspx頁面發出一個XMLHttp調用,獲得響應的html標籤,將這段html代碼加入到一個DIV容器中,並讓DIV可見。

    用這種方法,你可以將UI內容分拆到許多更小的*.aspx文件中。儘管這些文件不能含有javascript或者stylesheet塊,但是它們可以包含大量的你需要按需展示的html代碼。因此你可以讓只需要載入最基本的內容。

    應對拒絕服務攻擊

    Web Service是黑客最容易攻擊的目標,因為甚至一個初級黑客都可能通過直接調用那些很耗費資源的Web Service而掛掉一台伺服器。Ajax起始頁是DOS最好的攻擊目標。因為如果你只是訪問主頁而不保護cookies,每一個攻擊都建立一個新的用戶,請求一個新頁面。首次訪問是最消耗資源的一次。但,它是掛掉一個網站最容易攻擊的方式。你可以自己嘗試,僅需要寫如下的簡單代碼:

    給你的最大的驚喜是,你將發現,在兩次調用之後,你不能得到有效的響應。但這不是你表明你已經成功得掛掉了伺服器。這只是你的請求被拒絕了。你很高興你不再能獲取任何服務,因此你實現了拒絕服務(你自己這麼認為的)。而我們會高興拒絕為你服務。

    我的做法很簡單,我會記錄一個IP發送了多少次請求。當請求的數量超過一個特殊值時,拒絕一定時間內的進一步請求。方案是在asp.net的Cache中記錄調用者的IP並且維護對每一個發起請求的統計。當一個IP的統計值超出限制,拒絕該IP更之後的請求,在10分鐘之內。在十分鐘之後,再次響應來自該IP的請求。

    我有一個類叫做ActionValidator,它維護了一些特殊操作的統計,例如:首次訪問,再次訪問,非同步回傳,添加新部件,添加新頁面等等。它檢測是否為該特定IP的具體操作數超過了限制值。

    枚舉包含了操作的類型,以及檢測它們的限制值,並設置了一個特定的再次接受服務的時間。

    一個靜態方法,IsValid做具體的檢測處理。如果請求沒有超過限制值,它返回true,否則如果請求需要被拒絕,返回false。你也可以顯示一個頁面,顯示結果。

    緩存的鍵是通過操作類型與客戶端IP地址共同構建的。首先,它檢測在緩存中是否有關於該操作與IP的實體。如果沒有,開始計數並且為該操作記錄其IP到緩存中。該緩存項的絕對失效時間可以確保在緩存項持續時間之後將被清除並且重新開始計數。當已經有了一個實體在緩存中時,獲取最後一次訪問統計,並且檢查是否有超出限制值。如果沒有超過,增加計數。通過做:Cache[url]=hit;,不需要再次存儲更新過的值到緩存中。因為修改的是hit對象的引用,更新它就意味著也更新了緩存里的對象本身。事實上,如果你在緩存中再存儲一次,cache失效計數將重新計數並且失去了在特殊持續時間後重新計數的功能。

    使用非常簡單,在default.aspx頁面:

    我在這裡檢查了特殊的場景,例如首次訪問,再次訪問,回發等等。

    當然,你可以加入一些思科防火牆以防止拒絕服務攻擊。你將得到你的託管服務提供商的一個保證整個網路中對DOS以及DDOS(分散式DOS)攻擊是免疫的。但這些應用程序級別的DOS攻擊是硬體無法阻止的,它必須在你自己的代碼中實現。

    只有非常少的部分網站採用了這種措施來防止應用程序級別的DOS攻擊。因此,通過寫一個簡單的循環,訪問很耗資源的網頁或者以你家庭寬頻不斷調用Web Service,可以很輕易地掛掉一個伺服器。


    推薦閱讀:

    汽車性能參數很難懂?看完這篇再也難不倒你
    如何對APP性能進行監測並優化?有沒有工具推薦一下。
    雲計算史上的第一次開箱直播 阿里雲神龍技術架構首次全方位曝光
    一點技術心得
    為您的 Node 性能選擇最佳的 JS 引擎

    TAG:性能 | 秘密 | 提升 | 擴展 |