本文章是由機器翻譯。

Azure 網站

使用 Azure 網站擴充您的 Web 應用程式

Yochay Kiriaty

下載代碼示例

出人意料的是,規模是開發 Web 應用程式經常被忽略的方面。通常情況下,Web 應用程式的規模成為所關注,只有當事情開始出現故障,使用者體驗受到影響,由於緩慢或超時在展示層。一個 Web 應用程式啟動時表現出這種性能赤字,它已達到其可擴充性點 — — 點的缺乏的資源,如 CPU、 記憶體或頻寬,而不是一個邏輯錯誤在代碼中,阻礙了其功能的能力。

這是時間來擴展 Web 應用程式,並給它額外的資源,是否更高的計算,額外的存儲或一個更強大的資料庫後端。縮放在雲計算的最常見形式是水準 — — 添加額外計算允許要同時在多個 Web 服務器 (實例) 上運行的 Web 應用程式的實例。等微軟 Azure 雲計算平臺使它很容易擴展支援 Web 應用程式中通過提供任意數量的 Web 服務器的虛擬機器 (Vm),你的手指輕輕按形式的底層基礎架構。然而,如果您的 Web 應用程式並不設計的規模和運行多個實例,它將無法充分利用額外的資源優勢和不會產生預期的結果。

這篇文章需要看看關鍵的設計概念和縮放的 Web 應用程式的模式。實現細節和例子集中運行微軟 Azure 網站上的 Web 應用程式。

之前,它是重要的是要注意縮放的 Web 應用程式是非常依賴于上下文和您的應用程式的體系結構的方式。在這篇文章中使用的 Web 應用程式很簡單,但它觸及到擴展 Web 應用程式,專門解決規模 Azure 網站上運行時的基礎知識。

有不同級別的規模,以滿足不同的業務需求。在這篇文章,我看看四個不同級別的縮放功能,從一個 Web 應用程式不能運行多個實例,一個可以擴展到多個實例 — — 甚至跨多個地理區域和資料中心。

第一步:滿足應用程式

我要開始通過審查的示例 Web 應用程式的限制。此步驟將設置了比較基準,將做成所需的修改,以提高應用程式的可擴充性。我選擇來修改現有的應用程式,因為在現實生活中,經常是你要做的而不是從頭開始創建一個嶄新的應用和設計。

我會為這篇文章使用的應用程式是ASP.NETWeb 頁的 WebMatrix 照片庫範本 (bit.ly/1llAJdQ)。此範本是一個偉大的方式來學習如何使用ASP.NETWeb 頁來創建實際的 Web 應用程式。它是一個全功能的 Web 應用程式使使用者能夠創建相冊、 上傳圖片。任何人都可以查看的圖像,並已登錄的使用者可以發表評論。照片畫廊 Web 應用程式可以部署到 Azure 網站從 WebMatrix,或直接從 Azure 門戶通過 Azure Web 網站庫。

密切關注 Web 應用程式代碼揭示了限制應用程式的可伸縮性的至少三個顯著的體系結構問題:利用當地SQL ServerExpress 作為資料庫 ; 使用過程 (本地 Web 服務器記憶體) 的會話狀態 ; 和使用本地檔案系統來存儲照片。

我將回顧每深入這些限制。

PhotoGallery.sdf 檔,發現在 App_Data 資料夾中,是與應用程式一起分發的預設SQL Server快遞資料庫。SQL Server快遞容易地開始開發應用程式和提供一個很好的學習經驗,但它也對嚴重限制擴展的應用程式的能力。本質上,SQL Server快遞資料庫是一個檔在檔案系統中。照片庫在其目前狀態中的應用不能安全地規模跨多個實例。嘗試縮放跨多個實例可以留給你SQL Server快遞資料庫檔案,每一個本地檔,並且很可能不同步與其他人的多個實例。即使在不同的時間,所有的 Web 服務器實例共用相同的檔案系統,SQL Server快遞檔可以得到任何一個實例被鎖定,導致的其他實例失敗。

