在物件式分散式系統中,物件伺服器(object server)——專為代管分散式物件而設計的伺服器——扮演關鍵角色。本節先討論物件伺服器的一般面向,再以 Ice 執行期系統為例說明實務作法。
物件伺服器#
物件伺服器與傳統伺服器的重要差別:
- 物件伺服器本身不提供特定服務——具體服務由駐留其中的物件實作。
- 伺服器只提供「依遠端用戶端請求呼叫本地物件」的機制。
- 因此更換服務很容易:加入或移除物件即可。
物件伺服器是物件「居住」的地方。一個物件由兩部分組成:代表狀態的資料,以及執行方法的程式碼。這兩部分是否分離、方法實作是否由多個物件共用,都取決於物件伺服器的設計。
呼叫物件的各種政策#
要呼叫一個物件,伺服器必須知道執行哪段程式碼、操作哪份資料、是否另開執行緒等。假設「所有物件長得一樣、只有一種呼叫方式」雖然簡單,卻缺乏彈性、對開發者限制過多;較好的做法是讓伺服器同時支援多種政策:
- 暫時性物件的生成時機
- 政策一:第一次收到呼叫請求時建立、沒有用戶端繫結時銷毀。優點是只在真正需要時佔用資源;缺點是呼叫可能因為要先建立物件而變慢。
- 政策二:伺服器初始化時就建立所有暫時性物件,代價是即使沒人使用也佔資源。
- 記憶體配置
- 每個物件放在獨立記憶體區段(segment):物件之間不共用程式碼與資料。適用於實作未分離 code 與 data,或基於安全理由必須隔離物件的情況(後者需要伺服器或底層 OS 的特別支援來確保區段邊界不被跨越)。
- 讓物件至少共用程式碼:例如同一類別的大量資料庫物件,類別實作只需載入一次,收到呼叫時再從資料庫取出該物件的狀態執行方法,效率高得多。
- 執行緒政策
- 最簡單:整個伺服器單一控制執行緒。
- 每個物件一條執行緒:呼叫請求交給負責該物件的執行緒,忙碌時暫時排隊。好處是物件天然免於並行存取——所有呼叫都被該物件的執行緒序列化,簡潔俐落。
- 每個呼叫請求一條執行緒:則要求物件本身已具備並行保護。
- 另一個獨立的抉擇:執行緒隨需建立,還是維護執行緒池(thread pool)。
執行緒政策沒有唯一最佳解,取決於執行緒是否可用、效能要求高低等因素。「thread-per-object」的隱含序列化是最省心的並行保護手段,但吞吐量需求高時未必合適。
物件轉接器#
決定如何呼叫物件的種種抉擇,統稱為活化政策(activation policy)——強調許多情況下物件必須先被帶進伺服器位址空間(即活化)才能被呼叫。接著需要一個「依政策把物件分組」的機制,這就是物件轉接器(object adapter),或稱物件包裝器(object wrapper):
- Object adapter 可視為「實作某一特定活化政策的軟體」,重點是它是通用元件,只需組態即可套用特定政策。
- 一個 adapter 控制一或多個物件;因為伺服器要同時支援不同活化政策的物件,同一伺服器內可以同時存在多個 adapter。
- 呼叫請求送達伺服器時,先被分派(dispatch)到適當的 adapter。

圖 10-5:支援不同活化政策的物件伺服器組織方式
Object adapter 不知道它所控制物件的具體介面——否則就不可能通用。它只需要能從呼叫請求中取出物件參考,再依活化政策把請求交給該物件的 server-side stub(skeleton);skeleton 由物件的介面定義產生,負責解封送並呼叫正確的方法。
Adapter 的活化政策可以在執行期組態。以 CORBA 相容系統為例:可指定物件在其 adapter 停止後是否繼續存在、物件識別碼由 adapter 產生還是由應用提供、以及採用單執行緒或多執行緒模式等。
「物件」的實作內容其實完全開放:物件實作可能(間接)存取資料庫或呼叫特殊函式庫,這些細節對只跟 skeleton 溝通的 adapter 完全隱藏,未必與語言層級的物件有任何關係。因此一般採用不同的術語:servant 泛指「構成物件實作的那段程式碼」——從這個角度看,Java bean 也不過是另一種 servant。
範例:Ice 執行期系統#
Ice 是一套分散式物件系統,部分是為了回應商用物件式分散式系統的繁複而開發。
- Ice 的物件伺服器就是一個普通行程,啟動時先初始化 Ice 執行期系統(runtime system, RTS)。
- 執行環境的基礎是通訊器(communicator):管理若干基本資源的元件,最重要的是執行緒池,另有動態配置的記憶體等;也提供環境組態手段(如最大訊息長度、最大呼叫重試次數)。
- 通常一個物件伺服器只需一個 communicator;但當不同應用需要完全隔離時,可在同一行程內建立多個(組態可不同)communicator——至少能分開執行緒池,某一應用耗盡執行緒時不會波及其他應用。
建立物件伺服器的典型流程:
- 建立並初始化執行期環境。
- 透過 communicator 建立 object adapter,例如指定它在 TCP port 10000 監聽進入連線。
- 建立物件並加入 adapter。
- 活化 adapter——底層會啟動一條執行緒開始監聽進入請求。

圖 10-6:在 Ice 中建立物件伺服器的範例
活化政策透過修改 adapter 的屬性(properties)來調整。例如有一族屬性控制 adapter 專屬的執行緒集合:可以指定永遠只有一條執行緒,等於把該 adapter 上所有物件的存取全部序列化。被註冊的物件(如 MyObject)可以是單純的 C++ 物件,也可以是背後存取資料庫等外部服務的組合實作——這些細節對用戶端完全隱藏,用戶端只覺得自己在呼叫一個遠端物件。
延伸機制:Locator——動態載入物件
上述流程中物件是在應用程式裡建立後加入 adapter 的,這表示一個 adapter 可能得同時支撐大量物件,造成可擴充性問題。替代方案是需要時才把物件動態載入記憶體,Ice 為此提供稱為 locator 的特殊物件:
- 當 adapter 收到「未被明確加入的物件」的請求時,請求被轉交給 locator 處理。
- Locator 是被明確撰寫來處理這類請求的,沒有魔法。例如:物件狀態存在關聯式資料庫中,物件識別碼對應某筆記錄的鍵——locator 依鍵查詢、取出狀態,即可繼續處理請求。
- 一個 adapter 可掛多個 locator,由 adapter 記錄哪些物件識別碼屬於哪個 locator。如此單一 adapter 就能支撐大量物件;狀態雖需在執行期載入,伺服器本身卻可以保持相對簡單。