編寫高效能Web應用程式的10個入門技巧

來源:互聯網
上載者:User
web|程式|技巧|效能

  使用 ASP.NET 編寫 Web 應用程式的簡單程度令人不敢相信。正因為如此簡單,所以很多開發人員就不會花時間來設計其應用程式的結構,以獲得更好的效能了。在本文中,我將講述 10 個用於編寫高效能 Web 應用程式的技巧。但是我並不會將這些建議僅局限於ASP.NET 應用程式,因為這些應用程式只是 Web 應用程式的一部分。本文不作為對 Web應用程式進行效能調整的權威性指南 — 一整本書恐怕都無法輕鬆講清楚這個問題。請將本文視作一個很好的起點。

  成為工作狂之前,我原來喜歡攀岩。在進行任何大型攀岩活動之前,我都會首先仔細查看指南中的路線,閱讀以前遊客提出的建議。但是,無論指南怎麼好,您都需要真正的攀岩體驗,然後才能嘗試一個特別具有挑戰性的攀登。與之相似,當您面臨修複效能問題或者運行一個高輸送量網站的問題時,您只能學習如何編寫高效能 Web 應用程式。

  我的個人體驗來自在 Microsoft 的 ASP.NET 部門作為基礎架構程式經理的經驗,在此期間我運行和管理 www.ASP.NET,協助設計社區伺服器的結構,社區伺服器是幾個著名
ASP.NET 應用程式(組合到一個平台的 ASP.NET Forums、.Text 和 nGallery)。我確信有些曾經協助過我的技巧對您肯定也會有所協助。

  您應該考慮將應用程式分為幾個邏輯層。您可能聽說過 3 層(或者 n 層)物理體繫結構一詞。這些通常都是規定好的體繫結構方式,將功能在進程和/或硬體之進行了物理分離。當系統需要擴大時,可以很輕鬆地添加更多的硬體。但是會出現一個與進程和機器跳躍相關的效能下降,因此應該避免。所以,如果可能的話,請盡量在同一個應用程式中一起運行 ASP.NET 頁及其相關組件。

  因為代碼分離以及層之間的邊界,所以使用 Web 服務或遠端將會使得效能下降 20% 甚至更多。

  資料層有點與眾不同,因為通常情況下,最好具有專用於資料庫的硬體。然而進程跳躍到資料庫的成本依然很高,因此資料層的效能是您在最佳化代碼時首先要考慮的問題。

  在深入應用程式的效能修複問題之前,請首先確保對應用程式進行剖析,以便找出具體的問題所在。主要效能計數器(如表示執行記憶體回收所需時間百分比的計數器)對於找出應用程式在哪些位置花費了其主要時間也非常有用。然而花費時間的位置通常非常不直觀。

  本文講述了兩種類型的效能改善:大型最佳化(如使用 ASP.NET 緩衝),和進行自身重複的小型最佳化。這些小型最佳化有時特別有意思。您對代碼進行一點小小的更改,就會獲得很多很多時間。使用大型最佳化,您可能會看到整體效能的較大飛躍。而使用小型最佳化時,對於某個特定請求可能只會節省幾毫秒的時間,但是每天所有請求加起來,則可能會產生巨大的改善。

  資料層效能

  談到應用程式的效能調整,有一個試紙性的測試可用來對工作進行優先順序劃分:代碼是否訪問資料庫?如果是,頻率是怎樣的?請注意,這一相同測試也可應用於使用 Web 服務或遠端的代碼,但是本文對這些內容未做講述。

  如果某個特定的代碼路徑中必需進行資料庫請求,並且您認為要首先最佳化其他領域(如字串操作),則請停止,然後執行這個試紙性測試。如果您的效能問題不是非常嚴重的話,最好花一些時間來最佳化一下與資料庫、返回的資料量、進出資料庫的往返頻率相關的花費時間。

  瞭解這些常規資訊之後,我們來看一下可能會有助於提高應用程式效能的十個技巧。首先,我要講述可能會引起最大改觀的更改。

  技巧 1 — 返回多個結果集

  仔細查看您的資料庫代碼,看是否存在多次進入資料庫的請求路徑。每個這樣的往返都會降低應用程式可以提供的每秒請求數量。通過在一個資料庫請求中返回多個結果集,可以節省與資料庫進行通訊所需的總時間長度。同時因為減少了資料庫伺服器管理請求的工作,還會使得系統伸縮性更強。

  雖然可以使用動態 SQL 返回多個結果集,但是我首選使用預存程序。關於商務邏輯是否應該駐留於預存程序的問題還存在一些爭議,但是我認為,如果預存程序中的邏輯可以約束返回資料的話(縮小資料集的大小、縮短網路上所花費時間,不必篩選邏輯層的資料),則應贊成這樣做。

  使用 SqlCommand 執行個體及其 ExecuteReader 方法填充強型別的業務類時,可以通過調用NextResult 將結果集指標向前移動。圖 1 顯示了使用類型類填充幾個 ArrayList 的樣本會話。只從資料庫返回您需要的資料將進一步減少伺服器上的記憶體配置。