照片庫應用程式也是有限的方式它管理使用者的會話狀態。一個會話被定義為一系列的在一段時間內, 由同一使用者發出的請求是由和管理將與每個唯一的使用者關聯的會話 ID。ID 用於每個後續的 HTTP 要求和提供的用戶端,在 cookie 中或作為一個特殊的請求 URL 的片段。會話資料存儲在伺服器端支援的會話狀態存儲,其中包括在進程記憶體,SQL Server資料庫或ASP.NET狀態伺服器之一。

照片庫應用程式使用 WebMatrix WebSecurity 類來管理使用者登錄和狀態,和 WebSecurity 使用預設ASP.NET成員資格提供程式會話狀態。預設情況下,ASP.NET成員資格提供程式的會話狀態模式是 (InProc) 過程中。在此模式下,在本地 Web 服務器實例 (VM) 的記憶體中存儲會話狀態的值和變數。每個 Web 服務器本機存放區的使用者會話狀態限制的應用程式的多個實例上運行,因為從單一使用者的後續 HTTP 要求可以最終在不同的 Web 服務器實例上的能力。因為每個 Web 服務器實例在其自己的本地記憶體中保存其自己的副本的狀態,你可以得到不同 InProc 會話狀態物件在同一使用者的不同實例。這可導致意外和不一致的灌輸。在這裡,您可以看到的 WebSecurity 類可以用來管理使用者的狀態:

_AppStart.cshtml

@{
  WebSecurity.InitializeDatabaseConnection
    ("PhotoGallery", "UserProfiles", "UserId", "Email", true);
}

Upload.cshtml

@{
  WebSecurity.RequireAuthenticatedUser();
    ...
...
}

WebSecurity 類是一個幫手,簡化了程式設計ASP.NETWeb 頁中的元件。在幕後,Web­安全類與依次執行執行安全任務所需的較低級別工作ASP.NET成員資格提供程式進行交互。ASP.NETWeb 頁中的預設成員資格提供的 SimpleMembershipProvider 類,預設情況下,其會話狀態模式是 InProc。

最後,照片畫廊 Web 應用程式的當前版本在資料庫中,每一張照片作為位元組陣列存儲的照片。本質上,因為應用程式使用SQL Server快遞,照片保存在本地磁片上。相冊應用程式,用於的主要方案之一查看照片,因此應用程式可能需要處理和顯示的許多照片請求。從資料庫中讀取的照片是不甚理想。即使使用更複雜的資料庫,如SQL Server或 SQL Azure 資料庫中,並不理想,主要是因為檢索照片是一個昂貴的操作。

總之,這個版本的照片庫是一個有狀態的應用程式,和有狀態應用程式不能擴展以及跨多個實例。

第二步:修改照片畫廊是一個無狀態的 Web 應用程式

現在,我已經解釋過的一些關於縮放照片庫應用程式的限制,我會解決他們一個個來提高應用程式的規模能力。在第二步,我就會進行必要的更改,將從狀態轉換照片庫,為無國籍。在結束的第二步,更新的照片庫的應用程式將能夠安全地規模和運行多個 Web 服務器實例 (Vm)。

第一,我會用一個更強大的資料庫伺服器替換SQL Server快遞 — — Azure SQL 資料庫中,從微軟 Azure 服務平臺的一部分,作為提供資料存儲功能的基於雲計算的服務。天青 SQL 資料庫標準和高級 Sku 提供先進的業務連續性功能,我將使用在步驟 4 中。現在,我就只是將資料庫移轉從SQL Server快遞到 Azure 的 SQL 資料庫。你可以輕鬆地使用 WebMatrix 資料庫移轉工具或其他任何你想要將自衛隊檔轉換成 SQL Azure 資料庫格式的工具。

