程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF P2P如何在對等網絡中設計狀態共享

WCF P2P如何在對等網絡中設計狀態共享

編輯:關於.NET

本文將介紹以下內容:

固定的狀態服務器

選擇的狀態服務器

無服務器的數據沖擊

最近對等同步

本文使用了以下技術 :

WCF

目錄

固定的狀態服務器

瞬時選擇的狀態服務器

純對等無服務 器的數據沖擊

最近對等同步

WeSpend 示例應用程序

後續 步驟

近年來,人們開始發現利用對等網絡通信的應用程序具有令人驚奇 的強大功能。所謂的對等應用程序的范圍從簡單的文件共享到即時消息 (IM) 再 到功能齊全的協作應用程序(如共享白板、IP 語音 (VoIP) 呼叫和會議、社會 化網絡等)。

考慮一下 Xbox 360® 是如何自動檢測是否存在另一運 行 Windows Media® Center 的計算機並立即開始與該計算機共享音頻和視 頻,從而在您的 Xbox® 上播放計算機中的音樂的。如果業務應用程序都支 持相同類型的對等識別和功能豈不是大快人心?如果有人在其桌面上創建了一條 新記錄,組織內使用該應用程序的所有其他人都可以立即看到該新記錄,並且您 不必安裝和配置中心服務器即可實現此功能,想想客戶會有多麼滿意吧。

本文主要介紹了通過允許業務應用程序在無服務器的對等網絡中共享狀 態來實現其對等功能的內容。在深入研究示例應用程序之前,我想談一談人們通 常在對等網絡中實現狀態共享的一些方法,以及這些方法的優缺點。最後,我將 向您展示一個名為 WeSpend 的示例應用程序,此工具可用於跟蹤您的存折分類 帳。此應用程序可自動與家庭網絡中其自身的所有其他實例同步數據。

有多少種可能的應用程序思路就有多少種實現對等網絡的方法。每種實現都具有 其特定的優點和缺陷。其中有些方面與基礎結構相關,有些與隨著時間的推移維 護解決方案的難易程度有關,而其他則與最初開發解決方案時的輕松程度有關。 在本部分中,我將介紹人們在開發對等網絡時最常使用的一些方法。

固 定的狀態服務器

當許多開發團隊解決了實現對等的應用程序的初始概念 階段並著手實現時,面臨的首要問題之一通常是:如何共享狀態?

其中 一個最簡單的解決方案是創建混合對等網絡。在該解決方案中,所有的廣播和對 等通信都是在對等網格上發生的,其中有一個眾所周知的中心服務器,它通常通 過 Web 服務或其他的 Windows® Communication Foundation (WCF) 服務始 終保持狀態。這樣網絡中的對等點即可識別整個應用程序的單例狀態,並能夠很 好地使用優化後的對等網格通信。

此類網絡的最常見示例是社會化網絡 和 IM 應用程序。IM 應用程序通常需要一個中心服務器來維護登錄人員列表、 其狀態和可用性以及所有注冊用戶的好友列表(請參閱圖 1)。網絡用戶之間以 點對點方式進行通信。典型的客戶端-服務器和點對點功能之間存在一個極其有 用且功能強大的功能拆分。

圖 1 對等網絡中的中心狀態服務器

這種模式的好處是非常易於實現。對 等網絡組件並不復雜,並且近年來 Microsoft® .NET Framework 和 WCF 的 使用使得與中心服務器的通信變得極其輕松。

不足之處是此基礎結構需 要一台中心服務器。對等應用程序需要知道該服務器的地址,否則可能導致配置 和維護問題。此外,許多應用程序開發人員都沒有資源來全局部署中心狀態服務 器,並且應用程序的規范通常都無法滿足中心狀態服務器的要求。

瞬時 選擇的狀態服務器

共享狀態模式演變的下一步驟是通過將對等網格中的 其中一個節點選作狀態服務器來緩解之前模式中的基礎結構問題。通常,您可以 在聯網的即時策略游戲中發現此模式,即啟動游戲者具有“實際副本 ”的游戲狀態,而其他所有人具有同步的副本。

此模式的工作原理 是利用一種算法選擇節點作為網格的狀態服務器。在該節點成為狀態服務器後, 網格中的所有其他節點將遵循固定狀態服務器方案中的相同模式更新和查詢單例 狀態。