Figure 1 Extracting Multiple Resultsets from a DataReader
// read the first resultset
reader = command.ExecuteReader();

// read the data from that resultset
while (reader.Read()) {
suppliers.Add(PopulateSupplierFromIDataReader( reader ));
}

// read the next resultset
reader.NextResult();

// read the data from that second resultset
while (reader.Read()) {
products.Add(PopulateProductFromIDataReader( reader ));
}
   技巧 2 — 分頁的資料訪問

  ASP.NET DataGrid 具有一個很好的功能:資料分頁支援。在 DataGrid 中啟用分頁時,一次會顯示固定數量的記錄。另外,在 DataGrid 的底部還會顯示分頁 UI,以便在記錄之間進行導航。該分頁 UI 使您能夠在所顯示的資料之間向前和向後導航,並且一次顯示固定數量的記錄。

  還有一個小小的波折。使用 DataGrid 的分頁需要所有資料均與網格進行綁定。例如,您的資料層需要返回所有資料,那麼 DataGrid 就會基於當前頁篩選顯示的所有記錄。如果通過 DataGrid 進行分頁時返回了 100,000 個記錄,那麼針對每個請求會放棄 99,975 個記錄(假設每頁大小為 25 個記錄)。當記錄的數量不斷增加時,應用程式的效能就會受到影響,因為針對每個請求必鬚髮送越來越多的資料。

  要編寫效能更好的分頁代碼,一個極佳的方式是使用預存程序。圖 2 顯示了針對Northwind 資料庫中的 Orders 表進行分頁的一個樣本預存程序。簡而言之,您此時要做的只是傳遞頁索引和頁大小。然後就會計算合適的結果集,並將其返回。

Figure 2 Paging Through the Orders Table
CREATE PROCEDURE northwind_OrdersPaged
(
@PageIndex int,
@PageSize int
)
AS
BEGIN
DECLARE @PageLowerBound int
DECLARE @PageUpperBound int
DECLARE @RowsToReturn int

-- First set the rowcount
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn

-- Set the page bounds
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1

-- Create a temp table to store the select results
CREATE TABLE #PageIndex
(
IndexId int IDENTITY (1, 1) NOT NULL,
OrderID int
)

-- Insert into the temp table
INSERT INTO #PageIndex (OrderID)
SELECT
OrderID
FROM
Orders
ORDER BY
OrderID DESC

-- Return total count
SELECT COUNT(OrderID) FROM Orders

-- Return paged results
SELECT
O.*
FROM
Orders O,
#PageIndex PageIndex
WHERE
O.OrderID = PageIndex.OrderID AND
PageIndex.IndexID > @PageLowerBound AND
PageIndex.IndexID < @PageUpperBound
ORDER BY
PageIndex.IndexID