只要我已經感到遷移資料庫,它是一個很好的機會,使一些架構修改,雖然小,將對應用程式的擴展能力有顯著的影響。

第一,我會將從 INT 一些 (畫廊、 照片、 UserProfiles 等等) 的表的 ID 列類型轉換為 GUID。這種變化會有用在第四步,當我更新的應用程式運行在多個地區並需要保持的資料庫和照片的內容同步。它是重要的是請注意這種修改不會強制更改任何代碼上的應用 在應用程式中的所有 SQL 查詢都保持不變。

接下來,我會停止將照片存儲在資料庫中以位元組陣列。這種變化涉及到架構和代碼的修改。我會刪除 FileContents 和檔案大小列從照片表,存儲照片直接到磁片中,並使用照片的身份證,現在是一個 GUID,作為判別照片的手段。

下面的代碼片段顯示了更改 (請注意 fileBytes 和 fileBytes.Length 存儲在資料庫中直接) 之前插入語句:

db.Execute(@"INSERT INTO Photos
  (Id, GalleryId, UserName, Description, FileTitle, FileExtension,
  ContentType, FileSize, UploadDate, FileContents, Likes)
  VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10)",
  guid.ToString(), galleryId, Request.GetCurrentUser(Response), "",
  fileTitle, fileExtension, fileUpload.ImageFormat, fileBytes.Length,
  DateTime.Now, fileBytes, 0);

在這裡是資料庫更改後的代碼:

using (var db = Database.Open("PhotoGallery"))
{
  db.Execute(@"INSERT INTO Photos
  (Id, GalleryId, UserName, Description, FileTitle, FileExtension,
  UploadDate, Likes)
  VALUES (@0, @1, @2, @3, @4, @5, @6, @7)", imageId, galleryId,
  userName, "", imageId, extension,
  DateTime.UtcNow, 0);
}

在第三步,我將探討在更多的細節我如何修改應用程式。現在,可以這樣說照片被保存到一個中央位置,如一個共用磁片上,可以訪問所有的 Web 服務器實例。

我會在第二步的最後更改是停止使用 InProc 會話狀態。如前所述,WebSecurity 是一個説明器類,與ASP.NET成員資格提供程式進行交互。預設情況下,ASP.NETSimpleMembership 會話狀態模式是 InProc。有幾個進程外選項,您可以使用 SimpleMembership,包括SQL Server和ASP.NET狀態伺服器服務。這兩個選項啟用會話狀態,在多個 Web 服務器實例之間共用,避免伺服器的親和力 ; 那就是,它們不需要要被綁在一個特定的 Web 服務器的會話。

我的方法還管理進程,具體地使用一個資料庫和 cookie 狀態。然而,我依靠我自己的執行,而不是ASP.NET,本質上是因為我想讓事情簡單。執行使用 cookie,並將會話 ID 和它的狀態存儲在資料庫中。一旦一個使用者登錄時,我作為一個會話 ID,在資料庫中存儲分配一個新的 GUID。該 GUID 也會返回給使用者在以 cookie 的形式中。下面的代碼演示的 CreateNewUser 方法,被稱為在每次使用者登錄:

private static string CreateNewUser()
{
  var newUser = Guid.NewGuid();
  var db = Database.Open("PhotoGallery");
db.Execute(@"INSERT INTO GuidUsers (UserName, TotalLikes) VALUES (@0, @1)",
  newUser.ToString(), 0);
  return newUser.ToString();
}

當回應的 HTTP 要求,GUID 是一個 cookie 作為嵌入在 HTTP 回應中。 使用者名傳遞給方法是只是所示的 CreateNewUser 函數的乘積 AddUser 像這樣:

public static class ResponseExtensions
{
  public static void AddUser(this HttpResponseBase response, 
    string userName)
  {
    var userCookie = new HttpCookie("GuidUser")
    {
      Value = userName,
      Expires = DateTime.UtcNow.AddYears(1)
    };
    response.Cookies.Add(userCookie);
  }
}