盡管這樣消除了需要固定中心服務器的問題,卻催生出了復雜的 選擇系統的問題。要實現此類對等網格,首先需要確定如何選擇狀態服務器。一 個簡單易行的解決方案是選取最舊的節點(在網格中存在時間最長的節點)或最 新的節點。當節點離開網格時就會產生問題。如果所選的狀態服務器離線會發生 什麼情況?如果網格發現其離線,對等點可選擇一台新的狀態服務器。但如果狀 態服務器只是速度非常慢而並未離線,並且網格尚未決定重新選擇新的狀態服務 器,又會發生什麼情況呢?

正如您所看到的,此解決方案的缺點是盡管 它對中心服務器的基礎結構沒有要求,但產生了可能導致項目中止的復雜問題, 即要求構建一個選擇系統,它不但能選擇最佳的候選對象作為狀態服務器,並且 有足夠的恢復能力來解決狀態服務器的黑洞問題(消息只進不出,與簡單的離線 稍有不同)或狀態服務器離線問題。

如果真正出色地解決了選擇系統這 一復雜問題,則該系統將成為一個功能強大且多用途的系統。如果選擇系統處理 欠佳,則此類網絡將以慘敗告終且狀態共享會產生無數的問題。

純對等 無服務器的數據沖擊

前兩種方案試圖提供一種有且僅有一個權威狀態副 本的解決方案。無論狀態服務器的位置是固定還是選擇得出的,對等點查詢和操 作狀態的方式始終都是相同的:與單個遠程服務器聯系。

中心狀態服務 器的一種常見替代方案是我稱為“數據沖擊”網絡的方法。在此方案 中,每當有新對等點加入網格或某個對等點明確要求更新數據時,對等點即會將 其數據副本廣播到網格中的所有其他對等點。對等點每次收到狀態數據廣播時都 會將廣播內容與本地狀態進行比較,並相應地進行更新。

但此方法有兩 個相當明顯的弊端。第一個是網絡中發送的冗余數據量會變得相當大。對等網絡 上的計算機越多,浪費的帶寬就越多。實際上,此方案中的冗余數據傳輸量會隨 著網格中節點數的增加而呈指數級增長。

此方法的另一弊端是,由於每 個應用程序都廣播自身數據的副本,因此在接收廣播數據時,必須執行一個同步 操作來比較接收數據和本地數據並協調二者之間的差異。隨著對等網絡大小的增 加,可能出現狀態廣播尚未處理完下一消息即到達的情形,從而產生瓶頸並可能 降低應用程序自身的性能。必須通過某種方法將廣播中發送的數據標識為唯一, 因為對等網格中的每個節點都需要檢查數據是否重復。

這種在某種程度 上折衷的網絡資源浪費的好處是不需要中心狀態服務器且不會遇到選擇模式所引 發的復雜性問題。在某些情形下,尤其是在知道節點數絕不會超過特定的大小時 ,所減少的實施工作量絕對值得重復的數據傳輸。

最近對等同步

在研究可能實施選擇方案的各種方法時,我發現 WCF 中有個屬性可用於指示特 定消息行進的最大跳轉數。了解到這一點後,很顯然存在一種用於在對等網絡中 共享狀態的方法,該方法不僅不需要中心服務器,而且能抵御節點丟失且不需要 選擇。我將其稱為“最近對等同步”。

在對等網格中,任意 兩個節點間的任何消息所采用的路由全部由 WCF 規定。這使得 WCF 可以優化網 絡中的通信路徑。了解這一點並知道可將消息經過的距離限制為單跳距時,即可 實現鄰居同步模式來共享狀態。

首先,在加入網格之後,新加入的節點 將向外發送單跳消息以請求共享狀態記錄的唯一記錄標識符列表。網格中單跳距 的所有節點都將接收到此消息。然後,這些節點使用回調約定直接回復網格。該 回復包括該節點維護的所有數據記錄的唯一 ID 列表。將優先考慮第一個回復並 忽略所有其他回復。請記住,必須編寫用於忽略重復消息的代碼。WCF 不會替您 執行此操作。

