ICE中間件說明文檔

ICE中間件說明文檔

1       ICE中間件簡介...2

2       平臺核心功能...2

2.1        接口描述語言(Slice)...2

2.2        ICE運行時...3

2.2.1         通信器...3

2.2.2         對象適配器...3

2.2.3         位置透明性...4

2.3        異步編程模型...4

2.3.1         異步方法調用...4

2.3.2         異步方法分派...5

2.4        訂閱/發佈編程模型...6

2.5        動態服務管理(IceBox)...6

2.6        ICE網格計算...7

2.6.1         分佈式部署...7

2.6.2         負載均衡...8

2.6.3         註冊中心集羣...9

2.7        IceSSL應用...9

2.8        持久化存儲(IceFreeze)...10

3       ICE平臺功能研究小結...11

 


 

1       ICE中間件簡介

Ice 是 Internet Communications Engine 的簡稱,是一種面向對象的中間件平臺,支持面向對象的RPC編程,其最初的目的是爲了提供類似CORBA技術的強大功能,又能消除CORBA技術的複雜性。該平臺爲構建面向對象的客戶-服務器應用提供了工具、API 和庫支持。

    由ICE平臺開發的應用支持跨平臺部署,多語言編程,其中服務端支持C++、JAVA、C#、Python等幾種編程語言,客戶端還支持Ruby、PHP。ICE支持同步/異步、訂閱/發佈的編程模式,支持分佈式部署,網格計算,內置負載均衡功能,支持SSL安全加密。

    ICE 既可以把TCP/IP、也可以把UDP 用作底層傳輸機制, 還允許你把SSL 用作傳輸機制,讓客戶與服務器間的所有通信都進行加密。 

ICE平臺還提供一序列的編程庫,包括線程模型庫、定時器、信號處理器,這些編程庫的API全部支持線程安全。

ICE目前的最新版本爲ICE3.4.1,是2010年6月份發佈的,ICE3.1.1(2006年10月份發佈)及以前的版本支持Windows、LINUX、AIX、HP-UX、Solaris操作系統,但是ICE3.2.0(包含)以後的版本官方不再保證對AIX的完全支持,而3.3.1(包含)以後版本連HP-UX都不保證完全支持,雖然源代碼中仍然提供了這兩個操作系統下的源代碼編譯文件Make.rules.AIX和 Make.rules.HP-UX,根據官方的論壇說明是因爲他們基本上沒有這兩個系統的商業客戶,所以不再對這兩個平臺進行代碼測試,如果有需要的需要和他們聯繫。

2       平臺核心功能