當處理傳入的 HTTP 要求,第一次嘗試中提取的使用者 ID,表示為一個 GUID,從 GuidUser 餅乾了。接下來,我看為那在資料庫中的使用者 Id (GUID),提取任何特定于使用者的資訊。圖 1顯示得到的一部分,­CurrentUser 執行。

圖 1 GetCurrentUser

public static string GetCurrentUser(this HttpRequestBase request,
   HttpResponseBase response = null)
  {
    string userName;
    try
    {
      if (request.Cookies["GuidUser"] != null)
        {
          userName = request.Cookies["GuidUser"].Value;
          var db = Database.Open("PhotoGallery");
          var guidUser = db.QuerySingle(
            "SELECT * FROM GuidUsers WHERE UserName = @0", userName);
          if (guidUser == null || guidUser.TotalLikes > 5)
            {
              userName = CreateNewUser();
            }
        }
      ...
...
}

CreateNewUser 和 GetCurrentUser 是 RequestExtensions 類的一部分。同樣,AddUser 是 ResponseExtensions 類的一部分。這兩個類插到ASP.NET請求處理管道中,處理請求和回應,分別。

我的方法來管理會話狀態是相當天真一個作為它不安全和不會強制任何身份驗證。然而,它顯示的進程外的會話管理效益和規模。當您實現您自己的會話狀態管理,無論你基礎ASP.NET時,請確保您使用安全的解決方案,其中包括身份驗證和安全的方式來加密您返回的 cookie。

在這一點上,我可以放心地宣稱更新的照片庫的應用程式現在是一個無狀態的 Web 應用程式。通過當地的SQL Server快遞資料庫執行替換 SQL Azure 資料庫,並更改實現會話狀態從 InProc 到出過程中,使用一個 cookie 和一個資料庫,我成功轉換應用程式從有狀態為無狀態的如所示圖 2


圖 2 修改的照片庫應用程式的邏輯表示形式

採取必要的步驟,以確保您的 Web 應用程式是無狀態的可能是最有意義的任務在一個 Web 應用程式的開發過程中。跨多個 Web 服務器實例,與使用者的狀態、 資料損壞或功能的正確性,沒有擔心安全地運行的能力是擴展 Web 應用程式的最重要因素之一。

第三步:更多的改進,走很長的路

照片畫廊 Web 應用程式中第二步所做的更改確保應用程式是無狀態的可以安全地擴展到多個 Web 服務器實例。現在,我會讓一些額外的改進,進一步提高應用程式的可伸縮性特徵,使 Web 應用程式來處理更大的負載,用更少的資源。在此步驟中,我將回顧存儲策略和位址非同步設計模式,增強使用者體驗的性能。

第二步中討論的變化之一保存照片,到一個中央位置,如一個共用磁片上的所有 Web 服務器實例可以都訪問,而不一個資料庫。Azure 網站架構,確保跨多個 Web 服務器運行一個 Web 應用程式的所有實例都共用同一磁片,,作為圖 3 說明了。


圖 3 與微軟 Azure Web 網站,一個 Web 應用程式的所有實例見到相同的共用的磁片

照片畫廊 Web 應用的角度出發,從"共用的磁片"意味著當一張照片獲取由使用者上傳,它被保存到.../uploaded 資料夾,看上去像一個本地資料夾。但是,當圖像寫入到磁片,它不"本地保存"在特定的 Web 服務器上這一控制碼在 HTTP 要求,但相反保存到所有的 Web 服務器可以訪問的中央位置。因此,任何伺服器可以寫到共用磁片的任何照片和所有其他 Web 服務器可以讀取該圖像。照片中繼資料是存儲在資料庫中,由應用程式用於讀取照片 ID — — 一個 GUID — — 並作為 HTML 回應的一部分返回的圖像的 URL。下面的程式碼片段是 view.cshtml,它是我用來啟用查看圖像的頁面的一部分:

    <img class="large-photo" src="@ImagePathHelper.GetFullImageUrl(photoId,
      photo.FileExtension.ToString())" alt="@Html.AttributeEncode(photo.FileTitle)" />