然後,新加入的節點將唯一 ID 列表與自己的唯一 ID 列 表進行比較(因為它可能仍保持磁盤上的離線狀態且擁有部分共享狀態視圖)。 此後,將回復中已接收到但並未包含在本地狀態中的唯一 ID 向外發送到單跳消 息中的網格。回復該消息的第一個節點(再次使用該回調約定)將回復其中每個 唯一 ID 的詳細信息。詳細信息通常是一個完全有序且可序列化的對象。

此模式的亮點是能夠自動進行修正以消除故障節點。如果網格中某個節 點出現故障,將不會響應數據請求。然後,單跳距的所有其他節點都將有機會回 復該數據。如果網格的組織方法規定新加入的節點只能與一個出現故障的節點通 信,WCF 現在將過去為雙跳距的節點視為單跳距節點。無需選擇邏輯,並且在 WCF 對等通道層中直接使用自動故障轉移而不必編寫任何其他代碼。由於能保證 每個鄰居都與每個鄰居的狀態同步,因此狀態會自動在網格中所有對等點之間傳 播。圖 2 顯示了節點自動與鄰居同步的純無服務器的對等網格。

圖 2 無狀態服務器的對等網格

WeSpend 示例應用程序

為了將這 些想法轉化成具體的操作,讓我們來看一個有關個人財務管理器的模擬。用戶可 利用該管理器跟蹤對支票帳戶執行的財務事項(如填寫支票或借貸交易)。

因為網絡上運行的所有應用程序副本都會自動與其他副本共享其狀態, 因此 WeSpend 是一個協作對等應用程序。舉例講,其用戶識別效果相當於樓下 的一名家庭成員在 WeSpend 中輸入一筆交易時,樓上的另一家庭成員會立即看 到這筆新交易。當同一家庭中的第三個人啟動全新的 WeSpend 副本時,他會自 動接收應用程序尚未激活時已創建的交易。這些對等識別和協作功能的添加使出 色的熱門應用程序和簡單的普通應用程序迥然不同。

WeSpend 使用最近 的鄰居同步共享狀態模式。WCF 的幾個關鍵技術組件保證了這種應用程序的實現 。第一個是已介紹過的屬性 PeerHopCount,可用於規定僅將消息內容傳輸固定 的次數後就丟棄。此屬性可將數據消息的屬性轉變成與生存時間 (TTL) 的 IP 概念非常相似的內容。

以下是 WeSpend 應用程序中的一個 WCF 消息約 定示例,此應用程序中包括一個用於控制對等跳數的字段。必須注意,對等跳數 屬性僅供 NetPeerTcpBinding 協議綁定使用。所有其他綁定將忽略該屬性:

[MessageContract]
public class TransactionIdRequest {
  [MessageBodyMember]
  public string Requester;
  [PeerHopCount]
  public int Hops;
  public TransactionIdRequest() {
    Hops = 1;
  }
}

將此消息傳送到網格上時,不會出現向每個可用節點發送消息的 常見泛濫行為。相反,消息僅向外發送一次,之後該消息將消失。這樣您只能從 網格中最近的鄰居處請求交易 ID 列表。

實現此方案的另一關鍵組件是 回調約定的使用。當一個對等點對另一個 WCF 對等點調用某個方法時,目標代 碼可回調啟動方法調用的對等點網格。從而允許單個節點回復鄰居的請求,同時 省卻了在每個對等節點上托管獨立的 WCF 服務的需要。下面是使用回調約定回 復交易 ID 請求的代碼示例:

public void RequestTransactionIds(TransactionIdRequest request) {
   List<Guid> outboundIds = new List<Guid>();
   foreach (Transaction tx in ModelRoot.Current.Transactions) {
     outboundIds.Add(tx.TransactionID);
  }
   CallbackChannel.TransactionIdsReply(new TransactionIdReply() {
     ReplyFrom = AppController.Current.Username,
     TransactionIDs = outboundIds
  });
}

此處的回 調通道用於回復啟動該方法調用 RequestTransactionIds 的對等點。請記住, TransactionIdRequest 消息僅限於單跳距,因此即使在最大的對等網絡中,啟 動對等方也不會收到蜂擁而至的泛濫回復。