END


  在社區伺服器中,我們編寫了一個分頁伺服器控制項,以完成所有的資料分頁。您將會看到,我使用的就是技巧 1 中討論的理念,從一個預存程序返回兩個結果集:記錄的總數和請求的資料。

  返回記錄的總數可能會根據所執行查詢的不同而有所變化。例如,WHERE 子句可用來約束返回的資料。為了計算在分頁 UI 中顯示的總頁數,必須瞭解要返回記錄的總數。例如,如果總共有 1,000,000 條記錄,並且要使用一個 WHERE 子句將其篩選為 1000 條記錄,那麼分頁邏輯就需要瞭解記錄的總數才能正確呈現分頁 UI。

  技巧 3 — 串連池

  在 Web 應用程式和 SQL Server之間設定 TCP 串連可能是一個非常消耗資源的操作。Microsoft 的開發人員到目前為止能夠使用串連池已經有一段時間了,這使得他們能夠重用資料庫連接。他們不是針對每個請求都設定一個新的 TCP 串連,而是只在串連池中沒有任何串連時才設定新串連。當串連關閉時,它會返回串連池,在其中它會保持與資料庫的串連,而不是完全破壞該 TCP 串連。

  當然,您需要小心是否會出現泄漏串連。當您完成使用串連時,請一定要關閉這些串連。再重複一遍:無論任何人對 Microsoft?.NET Framework 中的記憶體回收有什麼評論,請一定要在完成使用串連時針對該串連顯式調用 Close 或 Dispose。不要相信公用語言運行庫(CLR) 會在預先確定的時間為您清除和關閉串連。儘管 CLR 最終會破壞該類,並強制串連關閉,但是當針對對象的記憶體回收真正發生時,並不能保證。

  要以最佳化的方式使用串連池,需要遵守一些規則。首先開啟串連,執行操作,然後關閉該串連。如果您必須如此的話,可以針對每個請求多次開啟和關閉串連(最好應用技巧 1),但是不要一直將串連保持開啟狀態並使用各種不同的方法對其進行進出傳遞。第二,使用相同的連接字串(如果使用整合身分識別驗證的話,還要使用相同的線程標識)。如果不使用相同的連接字串,例如根據登入的使用者自訂連接字串,那麼您將無法得到串連池提供的同一個最佳化值。如果您使用整合身分識別驗證,同時還要類比大量使用者,串連池的效率也會大大下降。嘗試跟蹤與串連池相關的任何效能問題時,.NET CLR 資料效能計數器可能非常有用。

  每當應用程式串連資源時,如在另一個進程中啟動並執行資料庫,您都應該重點考慮串連該資源所花時間、發送或檢索資料所花時間,以及往返的數量,從而進行最佳化。最佳化應用程式中任何種類的進程跳躍都是獲得更佳效能的首要一點。

  應用程式層包含了串連資料層、將資料轉換為有意義類執行個體和商務程序的邏輯。例如社區伺服器,您要在其中填充Forums 或 Threads集合,應用商務規則(如許可權);最重要的是要在其中執行緩衝邏輯。

  技巧 4 — ASP.NET 緩衝 API

  編寫應用程式程式碼之前,一個首要完成的操作是設計應用程式層的結構,以便最大化利用ASP.NET 緩衝功能。

  如果您的組件要在 ASP.NET 應用程式中運行,則只需在該應用程式項目中包括一個System.Web.dll 引用。當您需要訪問該緩衝時,請使用 HttpRuntime.Cache 屬性(通過Page.Cache 和 HttpContext.Cache 也可訪問這個對象)。

  對於快取資料,有幾個規則。首先,如果資料可能會多次使用時,則這是使用緩衝的一個很好的備選情況。第二,如果資料是通用的,而不特定於某個具體的請求或使用者時,則也是使用緩衝的一個很好的備選情況。如果資料是特定於使用者或請求的,但是壽命較長的話,仍然可以對其進行緩衝,但是這種情況可能並不經常使用。第三,一個經常被忽略的規則是,有時可能您緩衝得太多。通常在一個 x86 電腦上,為了減少記憶體不足錯誤出現的機會,您會想使用不高於 800MB 的專用位元組運行進程。因此緩衝應該有個限度。換句話說,您可能能夠重用某個計算結果,但是如果該計算採用 10 個參數的話,您可能要嘗試緩衝 10 個排列,這樣有可能給您帶來麻煩。一個要求 ASP.NET 的最常見支援是由於過度緩衝引起的記憶體不足錯誤,尤其是對於大型資料集。

  緩衝有幾個極佳的功能,您需要對它們有所瞭解。首先,緩衝會實現最近最少使用的演算法,使得 ASP.NET 能夠在記憶體運行效率較低的情況下強制緩衝清除 - 從緩衝自動刪除未使用過的項目。第二,緩衝支援可以強制失效的到期依賴項。這些依賴項包括時間、密鑰和檔案。時間經常會用到,但是對於 ASP.NET 2.0,引入了一個功能更強的新失效類型:資料庫緩衝失效。它指的是當資料庫中的資料發生變化時自動刪除緩衝中的項。有關資料庫緩衝失效的詳細資料,請參閱 MSDN?Magazine 2004 年 7 月的 Dino Esposito Cutting Edge 專欄。

  技巧 5 — 每請求緩衝

  在本文前面部分,我提到了經常遍曆代碼路徑的一些小改善可能會導致較大的整體效能收益。對於這些小改善,其中有一個絕對是我的最愛,我將其稱之為"每請求緩衝"。

  緩衝 API 的設計目的是為了將資料緩衝較長的一段時間,或者緩衝至滿足某些條件時,但每請求緩衝則意味著只將資料緩衝為該請求的期間。對於每個請求,要經常訪問某個特定的代碼路徑,但是資料卻只需提取、應用、修改或更新一次。這聽起來有些理論化,那麼我們來舉一個具體的樣本。

  在社區伺服器的論壇應用程式中,頁面上使用的每個伺服器控制項都需要個人化的資料來確定使用什麼外觀、使用什麼樣式表,以及其他個人化資料。這些資料中有些可以長期緩衝,但是有些資料卻只針對每個請求提取一次,然後在執行該請求期間對其重用多次,如要用於控制項的外觀。

  為了達到每請求緩衝,請使用 ASP.NET HttpContext。對於每個請求,都會建立一個HttpContext 執行個體,在該請求期間從 HttpContext.Current 屬性的任何位置都可訪問該執行個體。該 HttpContext 類具有一個特殊的 Items 集合屬性;添加到此 Items 集合的對象和資料只在該請求持續期間內進行緩衝。正如您可以使用緩衝來儲存經常訪問的資料一樣,您也可以使用 HttpContext.Items 來儲存只基於每個請求使用的資料。它背後的邏輯非常簡單:資料在它不存在的時候添加到 HttpContext.Items 集合,在後來的尋找中,只是返回 HttpContext.Items 中的資料。

  技巧 6 — 幕後處理

  通往代碼的路徑應該儘可能快速,是嗎?可能有時您會覺得針對每個請求執行的或者每n 個請求執行一次的任務所需資源非常多。寄送電子郵件或者分析和驗證傳入資料就是這樣的一些例子。

  剖析 ASP.NET Forums 1.0 並重新構建組成社區伺服器的內容時,我們發現添加新張貼的代碼路徑非常慢。每次添加新張貼時,應用程式首先需要確保沒有重複的張貼,然後必須使用"壞詞"篩選器分析該張貼,分析張貼的字元圖釋,對張貼委任標記並進行索引,請求時將張貼添加到合適的隊列,驗證附件,最終張貼之後,立即向所有訂閱者發出電子郵件通知。很清楚,這涉及很多操作。

  經研究發現,大多數時間都花在了索引邏輯和寄送電子郵件上。對張貼進行索引是一個非常耗時的操作,人們發現內建的 System.Web.Mail 功能要串連 SMYP 伺服器,然後連續寄送電子郵件。當某個特定張貼或主題領域的訂閱者數量增加時,執行 AddPost 功能所需的時間也越來越長。

  並不需要針對每個請求都進行電子郵件索引。理想情況下,我們想要將此操作進行批處理,一次索引 25 個張貼或者每五分鐘發送一次所有電子郵件。我們決定使用以前用於對資料緩衝失效進行原型設計的代碼,這個失效是用於最終進入 Visual Studio? 2005 的內容的。

  System.Threading 命名空間中的 Timer 類非常有用,但是在 .NET Framework 中不是很有名,至少對於 Web 開發人員來說是這樣。建立之後,這個 Timer 類將以一個可配置的間隔針對 ThreadPool 中的某個線程調用指定的回調。這就表示,您可以對代碼進行設定,使其能夠在沒有對 ASP.NET 應用程式進行傳入請求的情況下得以執行,這是幕後處理的理想情況。您還可以在此後台進程中執行如索引或寄送電子郵件之類的操作。

  但是,這一技術有幾個問題。如果應用程式定義域卸載,該計時器執行個體將停止觸發其事件。另外,因為 CLR 對於每個進程的線程數量具有一個硬性標準,所以可能會出現這樣的情形:伺服器負載很重,其中計時器可能沒有可在其基礎上得以完成的線程,在某種程度上可能會造成延遲。ASP.NET 通過在進程中保留一定數量的可用線程,並且僅使用匯流排程的一部分用於請求處理,試圖將上述情況發生的機會降到最低。但是,如果您具有很多非同步作業時,這可能就是一個問題了。

  這裡沒有足夠的空間來放置該代碼,但是您可以下載一個可以看懂的樣本,網址是www.rob-howard.net。請瞭解一下 Blackbelt TechEd 2004 示範中的投影片和示範。

  技巧 7 — 頁輸出緩衝和Proxy 伺服器

  ASP.NET 是您的展示層(或者說應該是您的展示層);它由頁、使用者控制項、伺服器控制項(HttpHandlers 和 HttpModules)以及它們產生的內容組成。如果您具有一個 ASP.NET 頁,它會產生輸出(HTML、XML、映像或任何其他資料),並且您針對每個請求運行此代碼時,它都會產生相同的輸出,那麼您就擁有一個可用於頁輸出緩衝的絕佳備選內容。

  將此行內容添加頁的最上端 <%@ Page OutputCache VaryByParams="none" Duration="60" %>

  就可以高效地為此頁產生一次輸出,然後對它進行多次重用,時間最長為 60 秒,此時該頁將重新執行,輸出也將再一次添加到 ASP.NET 緩衝。通過使用一些低級程式化 API 也可以完成此行為。對於輸出緩衝有幾個可配置的設定,如剛剛講到的 VaryByParams 屬性。VaryByParams 剛好被請求到,但還允許您指定 HTTP GET 或 HTTP POST 參數來更改快取項目。例如,只需設定 VaryByParam="Report" 即可對 default.aspx?Report=1 或 default.aspx?Report=2 進行輸出緩衝。通過指定一個以分號分隔的列表,還可以指定其他參數。

  很多人都不知道何時使用輸出緩衝,ASP.NET 頁還會產生一些位於快取服務器下遊的HTTP 標題,如 Microsoft Internet Security and Acceleration Server 或 Akamai 使用的標題。設定了 HTTP 緩衝標題之後,可以在這些網路資源上對文檔進行緩衝,用戶端請求也可在不必返回原始伺服器的情況下得以滿足。

  因此,使用頁輸出緩衝不會使得您的應用程式效率更高,但是它可能會減少伺服器上的負載,因為下遊緩衝技術會緩衝文檔。當然,這可能只是匿名內容;一旦它成為下遊之後,您就再也不會看到這些請求,並且再也無法執行身分識別驗證以阻止對它的訪問了。

  技巧 8 — 運行 IIS 6.0(只要用於核心緩衝)

  如果您未運行 IIS 6.0 (Windows Server? 2003),那麼您就錯過了 Microsoft Web 服務器中的一些很好的效能增強。在技巧 7 中,我討論了輸出緩衝。在 IIS 5.0 中,請求是通過 IIS 然後進入 ASP.NET 的。涉及到緩衝時,ASP.NET 中的 HttpModule 會接收該請求,並返回緩衝中的內容。

  如果您正在使用 IIS 6.0,就會發現一個很好的小功能,稱為核心緩衝,它不需要對ASP.NET 進行任何代碼更改。當請求由 ASP.NET 進行輸出緩衝時,IIS 核心緩衝會接收快取資料的一個副本。當請求來自網路驅動程式時,核心層級的驅動程式(無環境切換到使用者模式)就會接收該請求,如果經過了緩衝,則會將緩衝的資料重新整理到響應,然後完成執行。這就表示,當您將核心模式緩衝與 IIS 和 ASP.NET 輸出緩衝一起使用時,就會看到令人不敢相信的效能結果。在 ASP.NET 的 Visual Studio 2005 開發過程中,我一度是負責 ASP.NET 效能的程式經理。開發人員完成具體工作,但是我要看到每天進行的所有報告。核心模式緩衝結果總是最有意思的。最常見的特徵是網路充滿了請求/響應,而 IIS 運行時的 CPU 使用率只有大約 5%。這太令人震驚了!當然使用 IIS 6.0 還有一些其他原因,但是核心模式緩衝是其中最明顯的一個。

  技巧 9 — 使用 Gzip 壓縮

  雖然使用 gzip 並不一定是伺服器效能技巧(因為您可能會看到 CPU 使用率的提高),但是使用 gzip 壓縮可以減少伺服器發送的位元組數量。這就使人們覺得頁速度加快了,並且還減少了頻寬的用量。根據所發送資料、可以壓縮的程度以及用戶端瀏覽器是否支援(IIS只會向支援 gzip 壓縮的用戶端發送經過 gzip 壓縮的內容,如 Internet Explorer 6.0 和 Firefox),您的伺服器每秒可以服務於更多的請求。實際上,幾乎每當您減少所返回資料的數量時,都會增加每秒請求數。

  Gzip 壓縮已經內建到 IIS 6.0 中,並且其效能比 IIS 5.0 中使用的 gzip 壓縮要好的多,這是好訊息。但不幸的是,當嘗試在 IIS 6.0 中開啟 gzip 壓縮時,您可能無法在IIS 的屬性對話中找到該設定。IIS 小組在該伺服器中置入了卓越的 gzip 功能,但是忘了包括一個用於啟用該功能的管理 UI。要啟用 gzip 壓縮,您必須深入到 IIS 6.0 的 XML 配置設定內部(這樣不會引起心臟虛弱)。順便提一句,這歸功於 OrcsWeb 的 Scott Forsyth,他協助我提出了在 OrcsWeb 上宿主的 www.asp.net 伺服器的這個問題。

  本文就不講述步驟了,請閱讀 Brad Wilson 的文章,網址是 IIS6 Compression。還有一篇有關為 ASPX 啟用壓縮的知識庫文章,網址是 Enable ASPX Compression in IIS。但是您應該注意,由於一些實施細節,IIS 6.0 中不能同時存在動態壓縮和核心緩衝。

  技巧 10 — 伺服器控制項檢視狀態

  檢視狀態是一個有趣的名稱,用於表示在所產生頁的隱藏輸出欄位中儲存一些狀態資料的ASP.NET。當該頁張貼回伺服器時,伺服器可以分析、驗證、並將此檢視狀態資料應用回該頁的控制項樹。檢視狀態是一個非常強大的功能,因為它允許狀態與用戶端一起保持,並且它不需要 cookie 或伺服器記憶體即可儲存此狀態。很多 ASP.NET 伺服器控制項都使用檢視狀態來保持在與頁元素進行互動期間建立的設定,例如儲存對資料進行分頁時顯示的當前頁。

  然而使用檢視狀態也有一些缺點。首先,服務或請求頁時,它都會增加頁的總負載。對張貼回伺服器的檢視狀態資料進行序列化或取消序列化時,也會發生額外的開銷。最後,檢視狀態會增加伺服器上的記憶體配置。

  幾個伺服器控制項有著過度使用檢視狀態的趨勢,即使在並不需要的情況下也要使用它,其中最著名的是 DataGrid。ViewState 屬性的預設行為是啟用,但是如果您不需要,則可以在控制項或頁層級關閉。在控制項內,只需將 EnableViewState 屬性設定為 false,或者在頁中使用下列設定即可對其進行全域設定:

<%@ Page EnableViewState="false" %>

  如果您不回傳頁,或者總是針對每個請求重建頁上的控制項,則應該在頁層級禁用檢視狀態。

  我為您講述了一些我認為在編寫高效能 ASP.NET 應用程式時有所協助的技巧。正如我在本文前面部分提到的那樣,這是一個初步指南,並不是 ASP.NET 效能的最後結果。(有關改善 ASP.NET 應用程式效能的資訊,請參閱 Improving ASP.NET Performance。)只有通過自己的親身體驗才能找出解決具體效能問題的最好方法。但是,在您的旅程中,這些技巧應該會為您提供一些好的指南。在軟體開發中,幾乎沒有絕對的東西;每個應用程式都是唯一的。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.