由 GetFullImageUrl helper 函數,它採用照片 ID 和檔副檔名 (如.jpg、.png 等等),並返回一個字串,表示的圖像的 URL 的傳回值填充圖像 HTML 元素的來源。

將照片保存到一個中央位置可以確保 Web 應用程式是無狀態的。 然而,與當前實現中,直接從一個運行的 Web 應用程式的 Web 服務器之間提供給定的圖像。 具體來說,每個圖像源的 URL 指向 Web 應用程式的 URL。 因此,圖像本身被服務從 Web 服務器運行的 Web 應用程式,這意味著作為從 Web 服務器的 HTTP 回應發送的實際位元組數的圖像之一。 這意味著您的 Web 服務器,在處理動態 Web 頁,也是靜態內容如圖像。 Web 服務器可以為大量的靜態內容服務在大尺度上,但這樣做所以規定收費上的資源,包括 CPU、 IO 和記憶體。 如果您可以確保只有靜態內容如照片,並不直接從運行您的 Web 應用程式的 Web 服務器服務,但而是從其他地方,您可以減少擊中的 Web 服務器的 HTTP 要求的數量。 通過這樣做,你將免費要處理更動態的 HTTP 要求的 Web 服務器上的資源。

第一次的轉變,使是使用 Azure Blob 存儲 (bit.ly/TOK3yb) 來存儲和服務使用者的照片。 當使用者想要查看圖像,URL 返回更新後的 GetFullImageUrl 點到 Azure Blob。 最終的結果看起來像下面的 html 代碼,圖像 URL 指向 Blob 存儲的位置:

    <img class="large-photo" alt="764beb6b-1988-42d7-9900-03ee8a60749b"
      src="http://photogalcontentwestus.blob.core.windows.
    net/
      full/764beb6b-1988-42d7-9900-03ee8a60749b.jpg">

這意味著圖像提供服務,直接從 Blob 存儲而不是從運行的 Web 應用程式的 Web 服務器。

與此相反的是,下面的顯示照片保存到共用磁片中 Azure 的 Web 網站:

<img class="large-photo" alt="764beb6b-1988-42d7-9900-03ee8a60749b"
  src="http:// builddemophotogal2014.websites.
net/
  full/764beb6b-1988-42d7-9900-03ee8a60749b.jpg">

照片畫廊 Web 應用程式使用兩個容器,充分和縮略圖。 正如你期望的滿商店照片在其原來的大小,而縮略圖存儲較小的圖像顯示在庫中查看。

public static string GetFullImageUrl(string imageId, 
  string imageExtension)
{
  return String.Format("{0}/full/{1}{2}",
    Environment.ExpandEnvironmentVariables("%AZURE_STORAGE_BASE_URL%"),
    imageId, imageExtension);
}

AZURE_STORAGE_BASE_URL 是一個環境變數包含的基 URL 的 Azure Blob,在這種情況下,-HTTP://­photogalcontentwestus.blob.core.windows。淨。此環境變數可以設置在 Azure 門戶中在網站配置選項卡,或者它可以是應用程式的 web.config 的一部分。從 Azure 門戶設置環境變數給你更多的靈活性,但是,因為它更容易去改變而不需要重新部署。

Azure 存儲空間用於很多內容傳遞網路 (CDN) 相同的方式,主要是因為 HTTP 要求的圖像並不從應用程式的 Web 服務器,而是直接從 Azure 存儲容器被送達。這極大地減少了曾經到達您的 Web 服務器,允許 Web 服務器來處理更多動態請求的靜態 HTTP 要求通信量。此外請注意 Azure 存儲可以處理的流量更多,比你平均的 Web 服務器 — — 單個容器可以擴展以服務于許多數以萬計的每秒請求數。