當對等節點(通過調用 TransactionIdsReply 方法)接收到交易 ID 列表時,它會再次使用回調約定請 求本地存儲中缺少的有關這些 ID 的詳細信息(如圖 3 所示)。

圖 3 請求交易詳細信息

public void TransactionIdsReply (TransactionIdReply reply)
{ 
  // Compare the list of TX IDs with the list of IDs in local storage
  // for each item that is "missing" from local storage, put that item
   // in the request for details.
  List<Guid> output = new List<Guid>();
  foreach (Guid id in reply.TransactionIDs)
  {
    if (! ModelRoot.Current.Transactions.Any(
        tx => tx.TransactionID.Equals(id)))
    {
       output.Add(id);
      Console.WriteLine("[LTS] Need to request detail for TX " +
        id.ToString());
    }
  }
   CallbackChannel.RequestTransactionDetails(output);
}

當同步對的另一半調用其 RequestTransactionDetails 方法時 ,也將使用該回調約定來回復該網格(如圖 4 所示)。

圖 4 通過詳細信息進行回復

public void RequestTransactionDetails(List<Guid> transactionIds)
{
  List<LedgerTransaction> output = new List<LedgerTransaction>();
  foreach (Guid id in transactionIds)
  {
    Transaction tx = (from Transaction lt in
    ModelRoot.Current.Transactions
              where lt.TransactionID.Equals(id)
              select lt).FirstOrDefault();
    if (tx != null)
      output.Add(tx.ToLedgerTransaction());
   }
  CallbackChannel.TransactionDetailsAck(new TransactionDetailReply()
  {
    ReplyFrom = AppController.Current.Username,
    Transactions = output
  });
}

在實現 WCF 對等服務約定後,之前代碼列表 中所使用的屬性 CallbackChannel 定義如下:

protected ILedgerTransactionServiceChannel CallbackChannel {
  get {
    return OperationContext.Current.GetCallbackChannel<
      ILedgerTransactionServiceChannel>();
  }
}

圖 5 顯示了剛加入網格的對等點與最近的鄰居之間用於回復調 用以啟動同步操作的消息流。

圖 5 最近鄰同步順序

前述的方法實現中缺少的一樣東西是用於防止重新 進入的屏障。換言之,如果有多個對等點想要同時啟動某個同步操作,就需要生 產代碼來防止發生這種情況的發生。另請注意,代碼在執行同步操作時會使用大 量的回調約定。對等節點需要保證沒有其他的對等節點可同時執行同步,但我們 可通過一個簡單的 semaphore 做到這一點。

向應用程序添加對等聯網功 能可顯著改進客戶使用軟件時的體驗。但這樣做所時常使人們感到非常復雜,這 個障礙使得對等聯網功能超出了產品設計的范圍。由於復雜程度急劇攀升而無法 控制,使得某些實現的維護工作很快就會成為您的夢魇,人們不得已從規范中刪 除了對等聯網。

本文的目的是向您表明對等聯網不但很輕松就可實現, 甚至可實現高效、容錯且易於編寫代碼的無服務器狀態共享系統。另請注意,本 文所討論的模式幾乎存在無限種變體。

建議您下載並體驗該代碼示例。 它最適合於擁有兩台計算機並修改 app.config 來模擬兩個不同用戶名的工作環 境。在 txhost 應用程序設置為 true 的情況下(這意味著它創建了一些示例事 務),在啟動一個實例後,通過將 txhost 設為 false(不自動創建事務)來啟 動第二個實例。您會看到該事務從第一個實例自動傳播到第二個實例。單擊按鈕 創建一個新事務時,您會看到該事務同時出現在該示例應用程序的兩個正在運行 的示例中。要更加清楚地查看同步效果,可停止第二個實例然後重新啟動它。重 新啟動第二個實例時,將顯示所有的事務。根據對等名稱解析協議 (PNRP) 在計 算機上的運行方式,示例應用程序最多需要 30 秒即可首次開始通信。

Kevin Hoffman 是 Liquidnet Holdings, Inc. 的一名研究開發人員, 他還經常在 dotnetaddict.dotnetdevelopersjournal.com 上撰寫博客。他一直 滿腔熱情地致力於網絡、通信和分布式應用程序體系結構。早在 WCF 的代號仍 為“Indigo”時他就開始和它打交道了。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved