許多發佈/訂閱系統中的通訊相對簡單:例如幾乎所有 Java 式系統的通訊都透過遠端方法呼叫(remote method invocation)進行。

真正需要處理的重要問題出現在發佈/訂閱系統跨廣域系統部署時:發佈的資料應該送達相關的訂閱者。前一節描述過一種解法——用自組織方法讓點對點系統中的節點自動分群,再以群為單位散播。另一種解法是部署內容式路由(content-based routing)

內容式路由#

在內容式路由中,系統假設建立在點對點網路之上,訊息在節點之間被明確地路由。此架構的關鍵在於:路由器能根據訊息的內容做路由決策。更精確地說,假設每則訊息都帶有其內容的描述,而這份描述可以用來剪掉那些確定不通往感興趣接收者的路徑。

Carzaniga et al. (2004) 提出了一種實用的內容式路由做法。考慮一個由 N 台伺服器組成的發佈/訂閱系統,客戶端(應用程式)可向伺服器送出訊息或讀取進來的訊息;要讀取訊息,應用程式必須事先向伺服器提供它感興趣的資料描述,伺服器則在相關資料到達時通知應用程式。

Carzaniga 等人提出兩層路由方案:最底層是一棵連接 N 台伺服器的共享廣播樹(shared broadcast tree)。建樹方式有多種,從網路層多播支援到第 4 章討論過的應用層多播樹都可以。假設這棵樹已建好,N 台伺服器為端節點,另有一群中介節點作為路由器。

伺服器與路由器的區分只是邏輯上的:同一台機器可以同時承載兩種行程。

兩種極端做法#

先考慮只支援簡單的主題式發佈/訂閱(每則訊息帶一個唯一、非複合的關鍵字)時,內容式路由的兩個極端:

  1. 把每則發佈的訊息送到每台伺服器,再由伺服器檢查是否有客戶端訂閱了該訊息的主題。這本質上就是 TIB/Rendezvous 的做法。
  2. 讓每台伺服器把自己的訂閱廣播給所有其他伺服器。如此每台伺服器都能編出一份(主題, 目的地)清單。當應用程式提交主題為 s 的訊息時,其伺服器把目的伺服器清單附加在訊息前端;訊息到達路由器時,路由器即可依清單決定訊息該走的路徑。

圖 13-7:樸素的內容式路由。

路由過濾器#

以第二種做法為起點,可以進一步強化路由器決定轉發方向的能力:每台伺服器把訂閱廣播到整個網路,讓路由器組合出路由過濾器(routing filters)——一張對每條外出連結各有一個條目的表格。

例如:節點 3 訂閱屬性 a 落在 [0,3] 的訊息,節點 4 想要 a ∈ [2,5] 的訊息。則同時連向兩者的路由器 R2 會為它的三條外出連結(通往節點 3、節點 4、路由器 R1)各建一個條目。更上游的路由器 R1 則更有趣:節點 3 與 4 的訂閱合起來要求「任何 a 落在 [0,3] ∪ [2,5] = [0,5] 的訊息都應沿著通往 R2 的路徑轉發」,而這正是 R1 存進表格的資訊。不難想像還能支援更複雜的訂閱組合。

圖 13-8:部分填好的路由表。

這個簡單例子也說明:當節點離開系統、或不再對特定訊息感興趣時,它應取消訂閱,並且本質上得把這項資訊廣播給所有路由器,進而調整各處的路由過濾器。調整太慢頂多造成不必要的流量(訊息沿著已無訂閱者的路徑轉發),但要維持可接受的效能,及時調整是必要的

內容式路由的一個問題是:雖然組合路由過濾器的原理簡單,但判斷一則進來的訊息該沿哪些連結轉發可能非常耗費計算。計算複雜度來自屬性值與訂閱的比對實作——本質上是逐條目比較。如何有效率地做這種比較,見 Carzaniga et al. (2003)。

支援複合訂閱#

目前為止的例子都只是路由表的相對簡單延伸,足以應付「(屬性, 值/範圍)對向量」形式的訂閱。但實務上常需要更精緻的訂閱表達方式。例如訂閱的組合(compositions):一個行程在單一訂閱中指明它對非常不同型態的資料項都感興趣——比方它想同時看到 IBM 股票的資料項其營收資料,只送其中一種對它沒有用。

為處理訂閱組合,Li 與 Jacobsen (2005) 提議把路由器設計成類似規則資料庫(rule databases):訂閱被轉換成規則,描述在什麼條件下發佈的資料應該被轉發、以及沿哪些外出連結轉發。不難想像,這會導向比前述路由過濾器先進得多的內容式路由方案。

支援訂閱組合與協調式系統中的**命名(naming)**議題密切相關,下一節將討論。