除了使用 Blob 存儲為靜態內容,你還可以添加微軟 Azure CDN。添加一個 CDN 在您的 Web 應用程式進一步提高了性能,如 CDN 將為所有靜態內容提供服務。一張照片已經緩存在 CDN 的請求就不會到達 Blob 存儲。此外,CDN 也可提高感知的性能,作為 CDN 通常具有邊緣伺服器更接近到最終客戶。向應用程式範例中添加一個 CDN 的細節是超出了這篇文章的範圍所做的更改的大多圍繞在 DNS 註冊和配置。但當你解決規模生產,你想要確保您的客戶將享受快速、 反應靈敏的使用者介面,您應該考慮使用 CDN。

我還沒有審查處理使用者上傳的圖片的代碼,但這是一個很大的機會來解決一個基本的非同步模式,提高了 Web 應用程式的性能和體驗你會看到在步驟 4 中,這也將有助於兩個不同區域之間的資料同步。

我會讓照片畫廊 Web 應用程式的下一個更改是添加 Azure 存儲佇列,作為一種方式來分隔的前端與後端業務邏輯 (WebJob + 資料庫) 的應用程式 (Web 網站)。沒有一個佇列,照片庫代碼處理這兩個前端和後端,作為上傳代碼保存到存儲,創建一個縮略圖完全尺寸的圖像和保存到存儲,以及更新了SQL Server資料庫。那段時間,使用者等待回應。然而,隨著 Azure 存儲佇列的引入,前端只是將消息寫入佇列和立即將回應返回給使用者。一個後臺進程,WebJob (bit.ly/1mw0A3w)、 拾取消息從佇列並執行所需的後端業務邏輯。為照片庫中,這包括操作圖像、 將其保存到正確的位置和更新資料庫。圖 4 說明了在第三步,包括使用 Azure 存儲和添加佇列所做的更改。


圖 4 邏輯表示形式的照片畫廊郵政第三步

現在,我有一個佇列,我需要改變的 upload.cshtml 代碼。下面的代碼中你可以看到而不是執行複雜的業務邏輯與影像處理,我使用 StorageHelper 到佇列的消息 (該消息包含照片的身份證,這張照片的檔副檔名和畫廊 ID):

var file = Request.Files[i];
var fileExtension = Path.GetExtension(file.FileName).Trim();
guid = Guid.NewGuid();
using
var fileStream = new FileStream(
 Path.Combine( HostingEnvironment.MapPath("~/App_Data/Upload/"),
 guid + fileExtension), FileMode.Create))
{
  file.InputStream.CopyTo(fileStream);
  StorageHelper.EnqueueUploadAsync(
    Request.GetCurrentUser(Response),
     galleryId, guid.ToString(), fileExtension);
}

StorageHelper.EnqueueUploadAsync 只是創建 CloudQueueMessage,並以非同步方式將它上載到 Azure 存儲佇列:

public static Task EnqueueUploadAsync
  (string userName, string galleryId, string imageId, 
    string imageExtension)
{
  return UploadQueue.AddMessageAsync(
    new CloudQueueMessage(String.Format("{0}, {1}, {2}, {3}",
    userName, galleryId, imageId,
    imageExtension)));
}