2.1     接口描述語言(Slice

Slice (Specification Language for Ice)是一種用於使對象接口與其實現相分離的基礎性抽象機制。 Slice 在客戶與服務器之間建立合約,描述應用所使用的各種類型及對象接口。這種描述與實現語言無關,所以編寫客戶所用的語言是否與編寫服務器所用的語言相同,這沒有什麼關係。

Slice 定義由編譯器編譯到特定的實現語言。編譯器把與語言無關的定義翻譯成針對特定語言的類型定義和API。開發者使用這些類型和API 來提供應用功能,並與Ice 交互。目前ICE支持Slice到C++、JAVA、C#、Python、Ruby、PHP的語言映射。

Slice示例:

module Family //對應C++的名字空間

{

interface Child;

sequence<Child*> Children; // OK 可以利用C++的Vector

interface Parent //對應C++的類

{

Children getChildren(); // OK

};

interface Child

{

Parent* getMother();

Parent* getFather();

};

};

利用Slice 定義接口/類方法時和其他編程語言很相似,需要一個返回值和若干個參數,但是需要注意的是Slice不支持引用方式的參數傳遞,參數要麼爲輸入參數,要麼爲輸出參數,不同時爲in和out.作爲out參數的時候,不管客戶端對out參數的初始賦值是什麼,在服務端都取不到該,但是服務端可以對該參數進行賦值,再傳遞給客戶端。例如:

interface Hello

{

    string sayHello(int num,out string strMsg);

};

   還要注意的是out參數一定是放在所有輸入參數後面,不允許交叉。

2.2     ICE運行時

2.2.1  通信器

Ice run time 的主進入點由本地接口Ice::Communicator 表示,通常一個應用服務器只使用一個通信器,一個通信器實例管理着運行時資源,主要的運行時資源包括:

²  線程池:負責接收客戶端連接和請求。

²  配置屬性:Ice run time 的各個方面可以通過屬性進行配置。每個通信器都有自己的配置屬性

²  插件管理器:插件是用於給通信器增加特性的對象。例如, IceSSL (參見第23章)被實現成插件。每個通信器都有一個插件管理器,這個管理器實現Ice::PluginManager 接口,通過它,你可以訪問通信器的插件集。

²  對象工廠:爲了實例化從已知基類派生的類,通信器維護有一組對象工廠,能夠替Ice run time 對類進行實例化。用戶定義的每一個接口/類都隱式地繼承同一個基類Ice:Object.

²  缺省定位器:定位器用於把客戶請求的對象標識解析爲代理對象。

²  對象適配器:對象適配器用於分派接收到的請求,把每個請求轉發到正確的Servant。每個對象適配器可以綁定多個ICE對象,不同通信器的對象適配器和對象完全是相互獨立的。

2.2.2  對象適配器

一個通信器含有一個或更多對象適配器。對象適配器處在Ice run time和服務器之間的界線上,負有這樣一些責任:

²  它把Ice對象映射到到來請求的servant,並把請求分派給每個servant中的應用代碼(也就是說,對象適配器實現了一個向上調用接口,把Icerun time 與服務器中的應用代碼連接在一起)。

²  它協助進行生命週期操作,使得Ice對象和servant在創建和銷燬時不會出現競爭狀況。

²  它提供一個或更多傳輸端點。客戶通過這些端點訪問適配器所提供的Ice對象。每個對象適配器都有一個或更多servant,對Ice 對象進行體現;同時還有一個或更多傳輸端點。如果對象適配器擁有的傳輸端點不止一個,所有向該適配器作了註冊的servant 可以在任何一個端點上響應到來的請求。換句話說,如果對象適配器有多個傳輸端點,這些端點代表的是通往同一組對象的不同通信路徑(例如,通過不同的傳輸機制)。

²  每個對象適配器都只屬於一個通信器(但一個通信器可以有多個對象適配器)。

2.2.3  位置透明性

Ice run time 的一個有用的特性是位置透明性:客戶無需知道Ice 對象的實現的位置;對某個對象的調用會被自動引導到正確的目標,不管這個對象的實現是在本地地址空間中,在同一臺機器上的另一個地址空間中,還是在一臺遠地機器上的另一個地址空間中。位置透明性十分重要,因爲有了它,我們能夠改變對象實現的位置,而不會破壞客戶程序,同時,通過使用IceGrid,像域名和端口號這樣的信息可以放在應用的外部,不用出現在串化代理中。

2.3     異步編程模型

ICE平臺支持客戶端異步調用(AMI)和服務端異步分派編程(AMD)。

2.3.1  異步方法調用

異步方法調用(AMI) 這個術語描述的是客戶端的異步編程模型支持。如果你使用AMI 發出遠地調用,在Ice run time 等待答覆的同時,發出調用的線程不會阻塞。相反,發出調用的線程可以繼續進行各種活動,當答覆最終到達時, Ice run time 會通知應用。通知是通過回調發給應用提供的編程語言對象的。

要使用異步方法調用,只需要給對應的類或者方法前面加上元數據[“ami”],示例如下:

interface Hello

{

         [”ami”] string sayHello(int num);

};

通過Slice編譯器生成頭文件時,會生成對應的方法同步調用方法和異步調用方法,用戶在客戶端可以自行選擇使用同步調用還是異步調用,非常方便。編譯後對於每一個異步方法都會生成相應的異步回調類和異步調用代理方法,類的命名方式 AMI_類名_方法名,上述的slice經編譯後生成的類爲 AMI_Hello_sayHello,同時這個類提供了兩個方法:

void ice_response(<params>);

表明操作已成功完成。各個參數代表的是操作的返回值及out 參數。如果操作的有一個非void 返回類型, ice_response 方法的第一個參數就是操作的返回值。操作的所有out 參數都按照聲明時的次序,跟在返回值的後面。

void ice_exception(const Ice::Exception &);

表明拋出了本地或用戶異常。

客戶端只需要從AMI_Hello_sayHello 類繼續並實現上述兩個方法就可以了。示例代碼如下:

class AMI_Hello_sayHelloI : public AMI_Hello_sayHello

{

    void ice_response(const ::std::string& strMsg)

     {

         printf("%s\n",strMsg.c_str());

     }

    void ice_exception(const Ice::Exception& exception)

     {

         printf("error\n");

     }

};

生成的異步調用代理方法命名爲方法名_async,上述示例生成的方法爲 sayHello_async.然後客戶端的程序異步調用如下:

hello->sayHello_async(AMI_Hello_sayHelloPtr,<params>);

然後只需在ice_response 方法處理返回結果。

也可以調用同步方法:

hello->sayHello(<params>);

2.3.2  異步方法分派

異步方法分派(AMD) 是AMI 的服務器端等價物,在使用AMD 時,服務器可以接收一個請求,然後掛起其處理,以儘快釋放分派線程。當處理恢復、結果已得出時,服務器要使用Ice runtime 提供的回調對象,顯式地發送響應。

用實際的術語說, AMD 操作通常會把請求數據(也就是,回調對象和操作參數)放入隊列,供應用的某個線程(或線程池)隨後處理用。這樣,服務器就使分派線程的使用率降到了最低限度,能夠高效地支持大量併發客戶。

要使用異步方法調用,只需要給對應的類或者方法前面加上元數據[“amd”],示例如下:

interface Hello

{

         [”amd”] string sayHello(int num);

};

和異步方法調用不同的是,異步分派是服務端的,在服務端會生成相應的異步分派類和異步分派方法。服務端的分派器在接收到客戶請求時把請求分派給sayHello_async(const Demo::AMD_Hello_sayHelloPtr&, int, const Ice::Current&).然後用戶可以在該方法內把任務參數信息放入隊列,在隊列中循環檢查任務並處理,處理完成後調用 AMD_Hello_sayHelloPtr 類的 ice_response 方法返回給客戶端。

 

2.4     訂閱/發佈編程模型

IceStorm是一個高效的用於ICE應用的發佈/訂閱服務,IceStorm有幾個比較重要的概念:

²  消息:IceStorm的消息和普通的消息隊列中間件中描述的消息有點區別,IceStorm 的消息是強類型的,由對某個Slice 操作的調用代表:操作名標識消息的類型,操作參數定義消息內容。要發佈消息,可以按普通的方式調用某個IceStorm 代理上的操作。與此類似,訂閱者會像收到常規的向上調用(upcall)一樣收到消息。所以IceStorm 的消息遞送使用的是“推”模式

²  主題:應用要通過訂閱某個主題(topic)來表明自己有興趣接收某些消息。IceStorm 服務器能夠支持任意數量的主題,這些主題是動態創建的,通過唯一的名字來區分。每個主題都可以有多個發佈者和訂閱者。   

²  持久模式:IceStorm 擁有一個數據庫,裏面維護的是關於其主題和鏈接的信息。但是,通過IceStorm 發送的消息不會被持久地存儲,而是會在遞送給主題目前的訂閱者集之後,馬上被丟棄。如果在把消息遞送給某個訂閱者的過程中發生錯誤, IceStorm 不會爲該訂閱者進行消息排隊。

²  訂閱者出錯:因爲IceStorm 消息是採用單向語義遞送的, IceStorm 只能檢測到連接或超時錯誤。如果在把消息遞送給訂閱者的過程中, IceStorm 遇到這樣的錯誤,該訂閱者就會立刻被解除與該消息對應的主題的訂閱。當然用戶在使用過程中也可以通過設定QOS參數來改善這個問題,比如重試次數(retryCount),但是對於ObjectNotExistException 或者 NotRegisteredException之類的硬錯誤,Ice運行時不會重試,而是仍然直接解除訂閱關係。

 

IceStorm支持兩個主要的QOS參數reliability 和 retryCount,reliability的取值分別爲ordered 和空值,取ordered時,發佈者發佈的消息會保證按順序遞送給訂閱者。

從IceStorm提供的功能來看,對於不需要進行消息持久存儲轉發的應用來說很適合,但是由於在訂閱者出錯後立即解除訂閱關係,不是由訂閱者主動解除,這個在應用中需要特別注意是否符合實際應用。

IceStorm被實現爲IceBox服務,所以在部署IceStorm應用時需要啓動IceBox服務。

 

2.5     動態服務管理(IceBox

IceBox 用於動態加載用戶服務並對他們進行集中管理,可以通過iceboxadmin管理工具對IceBox中的服務進行遠程管理,通過IceBox用戶服務可以被開發成可以動態加載的動態庫組件.

使用IceBox的服務組件需要繼承IceBox::Service類,並實現start()、stop()方法,並在實現類中提供服務進入點函數,一般爲create()函數,在這函數中創建服務實現類的對象並返回。例如:

extern "C"

{

ICE_DECLSPEC_EXPORT IceBox::Service*

create(Ice::CommunicatorPtr communicator)

{

    return new HelloServiceI;

}

}

    對於Ice3.3.0以上版本,iceboxadmin提供了啓動、停止服務及停止IceBox 服務器的命令管理工具和應用程序接口,管理工具命令如下:

iceboxadmin [options] [command...]

Commands:

start SERVICE Start a service.

stop SERVICE Stop a service.

shutdown Shutdown the server.

 

 

2.6     ICE網格計算

IceGrid用於支持分佈式網絡服務應用,一個IceGrid域由一個註冊表(Registry)和任何數目的節點(Node)構成。註冊表(Registry)和節點(Node)一起合作管理一些信息以及包含一些應用(Application)的服務進程。每項應用(Application)被指定在特定節點上的服務。這個註冊表(Registry)持久記錄了這些信息,而節點(Node)負責啓動和監測其指定的服務器進程。對於一個典型的配置,一個節點(Node)運行在一臺計算機(稱之爲Ice服務器主機)。註冊表(Registry)並不消耗很多處理器時間,所以它常常是和一個節點(Node)運行在同一臺計算機上的,註冊表(Registry)還可以和一個節點(Node)可以運行在同一進程中.如果需要容錯,註冊表(Registry)還可以用主從式的設計支持複製(Replication)。

註冊表(Registry)的主要責任,是解決作爲Ice定位服務的間接代理問題,當客戶端第一次嘗試使用一種間接代理,客戶端Ice run time首先連接註冊表(registry),註冊表將間接代理的符號信息轉化爲直接代理的endpoint,然後客戶端和直接代理建立一個連接。通過適配器複製,同名適配器可以分佈在多個節點上,間接代理可以映射到多個節點上的直接代理,在運行時由註冊表服務根據負載均衡自動選擇一個直接代理給客戶端。

使用間接代理時,客戶端可以用以下方式直接獲取服務對象代理:

MyProxy=theObject@theAdapter   //  對象@適配器

更簡單一點的話可以用以下方式

MyProxy=theObject   //  對象

2.6.1  分佈式部署

在部署IceGrid分佈式服務時,需要啓動註冊表服務(icegridregistry),並配置註冊表服務地址端口、通信協議和註冊信息保存的目錄地址(ICE的註冊信息保存爲BerkeleyDB的數據庫文件):

IceGrid.Registry.Client.Endpoints=tcp -p 4061

IceGrid.Registry.Data=/opt/ripper/registry

 

在服務器節點中和客戶端都需要配置註冊表服務的地址端口和通信協議:

Ice.Default.Locator=IceGrid/Locator:tcp -h 172.0.0.1 -p 4061

然後分別啓動註冊表服務(icegridregistry)和節點服務(icegridnode).

ICE提供了部署工具icegridadmin, 這個icegridadmin工具也需要定義Ice.Default.Locator屬性.

接下需要編寫應用部署文件,應用部署文件以XML方式保存。以下爲支持適配器複製的應用配置文件,使用了服務模板:

<icegrid>

<application name="Ripper">

<replica-group id="EncoderAdapters"> //定義適配器複製組

<object identity="EncoderFactory"    //identity將在客戶端中使用。

type="::Ripper::MP3EncoderFactory"/>

</replica-group>

<server-template id="EncoderServerTemplate"> //定義服務器模板

<parameter name="index"/>

<parameter name="exepath"

default="/opt/ripper/bin/server"/>

<server id="EncoderServer${index}"

exe="${exepath}"

activation="on-demand">

<adapter name="EncoderAdapter"

replica-group="EncoderAdapters"

endpoints="tcp"/>

</server>

</server-template>

<node name="Node1">

<server-instance template="EncoderServerTemplate"

index="1"/>

</node>

<node name="Node2">

<server-instance template="EncoderServerTemplate"

index="2"/>

</node>

</application>

</icegrid>

然後在客戶端可以用以下方式獲取對象代理:

Ice::ObjectPrx obj = communicator->stringToProxy("EncoderFactory");

2.6.2  負載均衡

ICE平臺內嵌負載均衡功能,對於分佈大多個節點上的應用服務提供多種負載均衡方案,只需要通過XML配置文件即可完成負載均衡配置。配置項包括Type (負載均衡類型)、Sampling interval(負載信息收集間隙)、Number of replicas(返回給客戶端的適配器個數)。

負載均衡類型有以下4種方式:

²  Random (隨機方式):註冊中心隨機選擇一個適配器給客戶端,不檢查適配器的負載。

²  Adaptive(適配方式):註冊中心從所有適配器中選擇一個負載最輕的適配器給客戶端,Sampling interval參數只有在該類型的負載均衡中有效,這個參數指定節點定期向註冊中心報告本地系統負載信息(system load information);

²  Round Robin(最近最少使用):註冊中心從對應的適配器組中選擇一個最近最少使用的適配器給客戶。

²  Ordered(順序方式):註冊中心根據適配器的優先級,從高到低順序選擇一個適配器給客戶端。

配置示例:

         <replica-group id="EncoderAdapters">

<load-balancing type="adaptive"/>   //配置爲適配方式

<object identity="EncoderFactory"

type="::Ripper::MP3EncoderFactory"/>

</replica-group>

2.6.3  註冊中心集羣

前兩節中描述的是屬於用戶應用的分佈部署,分佈式部署一個很重要的支撐是ICE的註冊中心,所有客戶端都向註冊中心查詢服務代理的真實端點,從而建立通信連接,在這裏註冊中心又成了一個單點服務,爲了避免註冊中心成爲應用的瓶頸,提高系統的可靠性,ICE3.3.0以上版本提供了註冊中心集羣功能

ICE註冊中心集羣通過主從式的註冊中心複製來實現,一個集羣中有一個主註冊中心,若干個副註冊中心,主從的區別通過IceGrid.Registry.ReplicaName屬性配置來實現,主註冊中心的名稱爲 Master,其他的名字可以任意取。啓動時先啓動主註冊中心,再啓動其他註冊中心,通過主註冊中心更新的信息都將同步給副註冊中心,各副註冊中心之間不通信。如果主註冊中心失效,需要從其他副註冊中心提撥一個成爲主註冊中心,但是從3.3版本的說明文檔中來看,如果需要把某個副註冊中心提撥成爲主註冊中心需要重新啓動相應進程並修改IceGrid.Registry.ReplicaName 屬性值爲Master,或者刪除該屬性,默認情況下該屬性值爲Master.

使用集羣方式時,在客戶端配置時把所有的主從註冊中心地址端口全部填到Ice.Default.Locator,例如:

Ice.Default.Locator=IceGrid/Locator:default -p 12000:default -p 12001

在應用節點也把所有的註冊中心地址端口綁定,這樣應用的更新會同時通知所有的註冊中心。

2.7     IceSSL應用

ICE平臺可以通過簡單的配置來支持SSL應用,配置過程如下:

²  首先需要通過修改配置文件來啓用SSL插件,C++服務端的配置方法爲:Ice.Plugin.IceSSL=IceSSL:createIceSSL

只需要把IceSSL動態庫放到LD_LIBRARY_PATH包含的路徑下即可。

²  然後修改適配器的監聽選項:

MyAdapter.Endpoints=tcp -p 8000:ssl -p 8001:udp -p 8000 //表示該適配器在三種協議端口上同時監聽。

ICE還提供了多種配置屬性來滿足實際應用,例如下例所示:

Ice.Plugin.IceSSL=IceSSL:createIceSSL

IceSSL.DefaultDir=/opt/certs  //默認證書目錄

IceSSL.CertFile=pubkey.pem  //證書文件

IceSSL.KeyFile=privkey.pem  //私鑰文件

IceSSL.CertAuthFile=ca.pem  //信任的根證書文件

IceSSL.Password=password    //私鑰文件查看密碼

2.8     持久化存儲(IceFreeze

ICE提供的持久化方案可以支持普通用戶數據(鍵/值對)的持久化存儲和服務對象實例的持久化管理,普通用戶數據的持久化存儲使用比較簡單,服務對象實例的管理相對複雜一點,暫時不關注。

ICE的持久存儲介質爲BerkeleyDB,對普通數據的持久化在C++實現中採用Map的方式進行操作,用戶需要用Slice定義需要存儲的數據,並用slice2freeze 生成相應的Map操作類,然後對數據的操作就可以使用Map容器函數來進行。示例如下:

首先生成需要存儲的數據類型:

slice2freeze --dict StringIntMap,string,int StringIntMap

代碼使用:

Ice::CommunicatorPtr communicator =

Ice::initialize(argc, argv);

// Create a Freeze database connection.

Freeze::ConnectionPtr connection = Freeze::createConnection(communicator, "db"); //連接到數據庫文件。

// Instantiate the map.

StringIntMap map(connection, "simple");//創建表。

// Clear the map.

map.clear();

Ice::Int i;

StringIntMap::iterator p;

// Populate the map.

for (i = 0; i < 26; i++)

{

std::string key(1, 'a' + i);

map.insert(make_pair(key, i));

}

// Iterate over the map and change the values.

for (p = map.begin(); p != map.end(); ++p)

p.set(p->second + 1);

// Find and erase the last element.

p = map.find("z");

assert(p != map.end());

map.erase(p);

// Clean up.

connection->close();

communicator->destroy();

IceFreeze還允許使用結構體和類對象作爲值進行存儲,但是隻有public的成員變量會被存儲,其他成員變量不會被存儲。

對於較高版本的ICE,還允許對值建立索引,如果值爲結構體或者類對象,那麼還允許以結構體/對象變量作爲索引,通過slice2freeze編譯後會生成對應的索引查詢函數。例如定義瞭如下需要存儲的數據結構:

module Demo

{

struct Struct1

{

    long l;

};

class Class1

{

    string s;

};

};

然後執行以下命令生成映射表,同時生成索引,以class1的成員變量s爲索引。

Slice2freeze

--dict Demo::IndexedStruct1Class1Map,Demo::Struct1,Demo::Class1         --dict-index Demo::IndexedStruct1Class1Map,s,case-sensitive         BenchTypes Test.ice

編譯後代碼中會自動生成findByS(string &),在程序中可以按以下方式直接調用:

IndexedStruct1Struct2Map& m=...;

IndexedStruct1Struct2Map::iterator p = m.findByS(os.str());

3       ICE平臺功能研究小結

ICE平臺提供的功能比較多,除了文檔中羅列的部分,還支持程序包分發(IcePath2)、防火牆穿透(Glacier),鑑於目前的項目應用暫時不對這兩部分作介紹。

從ICE官方提供的Demo和自己編寫的測試程序在Iinux(opensuse)運行良好,對於適用於AIX的3.1.1版本在AIX上運行異步編程的測試也很順利,但是目前還未對ICE平臺的應用做性能測試。

從文檔的介紹,ICE平臺支持同步/異步、訂閱/發佈、分佈式部署、內部持久化存儲,支持接口描述語言到各種面向對象開發語言的映射,可以滿足ESB系統開發的技術需求,但是也有一定的風險,ICE3.1以後的版本對AIX、HP-UX操作系統不保證完全支持,對3.1以後各個升級版本需要進行編譯並運行測試。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章