• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            loop_in_codes

            低調做技術__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

            分布式程序開發平臺ICE概覽

            本文基于ICE Manual及相關文檔就ICE的一些主要特性做一個概覽,它不是一個tutorial,不是一個guid,更不是manual。

            概覽

            ICE,Internet Communications Engine,按照官方介紹,是一個支持C++、.Net、Java、Python、Objective-C、Ruby、PHP及ActionScript等語言的分布式程序開發平臺。按照我的理解,簡單來說它是一個核心功能包裝RPC的庫。要把這個RPC包裝得漂亮,自然而然,對于使用者而言,調用一個遠端的接口和調用一個本地的接口沒有什么區別,例如:

                Object *obj = xxx
                obj->sayHello(); 
            

            ICE包裝sayHello接口,當應用層調用該接口時,ICE發送調用請求到遠端服務器,接收返回結果并返回給應用層。ICE在接口提供方面,做到了這一點。

            以下,我將逐個給出ICE中的一些工具、組件、特性說明,以展示它作為一個分布式程序開發平臺所擁有的能力。到目前為止,所有這些信息均來自于ICE相關文檔,總結出來權當為自己服務。

            Slice

            Slice(Specification Language for Ice)是ICE定義的一種中間語言,其語法類似于C++。對于一個RPC過程而言,例如上面調用遠端的sayHello接口,其主要涉及到調用這個接口的參數和返回值傳遞,當然接口本身的傳遞不在話下,ICE為了包裝這個過程,其使用了這樣一種方式:使用者使用Slice語言描述RPC過程中調用的接口,例如該接口屬于哪個類,該接口有哪些參數哪些返回值;然后使用者使用ICE提供的Slice編譯器(實際上是一個語言翻譯程序)將Slice源碼翻譯成目標語言。而這個目標語言,則是使用者開發應用程序的開發語言,即上文提到的C++、.Net、Java等。

            這些翻譯出來的目標代碼,就封裝了sayHello底層實現的一切細節。當然事情沒有這么簡單,但我們目前只需關注簡單的這一部分。ICE之所以支持那么多種開發語言,正是Slice立下的功勞。Slice語言本身的語言特性,實際上受限于目標語言的語言特性,例如Slice支持異常,恰是因為Slice轉換的所有語言都包含異常這個語法特性。

            Slice還有一個重要特性,在于一份Slice源碼被翻譯出來的目標代碼,一般情況是被服務器和客戶端同時使用。

            開發步驟

            使用ICE開發應用程序,其步驟遵循:

            1. 編寫Slice,說明整個RPC中涉及到的接口調用,編譯它
            2. 基于Slice目標代碼和ICE庫編寫Server
            3. 基于Slice目標帶啊和ICE庫編寫Client

            一個例子

            有必要展示一個例子,以獲得使用ICE開發應用程序的感性認識。這個例子是一個簡單的hello world程序,客戶端讓服務器打印一個字符串。

            • 編寫Slice
                // Printer.ice,Slice源碼后綴為ice
                module Demo {
                    interface Printer {
                        void printString(string s);
                    };
                };
            

            使用ICE提供的程序翻譯為C++代碼:

                $ slice2cpp Printer.ice
            

            得到Printer.cpp和Printer.h。Slice翻譯出來的目標代碼除了封裝RPC交互的一些細節外,最重要的,因為本身Slice文件其實是定義接口,但接口的實現,則需要應用層來做。

            • 服務器端使用生成的Printer.cpp/.h,并實現Printer接口
                // 翻譯出來的Printer.h中有對應于Slice中定義的Printer類,及需要實現的printString接口
                class PrinterI : public Printer {
                public:
                    virtual void printString(const string& s, const Ice::Current&) {
                        count << s << endl;
                    }
                };
            
            • 客戶端使用生成的Printer.cpp/.h,通過ICE獲得一個Printer對象,然后調用其printString接口
                // don't care about this
                PrinterPrx printer = PrinterPrx::checkedCast(base);
                printer->printString("Hello World!");
            

            使用ICE開發應用程序,整體過程即為以上展示。

            概念

            ICE包含了很多概念,作為一個開發平臺而言,有其專有術語一點不過分,熟悉這些概念可以更容易學習ICE。這里羅列一些關鍵概念。

            服務器端和客戶端

            ICE中的服務器端和客戶端和一般網絡程序中的概念不太一樣。在若干個交互的網絡程序中,我們都很好理解這樣一種現象:某個程序有多個角色,它可能是作為A程序的服務器端,也可能是作為B程序的客戶端。ICE中的服務器和客戶端角色更容易變換。

            以Printer例子為例,如果我們的printString接口有一個回調函數參數(這在ICE中很常見),服務器實現printString時,當其打印出字符串后,需通過該回調函數通知客戶端。這樣的回調機制在ICE的實現中,會創建一個新的網絡連接,而此時,這個原有的服務器端就變成了原有客戶端的客戶。當然,你也可以避免這樣的情況出現。

            ICE Objects/Object Adapter/Facet

            對于Printer例子,一個Printer對象可以被看作是一個ICE Objects。Object可以說是服務器端提供給客戶端的接口。所以在服務器端通常會創建出很多個Object。服務器端使用Object Adapter對象去保存這些Object。例如,一個典型的ICE對象在初始化時可能包含以下代碼:

                // 創建一個Object Adapter
                Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Hello");
                // 創建一個Object,形如Printer
                Demo::HelloPtr hello = new HelloI;
                // 將Object加入到Object Adapter
                adapter->add(hello, communicator()->stringToIdentity("hello"));
            

            Facet是Object的一部分,或者說Object是Facet的一個集合,摘Ice manual中的一句話:

            An Ice object is actually a collection of sub-objects known as facets whose types are not necessarily related.

            Proxy

            Proxy是ICE客戶端里的概念??蛻舳送ㄟ^Proxy訪問服務器端上的Object,通過Proxy調用服務器端Object上提供的接口。在客戶端上一般有類似以下代碼:

                Ice::ObjectPrx base = ic->stringToProxy("SimplePrinter:default -p 10000");
                // Printer Proxy
                PrinterPrx printer = PrinterPrx::checkedCast(base);
                printer->printString("Hello World!");
            

            Proxy又分為幾種,包括:

            Direct Proxy

            Direct Proxy,這里的direct意指這個proxy訪問的object時,是否攜帶了地址(EndPoint)信息,例如上面例子中SimplePrinter:default -p 10000就是一個地址。

            Indirect Proxy

            Indirect Proxy相對Direct Proxy而言,其沒有具體的地址,僅僅是一個符號。通常包含兩種形式:

            • SimplePrinter
            • SimplePrinter@PrinterAdapter

            為了獲取真正的地址,客戶端需要一個定位服務(location service)來獲取這個符號對應的地址。ICE中提供了一些默認的服務程序,IceGrid就是其中之一,而IceGrid的作用就包括定位具體的地址,即翻譯符號地址到具體的地址。

            這里Indirect Proxy可以看作一個域名,而Direct Proxy可以看作是IP地址。Indirect Proxy使用時,就需要借助DNS翻譯得到域名對應的IP地址。

            Fixed Proxy

            由于Proxy是用于與服務器端的Object通信的,客戶端借助Proxy來訪問服務器端的Object,所以Proxy通常都會對應一個真實的網絡連接。在ICE中,一般的Proxy于網絡連接(Connection)實際上是沒有太大關聯的。一個Proxy可以沒有Connection,也可以在建立這個Connection后又斷開之。但是,ICE提供了一種特殊的Proxy,Fixed Proxy,這種Proxy緊密地與一個Connection綁定在一起,其生命周期被強制關聯起來。

            關于Fixed Proxy可以參看ICE Manual Connection Management。

            其他

            • AMI

            Asynchronous Method Invocation,對于客戶端而言,用于表示某個服務器端接口是異步操作,需在Slice中使用metadata來修飾這個接口,例如:

                ["ami"]  void sayHello(int delay)
            
            • AMD

            Asynchronous method dispatch,這個針對于服務器端,同樣表示這個接口是異步操作,需在Slice中使用metadata來修飾這個接口:

                ["ami", "amd"]  void sayHello(int delay)
            

            通常對于這種異步接口而言,都需要使用Slice metadata amiamd同時修飾。

            • idempotent

            idempotent是Slice中的概念,同const一樣用于修飾某個接口的特性。idempotent表示該接口無論調用多少次,其執行結果都是相同的,例如一般的get類接口。

            • batched invocation

            客戶端調用服務器端的接口這個動作稱為invocation。就像網絡層的數據緩存一樣,ICE對于接口調用也可能暫時緩存,當多個提交請求緩存起來后,然后調用刷新接口全部刷新到服務器端,則稱為batched invocation。

            服務

            ICE除了提供一個庫之外,還提供了一些應用程序。這些應用程序本身也是一些服務器,提供了一些方便的功能方便我們開發分布式程序。

            Freeze

            Freeze用于將Slice對象持久化到數據庫中,按照Manual里的說法,它應該是一個編譯器,可以生成一些持久化操作的代碼。Freeze持久化對象時使用的數據庫是Berkeley DB。

            Ice has a built-in object persistence service, known as Freeze. Freeze makes it easy to store object state in a database: you define the state stored by your objects in Slice, and the Freeze compiler generates code that stores and retrieves object state to and from a database. Freeze uses Berkeley DB as its database.

            FreezeScript有點類似于Rails中的數據庫操作工具,可用于操作持久化到數據庫中的對象數據。

            Ice also offers a tool set collectively called FreezeScript that makes it easier to maintain databases and to migrate the contents of existing databases to a new schema if the type definitions of objects change.

            IceBox

            IceBox可用于管理服務器中的動態組件。這些動態組件本質上也是提供服務的ICE程序。在形式上,這些組件可以是動態連接庫。

            IceBox is a simple application server that can orchestrate the starting and stopping of a number of application components. Application components can be deployed as a dynamic library instead of as a process.

            IceGrid

            IceGrid相當于一個DNS解析服務,可以讓服務器不用配置EndPoint,客戶端也不用指定服務器的EndPoint,以方便大量的服務器部署。在一般的應用中,我們需要為ICE服務器指定綁定的網絡地址(IP和端口),同時也需要為客戶端指定服務器端的地址信息。當服務增加到一定數量時,就會存在管理上和配置上的麻煩。而IceGrid則是用于避免這種麻煩,將服務器端和客戶端上的地址信息通過一個符號代替,就像我們把Internet上的服務器使用域名來標識一樣。

            但IceGrid的作用不僅如此,通過配合部署一系列稱為IceGrid Node的程序,IceGrid還可以管理各個服務器的啟動、關閉、宕機重啟等,其中甚至包括負載均衡。

            IceGrid provides a facility to activate servers on demand, when a client first invokes an operation. Server activation is taken care of by IceGrid nodes. You must run an IceGrid node on each machine on which you want IceGrid to start servers on demand.

            簡要介紹可以參看ICE Manual Teach Yourself IceGrid in 10 minutes

            Glacier2

            Glacier2 is a lightweight firewall traversal solution for Ice applications.

            按我的理解,Glacier2就像一個網關服務器。它被部署在服務器和客戶端之間,我們的服務器群部署在內網,外網不可訪問,然后通過Glacier2,外部網絡的客戶端就可以訪問內網的服務器群提供的服務。

            對于服務器的開發而言,使用Glacier2,服務器端不需要做任何改動。客戶端需要配置Glacier2服務的地址信息,也需要配置要使用服務器的地址信息。Glacier2通過客戶端欲訪問的服務器地址,在內網定位到真實的服務器,并轉發請求提供服務。

            Glacier2支持驗證客戶端,從這一點看來,它又有點像一個驗證服務器。通過驗證客戶端,以提供被正確授權的客戶端以完整服務。

            Glacier2的工作過程可以描述為:

            When a client invokes an operation on a routed proxy, the client connects to one of Glacier2’s client endpoints and sends the request as if Glacier2 is the server. Glacier2 then establishes an outgoing connection to the client’s intended server in the private network, forwards the request to that server, and returns the reply (if any) to the client. Glacier2 is essentially acting as a local client on behalf of the remote client.

            一個Glacier2可服務于若干個客戶端和服務器。

            詳細參看ICE Manual Glacier2

            管理

            ICE服務器可以提供給外部一定的管理功能,包括:關閉服務器、讀取服務器配置。這個功能是通過操作Ice.Admin這個Ice Object來實現的。這個Object包含兩個Facet:Process和Property,分別對應于關閉服務器和讀取服務器配置功能。

            對于需要管理服務器的客戶端而言,可以大致通過如下代碼來完成:

                // 可以通過communicator來獲取這個admin object
                Ice::ObjectPrx adminObj = ...;
                // 獲取admin object里的property facet
                Ice::PropertiesAdminPrx propAdmin = Ice::PropertiesAdminPrx::checkedCast(adminObj, "Properties");
                Ice::PropertyDict props = propAdmin->getPropertiesForPrefix("");
            

            詳細參看ICE Manual Administrative Facility

            連接管理

            前已述及,ICE中的網絡連接隱藏于Proxy之下。Proxy有兩個接口可以獲取這個連接對象:

                ice_getConnection
                ice_getCachedConnection
            

            例如:

                HelloPrx hello = HelloPrx::uncheckedCast(communicator->stringToProxy("hello:tcp -h remote.host.com -p 10000"));
                ConnectionPtr conn = hello->ice_getConnection();
            

            ICE隱藏了網絡連接的細節。當ICE發現需要建立連接時才會去建立,例如以上例子中當獲得一個Proxy時(這里是HelloPrx),ICE并不建立網絡連接,當某個時刻通過該Proxy調用服務器端的某個接口時,ICE發現對應的網絡連接沒有建立,則發起網絡連接。

            以上例子在獲取Proxy時,使用了uncheckCast,關于checkedCastuncheckedCast,也影響著網絡連接的建立邏輯:

            On the other hand, if the code were to use a checkedCast instead, then connection establishment would take place as part of the checkedCast, because a checked cast requires a remote call to determine whether the target object supports the specified interface.

            關于連接管理,ICE使用了一個稱為ACM的機制,即Active connection management。當某個連接非active一段時間后,ICE就會主動關閉此連接。應用層當然可以控制這個行為。

            詳細參看ICE Manual Connection Management

            posted on 2013-02-15 15:24 Kevin Lynx 閱讀(6429) 評論(0)  編輯 收藏 引用 所屬分類: c/c++

            欧美亚洲另类久久综合婷婷| 日韩乱码人妻无码中文字幕久久| 久久青草国产精品一区| 爱做久久久久久| 国内精品伊人久久久影院| 超级97碰碰碰碰久久久久最新| 亚洲精品乱码久久久久久蜜桃不卡 | 欧美伊人久久大香线蕉综合69| 91视频国产91久久久| 久久国产影院| 97久久国产亚洲精品超碰热 | 人妻系列无码专区久久五月天| 亚洲精品美女久久777777| 国内精品久久久久久久久 | 一级a性色生活片久久无少妇一级婬片免费放 | 亚洲欧美久久久久9999| 国产成人无码精品久久久性色| 久久青青草原精品影院| A级毛片无码久久精品免费| 国产精品成人精品久久久| 亚洲AV无码久久精品狠狠爱浪潮| 久久伊人影视| 国产精品成人99久久久久| 国产精品福利一区二区久久| 久久夜色精品国产亚洲| 三级片免费观看久久| 91麻豆精品国产91久久久久久| 性高湖久久久久久久久| 久久亚洲AV成人无码| 久久综合鬼色88久久精品综合自在自线噜噜| 久久99精品久久久久久hb无码| 午夜精品久久久久久99热| 波多野结衣AV无码久久一区| 久久综合鬼色88久久精品综合自在自线噜噜| 精品久久久久久久久久中文字幕| 秋霞久久国产精品电影院| 国内精品久久人妻互换| 国内精品伊人久久久久| 久久综合综合久久97色| 久久精品国产亚洲7777| 日韩影院久久|