WebJob 現在是負責後端業務邏輯。 新的 WebJobs 功能的 Azure 網站提供簡便的方法在 Web 網站上運行程式 (如服務或背景工作。 WebJob 偵聽佇列上的變化並撿起任何新郵件。 在所示的 ProcessUploadQueueMessages 方法圖 5,被稱為有時至少一個消息在佇列中。 QueueInput 屬性是微軟 Azure WebJobs SDK 的一部分 (bit.ly/1cN9eCx),這是一個框架,簡化了添加到 Azure 網站的幕後處理的任務。 WebJobs SDK 是超出了這篇文章的範圍,但你真正需要知道的就是 WebJob SDK 讓您輕鬆地將綁定到一個佇列,在我的案例 uploadqueue,,聽聽傳入的消息。

圖 5 從佇列中讀取消息和更新資料庫

public static void ProcessUploadQueueMessages
  ([QueueInput(“uploadqueue”)] string queueMessage, IBinder binder)
{
  var splited = queueMessage
    .Split(‘,’).Select(m => m.Trim()).ToArray();
  var userName = splited[0];
  var galleryId = splited[1];
  var imageId = splited[2];
  var extension = splited[3];
  var filePath = Path.Combine(ImageFolderPath, 
    imageId + extension);
  UploadFullImage(filePath, imageId + extension, binder);
  UploadThumbnail(filePath, imageId + extension, binder);
  SafeGuard(() => File.Delete(filePath));
  using (var db = Database.Open(“PhotoGallery”))
  {
    db.Execute(@”INSERT INTO Photos Id, GalleryId, UserName,
      Description, FileTitle, FileExtension, UploadDate, Likes)
      VALUES @0, @1, @2, @3, @4, @5, @6, @7)”, imageId,
      galleryId, userName, “”, imageId, extension, DateTime.UtcNow, 0);
  }
}

每個消息進行解碼,將輸入的字串拆分為其各自的零件。接下來,該方法將調用兩個説明器函數來操縱和上傳圖片到 Blob 容器。最後,更新資料庫。

在這一點上,更新的照片畫廊 Web 應用程式可以處理數以百萬計的每一天的 HTTP 要求。

第四步:全球影響力

我已經縮放能力照片畫廊 Web 應用程式的巨大改進。如前所述,應用程式現在可以處理數以百萬計的使用 Azure 網站上只有幾個大型伺服器的 HTTP 要求。目前,所有這些伺服器都位於單個 Azure 資料中心。雖然從單個資料中心的運行並不確切地規模限制 — — 至少不是由標準的定義的規模 — — 如果你從全球各地的客戶需要低延遲時間,你需要從多個資料中心運行您的 Web 應用程式。這也提高了 Web 應用程式中的耐久性和業務連續性功能。在罕見的情況下,另一個資料中心經驗中斷,您的 Web 應用程式將繼續服務于交通從第二個位置。

在這一步,我會給應用程式,使它能夠跨多個資料中心運行所做的更改。對於本文,我將重點介紹運行從兩個位置在主動-主動模式下,在這兩個資料中心中的應用,允許使用者查看的照片,以及上傳照片和評論。

請記住因為我明白照片畫廊 Web 應用程式的上下文,知道大部分使用者操作讀取操作,顯示的照片。只有少量使用者請求涉及上載新照片或更新的評論。照片畫廊 Web 應用程式,我可以安全地讀/寫比率是至少 95%的讀取。這樣我可以做一些假設,例如,整個系統具有最終一致性是可以接受的也是為寫操作的回應較慢。

它是重要的是理解這些假設是上下文感知和依賴于給定的應用程式的具體特點和將最可能發生的變化,從到另一個應用程式。

出人意料的是,從兩個不同的位置運行照片庫所需的工作量很小,因為繁重的工作大部分在第二步和第三步完成。圖 6 從兩個不同的資料中心中運行的應用程式拓撲中的高級別塊示意圖。在美國西部的應用是"主"應用程式,基本上有三步的輸出。在東美國中的應用是"次要"的網站,,Azure 交通經理放在兩個。蔚藍的流量管理器的幾個配置選項。我會使用性能選項,會使交通管理器監視這兩個網站在其各自區域的延遲和路由流量的基礎最低的延遲。在這種情況下,客戶從紐約 (東海岸) 將被定向到東美國網站和客戶從 San Francisco (西海岸) 將向美國西部網站。這兩個網站在同一時間,服務交通活動。在一個區域中的應用應該遇到性能問題,不管什麼原因,流量管理器將通信路由到其他應用程式。資料同步,因為沒有資料應該會丟失。


圖 6 邏輯表示形式的照片畫廊郵政第四步

我會看看對美國西部的更改應用程式。代碼更改只是到 WebJob 偵聽佇列中的消息。而不是將照片保存到一個 Blob,WebJob 將照片保存到本地和"遠端"Blob 存儲區。在圖 5,UploadFullImage 是一個説明器方法,將照片保存到 Blob 存儲。要啟用遠端 Blob,以及當地的 Blob 複製一張照片,我的 ReplicateBlob helper 函數末尾添加的 UploadFullImage,正如你看到的在這裡:

private static void UploadFullImage(
  string imagePath, string blobName, IBinder binder)
{
  using (var fileStream = new FileStream(imagePath, FileMode.Open))
  {
    using (var outputStream =
      binder.Bind<Stream>(new BlobOutputAttribute(
      String.Format("full/{0}", blobName))))
    {
      fileStream.CopyTo(outputStream);
    }
  }
  RemoteStorageManager.ReplicateBlob("full", blobName);
}

下面的代碼中的 ReplicateBlob 方法有一個重要的行 — — 最後一行調用 StartCopyFromBlob 方法,並提出要將所有的內容、 屬性和中繼資料的 Blob 複製到一個新的 Blob (我讓照顧其餘的 Azure SDK 和存儲服務) 的服務:

public static void ReplicateBlob(string container, string blob)
{
  if (sourceBlobClient == null || targetBlobClient == null)
    return;
  var sourceContainer = 
    sourceBlobClient.GetContainerReference(container);
  var targetContainer = 
    targetBlobClient.GetContainerReference(container);
  if (targetContainer.CreateIfNotExists())
  {
    targetContainer.SetPermissions(sourceContainer.GetPermissions());
  }
  var targetBlob = targetContainer.GetBlockBlobReference(blob);
  targetBlob.StartCopyFromBlob(sourceContainer.GetBlockBlobReference(blob));
}

東,美國的 ProcessLikeQueueMessages 方法不會處理任何事情 ; 它只是將郵件推送到美國西部 佇列。 將處理的郵件,在美國西部,將複製的圖像,正如剛才所和資料庫會進行同步,我現在會解釋。

這是最後一塊拼圖的魔法 — — 同步資料庫。 要實現這一目標,我將使用 SQL Azure 資料庫的主動 Geo-複製 (連續複製) 預覽功能。 使用此功能,你可以有二次唯讀資料庫的複製副本你主。 寫到主資料庫的資料自動複製到次要資料庫。 主人被配置為讀寫資料庫和所有次要資料庫是唯讀的這是我的方案中的消息都從東美國推的原因 到美國西部的佇列 一旦您配置活動的土力工程處複製 (通過入口網站),資料庫將保持同步。 不需要更改代碼需要超越我已經介紹過。

總結

微軟 Azure 可以讓你構建 Web 應用程式,可以擴展了很多很小的努力。 在這篇文章,表明的: 怎麼了,在幾個步驟,您可以修改 Web 應用程式從一個真的不能因為它不能運行在多個實例,為一種可以運行不僅是跨多個實例,也是跨多個地區,在所有規模處理數以百萬計 (高數千萬人) 的 HTTP 要求。 例子是特定于特定的應用程式,但概念是有效的可以在任何給定的 Web 應用程式上執行。

Yochay Kiriaty 是一個主要的專案經理帶領微軟 Azure 團隊,工作 Azure 網站上.聯繫到他在 yochay@microsoft.com 和跟著他在 Twitter 上 twitter.com/yochayk

感謝以下的微軟技術專家對本文的審閱:Mohamed 阿明易卜拉欣