ZeroC ICE之旅

Ice 是 Internet Communications Engine 的简称,出自ZeroC名门之下。 
Ice 是一种面向对象的中间件平台。从根本上说,这意味着Ice 为构建面向对象的客户-服务器应用提供了工具、API 和库支持。Ice 应用适合于异构平台环境中使用:客户和服务器可以采用不同的编程语言,可以运行在不同的操作系统和机器架构上,并且可以使用多种网络技术进行通信。无论部署环境如何,这些应用的源码都是可移植的。 

其采用C/S 模式结构,支持同步调用方式和异步调用方式,异步派发调用方式。支持跨语言的对象调用。多种语言之间采用共同的Slice(Specification Language for Ice)进行沟通。支持ice到C,JAVA,C#,VB,Python,Ruby,PHP等多种语言的映射。

工欲善其事,必先利其器,我们首先从www.zero.com,下载最新安装包; 
btw: 

目前最新的v3.3 
http://www.zeroc.com/download_beta.html 
最新稳定版本: 
http://www.zeroc.com/download.html 


由于我自己的平台是CentOS release 4.4 (Final),java version "1.6.0_01" 
所以下载的是: 
http://www.zeroc.com/download/Ice/3.3/Ice-3.3b-rhel4-i386-rpm.tar.gz 

解开之后: 
-rw-r--r--  1 506 users 1130231  4月  1 10:39 db46-4.6.21-2ice.rhel4.i386.rpm 
-rw-r--r--  1 506 users   51459  4月  1 10:39 db46-devel-4.6.21-2ice.rhel4.i386.rpm 
-rw-r--r--  1 506 users  810562  4月  1 10:40 db46-java-4.6.21-2ice.rhel4.i386.rpm 
-rw-r--r--  1 506 users   72125  4月  1 10:40 db46-utils-4.6.21-2ice.rhel4.i386.rpm 
-rw-r--r--  1 506 users   84281  4月  1 10:15 ice-3.3b-1.rhel4.noarch.rpm 
-rw-r--r--  1 506 users  450359  4月  1 10:15 ice-c++-devel-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users 2823701  4月  1 10:16 ice-java-3.3b-1.rhel4.noarch.rpm 
-rw-r--r--  1 506 users  263085  4月  1 10:16 ice-java-devel-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users 3439061  4月  1 10:17 ice-libs-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users  162092  4月  1 10:19 ice-php-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users  739055  4月  1 10:19 ice-python-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users   32913  4月  1 10:19 ice-python-devel-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users  223577  4月  1 10:19 ice-ruby-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users   21406  4月  1 10:19 ice-ruby-devel-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users 3657167  4月  1 10:20 ice-servers-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users 4350193  4月  1 10:24 ice-utils-3.3b-1.rhel4.i386.rpm 
-rw-r--r--  1 506 users   74856  4月  1 10:40 mcpp-devel-2.6.4-1ice.rhel4.i386.rpm 
由于需要c和java的包: 
所以我们仅安装: 
rmp -ivh ice-3.3b-1.rhel4.noarch.rpm 
rmp -ivh ice-3.3b-1.rhel4.noarch.rpm 
rpm -ivh ice-3.3b-1.rhel4.noarch.rpm 
rpm -ivh ice-libs-3.3b-1.rhel4.i386.rpm 
rpm -ivh ice-utils-3.3b-1.rhel4.i386.rpm 
rpm -ivh mcpp-devel-2.6.4-1ice.rhel4.i386.rpm 
rpm -ivh ice-servers-3.3b-1.rhel4.i386.rpm 
rpm -ivh ice-libs-3.3b-1.rhel4.i386.rpm 
rpm -ivh ice-c++-devel-3.3b-1.rhel4.i386.rpm 
rpm -ivh ice-java-3.3b-1.rhel4.noarch.rpm 
rpm -ivh ice-java-devel-3.3b-1.rhel4.i386.rpm 

安装之后的Ice相关路径: 
slice2cpp,slice2java在/usr/bin/下 
Ice.jar 存储于 /usr/share/java/下 
相关的Ice的库存储于/usr/lib下. 

一切就绪,我们开始Ice之旅的Slice地带: 
首先,我们建立一个demo.ice的文件: 

Java代码  
  1. module Demo{  
  2. interface test{  
  3.  string   execute(string mth,string cmd);  
  4. };  
  5. };  


注意,后两个"}"一定要包含";",否则slice2java就会过不去,赫赫 
执行: 
slice2java demo.ice 

会在当前目录产生一个Demo目录,目录下自动生成: 
-rw-r--r--  1 root root 2316  4月 15 17:01 _testDelD.java 
-rw-r--r--  1 root root  560  4月 15 17:01 _testDel.java 
-rw-r--r--  1 root root 1929  4月 15 17:01 _testDelM.java 
-rw-r--r--  1 root root 4177  4月 15 17:01 _testDisp.java 
-rw-r--r--  1 root root 1070  4月 15 17:01 testHolder.java 
-rw-r--r--  1 root root  488  4月 15 17:01 test.java 
-rw-r--r--  1 root root  481  4月 15 17:01 _testOperations.java 
-rw-r--r--  1 root root  460  4月 15 17:01 _testOperationsNC.java 
-rw-r--r--  1 root root 5418  4月 15 17:01 testPrxHelper.java 
-rw-r--r--  1 root root  569  4月 15 17:01 testPrxHolder.java 
-rw-r--r--  1 root root  567  4月 15 17:01 testPrx.java 
到目前为止,demo.ice所以Ice接口部分的定义以及相关依赖都已经自动生成. 

我们要实现自己的execute方法,覆盖testPrx.java的同名方法: 
Java代码  
  1. //TestImp.java  
  2. package Demo;  
  3.   
  4. import Ice.Current;  
  5.   
  6.   
  7. public class TestImp extends _testDisp{  
  8.   
  9.     public String execute(String mth, String cmd, Current __current) {  
  10.         // TODO Auto-generated method stub  
  11.         return mth+cmd;  
  12.     }  
  13.   
  14.   
  15.   
  16. }  
看到了,就是这么简单,仅仅覆盖_testDisp里面的抽象方法,实现把我们自己的实现代码填充到里面就行了. 
之后,我们建立一个Server服务在10000端口进行侦听。 
Java代码  
  1. //Server.java  
  2. package Demo;  
  3.   
  4. public class Server {  
  5.     public static void main(String[] args) {  
  6.         int status = 0;  
  7.         Ice.Communicator ic = null;  
  8.         try {  
  9.             ic = Ice.Util.initialize(args);  
  10.             Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints(  
  11.                     "TestAdapter""default -p 10000");  
  12.             Ice.Object object = new TestImp();  
  13.             adapter.add(object, ic.stringToIdentity("TestAdapter"));  
  14.             adapter.activate();  
  15.             ic.waitForShutdown();  
  16.         } catch (Ice.LocalException e) {  
  17.             e.printStackTrace();  
  18.             status = 1;  
  19.         } catch (Exception e) {  
  20.             System.err.println(e.getMessage());  
  21.             status = 1;  
  22.         }  
  23.         if (ic != null) {  
  24.             // Clean up  
  25.             //  
  26.             try {  
  27.                 ic.destroy();  
  28.             } catch (Exception e) {  
  29.                 System.err.println(e.getMessage());  
  30.                 status = 1;  
  31.             }  
  32.         }  
  33.         System.exit(status);  
  34.     }  
  35. }  

貌似很复杂,其实里面的很多内容都是固定格式,有些部分需要固定和约定。其中上述红色部分是修改部分。 

到目前为止,我们已经完成了大部分工作,我们还需要建一个客户端来对服务端的方法进行调用。 
Java代码  
  1. package Demo;  
  2.   
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         int status = 0;  
  6.         Ice.Communicator ic = null;  
  7.         try {  
  8.             ic = Ice.Util.initialize(args);  
  9. //          Ice.ObjectPrx base = ic  
  10. //                  .stringToProxy("SimplePrinter:tcp -h 172.17.12.101 -p 10000");  
  11.             Ice.ObjectPrx base = ic  
  12.             .stringToProxy("TestAdapter:default -p 10000");  
  13.   
  14.             testPrx test = testPrxHelper.checkedCast(base);  
  15.             if (test == null)  
  16.                 throw new Error("Invalid proxy");  
  17.             System.out.println(test.execute("My first Ice ""demo"));  
  18.             //System.out.println("ok");  
  19.         } catch (Ice.LocalException e) {  
  20.             e.printStackTrace();  
  21.             status = 1;  
  22.         } catch (Exception e) {  
  23.             System.err.println(e.getMessage());  
  24.             status = 1;  
  25.         }  
  26.         if (ic != null) {  
  27.             // Clean up  
  28.             //  
  29.             try {  
  30.                 ic.destroy();  
  31.             } catch (Exception e) {  
  32.                 System.err.println(e.getMessage());  
  33.                 status = 1;  
  34.             }  
  35.         }  
  36.         System.exit(status);  
  37.     }  
  38. }  


也貌似很复杂吧,其实不然,也很简单,同样包含很多固定格式。其中 

Java代码  
  1. System.out.println(test.execute("my first Ice ""demo"));  


是我们自己调用的逻辑。 

赫赫,大功告成了,现在我们开始运行Server,再运行Client看到了么? 
"My first Ice demo" 

得到这样的结果,基本Ice之旅的Java部分简单实例我们基本完成。 

Ice的性能和稳定性远超于我们的想象,skype知道么?其部分通讯架构就是采用的Ice. 

ZeroC ICE之旅------Slice

 Slice是在ICE所特有的特殊语言,ICE 提供基于Ice语言的多语言映射工具。Slice主要针对程序所涉及到的接口和类型进行定义。不涉及到具体实现和具体语言的特征。 
   既然ICE支持跨语言的调用,那么是不是Slice支持每种的特有数据类型呢? 
   当然不是,ICE只是保留各种具体语言数据类型的最小交集。 
提供: 
Java代码  
  1. 1.bool (false or true,>=1bit)  
  2. 2.byte (-128-127@,>=8bits)  
  3. 3.short (-2^15 to 2^15-1,>=16bits)  
  4. 4.int (-2^31 to 2^31-1,>=32bits)  
  5. 5.long (-2^63 to 2^63-1,>=64bits)  
  6. 6.float (IEEE single-precision,>=32bits)  
  7. 7.double (IEEE double-precision,>=64bits)  
  8. 8.string (All Unicode characters, excluding ,the character with all bits zero.)  


string 采用Unicode编码,具有很好的国际化语言支持。 

下面主要在介绍一下Slice的特性和约束: 
1. Slice文件必须以.ice结尾,其他结尾方案的文件会被编译器拒绝。 
2. Slice 文件格式实际就是text文本描述,由于Slice形式自由,可以用任何文本编辑器进行编辑。 
3. Slice 支持#ifndef,#define,#endif,#include 
例如: 
Java代码  
  1. // File Clock.ice  
  2. #ifndef _CLOCK_ICE  
  3. #define _CLOCK_ICE  
  4. // #include directives here...  
  5. // Definitions here...  
  6. #endif _CLOCK_ICE  

在include 要避免使用双引号"",以及"",而要使用"/" 
例如: 
#include "Clock.ice" // 不推荐采用; 
#include <SliceDefs/Clock.ice> // 正确 
#include <SliceDefs\Clock.ice> // 非法 
4.Slice 中文件的结构,模块,接口,类型出现的顺序,,可以按照你的喜好而自由定义。 
5.Slice 的词法规则很多来源于C++和Java,只有少量的差异。 
6.可以采用c++的注释规则。// 或  
7.Slice 的关键词需要区分大小写: 
关键词: 
Java代码  
  1. bool        enum        implements      module      struct  
  2. byte        exception   int         Object      throws  
  3. class       extends     interface       out     true  
  4. const       false       local           sequence    void  
  5. dictionary  float       LocalObject     short  
  6. double      idempotent  long            string  
8.在接口定义的时候也避免使用非Slice关键字,但是C++ 或 Java关键字的标识符。 

例如:switch 

9.Ice保留了所有以"ice"作为开始标识符。保留以"Helper","Holder","Prx","Ptr"结尾的标识符。所以大家定义的时候最好避免一些不必要的麻烦。 

10.Ice可以通过module嵌套的方式,类似于c++的namespace和java的包的概念。 


11.除了刚才提到的Slice支持的基础类型外,还支持用户自定义类型:enumerations, structures, sequences, and dictionaries. 

enumerations:枚举就不要介绍了,采用C++的语法形式 
enum Fruit { Apple, Pear, Orange }; 

Structures:结构,也是采用C++的语法形式,避免,结构中定义结构 
Java代码  
  1. 合法:  
  2. struct TimeOfDay {  
  3. short hour; // 0 - 23  
  4. short minute; // 0 - 59  
  5. short second; // 0 - 59  
  6. };  
  7. 无效:  
  8. struct TwoPoints {  
  9. struct Point { // Illegal!  
  10. short x;  
  11. short y;  
  12. };  
  13. Point coord1;  
  14. Point coord2;  
  15. };  

sequence:序列号类型,映射到java采用的数组方式实现,而不是所谓的集合容器类型对象存储。映射到C++中则采用STL容器存储。 
sequence<int> values; 
dictionary:字典类型,映射到java采用Map 进行存储,映射到C++采用map进行存储. 
dictionary<int,string> myValues; 
12.常量定义可以直接使用,但常量的定义必须是基本类型或枚举类型.定义形式也是采用C++定义方式. 
13.方法的定义,形式类型java的方法定义,方法返回可以使void或对象类型. 
14.Slice支持方法异常的定义,以及异常的继承.关于异常机制,我想java开发者可能更加熟悉, 
例如: 
Java代码  
  1. exception Error {}; // Empty exceptions are legal  
  2. exception RangeError {  
  3. TimeOfDay errorTime;  
  4. TimeOfDay minTime;  
  5. TimeOfDay maxTime;  
  6. };  
  7. interface Clock {  
  8. idempotent TimeOfDay getTime();  
  9. idempotent void setTime(TimeOfDay time)  
  10. throws RangeError, Error;  
  11. };  

Ice的错误机制也是异常强大,吸取了很多Java关于异常机制的特点. 


Slice还包括很多良好的特性,在这里就不一一列举,对于支持自定义类型,基本类型,异常支持,对于一般的网络通讯应用已经足够了,更多Slice语言的介绍参阅其帮助. 

Ice为我们提供了强大而又丰富的Slice,可以利用Slice,结合我们应用的特点,定义间接的Slice描述。 

btw: 

    虽然Slice提供给我们丰富的功能和特性,在此我还是建议大家尽量采用基本类型和非异常机制.这样会对系统性能会带有一定的帮助。 
    另外接口的定义我想大家能够保持KISS(Keep it It Simple)设计原则,会使我们的应用看起来更美丽。 
    不要过度的使用Slice,否则会给我们带来无尽的烦恼。 

ZeroC ICE之旅------多语言互通互联

ce的服务端可以采用C++/Java/Python/C#等实现,客户端可以采用C++/Java/Python/C#/VB/PHP/Ruby来实现,就是说我的一个服务端采用C++实现,客户端可以采用java/php/vb/c# 等其他语言实现。 

这个特性也是Ice的很重要的优势之一. 

Ice的多语言之间如何确保对象的正确传输,每种语言都有各自的特点,数据类型,Ice是如何达到各种语言之间的互通互联的呢? 
那么就一定提到Slice语言.Slice是保证各种语言的互通互联的关键,它是独立于其它任何语言,Ice可以通过把Slice代码片断转化为各自的 

语言描述. 

Java代码  
  1. -rwxr-xr-x  1 system users 447888 2007-03-09  slice2java  
  2. -rwxr-xr-x  1 system users  67753 2007-03-09  slice2py  
  3. -rwxr-xr-x  1 system users  38679 2007-03-09  slice2rb  
  4. -rwxr-xr-x  1 system users 505441 2007-03-09  slice2vb  
  5. -rwxr-xr-x  1 system users 507119 2007-03-09  slice2cpp  
  6. -rwxr-xr-x  1 system users 454347 2007-03-09  slice2cs  


赫赫够多! 

Slice的全称:Specification Language for Ice,是Ice自己的特殊语言,一种用于使对象接口与其实现相分离的基础性抽象机制。Slice 建立在客户与服务器之间的合约,用以描述应用所使用的类型和对象接口。Slice描述独立于实现语言,所以客户实现语言是否与编写服务器所用的语言相同没有任何关系。 

slice语言片段可以被编译为任何所支持语言的实现。目前Ice Slice可以支持映射到到C++, Java, C#, Python,Ruby, and PHP。 
因为Slice主要对接口和类型的定义和描述,没有实现部分。 

到底如何实现不同语言的互通互联的呢?我们已Java,C++作为Ice例子原形,实际上我们仅仅做少量修改,就可以实现 

C++的服务端,Java的客户端。Server和Client还是保持在同一台机器上运行。注意我们基于同一个demo.ice的事例。 

首先运行./Server,再运行Client,看到结果了么?赫赫,是不是出现了正常结果。 

到目前没有我们所有实例都是基于同一台机器的,实际情况Server,Client会分布在不同机器上。这种情况下,我们需要如何处理呢? 


这个很简单,在Server少量修改 
Java代码  
  1. Ice::ObjectAdapterPtr adapter  =   ic->createObjectAdapterWithEndpoints ("TestAdapter",                                "default -p 10000");  


"default -p 10000" 采用 "tcp -h server1 -p port" 替代 

Server所在主机IP:172.17.12.101 ,端口:10000 

所以就修改为:tcp -h 172.17.12.101 -p 10000,再重新编译Server 

Java代码  
  1. #include <Ice/Ice.h>  
  2. #include <demo.h>  
  3. using namespace std;  
  4. using namespace Demo;  
  5. class Server:public test  
  6. {  
  7. public:  
  8.   ::std::string execute (const string & mth, const string & str,  
  9.                          const Ice::Current &);  
  10. public:  
  11.     Server ();  
  12. };  
  13. Server::Server ()  
  14. {  
  15.    
  16. };  
  17. std::string Server::execute (const string & mth, const string & str,  
  18.                              const Ice::Current &)  
  19. {  
  20.   cout << mth + str << endl;  
  21.   return mth + str;  
  22. }  
  23.    
  24. int  
  25. main (int argc, char *argv[])  
  26. {  
  27.   int  
  28.     status = 0;  
  29.   Ice::CommunicatorPtr ic;  
  30.   try  
  31.   {  
  32.     ic = Ice::initialize (argc, argv);  
  33.     Ice::ObjectAdapterPtr adapter  
  34.       =  
  35.       ic->createObjectAdapterWithEndpoints ("TestAdapter",  
  36.                                             "tcp -h 172.17.12.101 -p 10000");  
  37.     Ice::ObjectPtr object = new Server;  
  38.     adapter->add (object, ic->stringToIdentity ("TestAdapter"));  
  39.     adapter->activate ();  
  40.     ic->waitForShutdown ();  
  41.   } catch (const Ice::Exception & e)  
  42.   {  
  43.     cerr << e << endl;  
  44.     status = 1;  
  45.   } catch (const char *msg)  
  46.   {  
  47.     cerr << msg << endl;  
  48.     status = 1;  
  49.   }  
  50.   if (ic)  
  51.     {  
  52.       try  
  53.       {  
  54.         ic->destroy ();  
  55.       }  
  56.       catch (const Ice::Exception & e)  
  57.       {  
  58.         cerr << e << endl;  
  59.         status = 1;  
  60.       }  
  61.     }  
  62.   return status;  
  63. }  

编译方式参见: 
http://masterkey.iteye.com/blog/183307 

下面我们需要对Client连接部分进行修改,同理: 
Java代码  
  1. Ice.ObjectPrx base = ic.stringToProxy("TestAdapter:tcp -h 172.17.12.101 -p 10000");  


Java代码  
  1. package Demo;  
  2.   
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         int status = 0;  
  6.         Ice.Communicator ic = null;  
  7.         try {  
  8.             ic = Ice.Util.initialize(args);  
  9. //          Ice.ObjectPrx base = ic  
  10. //                  .stringToProxy("SimplePrinter:tcp -h 172.17.12.101 -p 10000");  
  11.             Ice.ObjectPrx base = ic  
  12.             .stringToProxy("TestAdapter:tcp -h 172.17.12.101 -p 10000");  
  13.   
  14.             testPrx test = testPrxHelper.checkedCast(base);  
  15.             if (test == null)  
  16.                 throw new Error("Invalid proxy");  
  17.             System.out.println(test.execute("My first Ice ""事例"));  
  18.             //System.out.println("ok");  
  19.         } catch (Ice.LocalException e) {  
  20.             e.printStackTrace();  
  21.             status = 1;  
  22.         } catch (Exception e) {  
  23.             System.err.println(e.getMessage());  
  24.             status = 1;  
  25.         }  
  26.         if (ic != null) {  
  27.             // Clean up  
  28.             //  
  29.             try {  
  30.                 ic.destroy();  
  31.             } catch (Exception e) {  
  32.                 System.err.println(e.getMessage());  
  33.                 status = 1;  
  34.             }  
  35.         }  
  36.         System.exit(status);  
  37.     }  
  38. }  

看到了么,就是这么简单,其他部分不用修改。 

好了,我们进行验证,首先启动./Server,再执行Client ,看到了 

"My first Ice 事例" 看到了么,祝贺你,跨语言的分布式调用例子你已经实现了。 


其实Ice的通讯机制极其强大,支持集群和容错技术。关于集群的事例会在日后的文章中介绍。 

BTW: 

注意,Server运行之后监听于10000端口,需要修改iptables,允许其他机器可以连接。 
编辑 iptables 
vi /etc/sysconfig/iptables 
追加: 
Java代码  
  1. -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 10000 -j ACCEPT  

ZeroC ICE之旅------负载均衡及容错


Zero ICE我们已经掌握其基本运行原理。下面我们主要介绍一下ICe的多端口邦定的问题。 
ICE使用TCP/IP 和UDP协议,以及基于TCP/IP之上的SSL协议。SSL协议可以充分保障Server/Client数据传输的加密安全性问题。 
在这里,Server如何在同一台主机监听多个端口。 


关于TCP/IP还是UDP还是SSL协议的选择,还是要看具有应用的要求,通常情况下TCP/IP协议的ICE应用已经足够了。 

在同一个主机主机上,ICE服务支持多端口的监听。 

服务端注册: tcp -h host -p port1:tcp -h host -p port2形式, 

例如: 

IP:172.17.12.101,需要在10001和10000同时监听。 

就可以写成: 

tcp -h 172.17.12.101 -p 10000:tcp -h 172.17.12.101 -p 10001 


赫赫是不是很简单,运行之后,服务就监听于10000和10001端口,请注意:避免其他应用相冲突。 


客户端连接可以采用如下3种形式: 

1. tcp -h 172.17.12.101 -p 10000 
2. tcp -h 172.17.12.101 -p 10001 
3. tcp -h 172.17.12.101 -p 10000:tcp -h 172.17.12.101 -p 100001 

是不是很爽。 

无论Server监听在多个端口,还是只有唯一的一个Server在工作, 

对于Client较多的应用或负载要求很高的情况下,我们可以把Server程序运行于多台主机之上。通过集群方式合理有效的化解来自Client的压力。 

例如: 

ServerA 172.17.12.101 tcp -h 172.17.12.101 -p 10000 
ServerB 172.17.12.102 tcp -h 172.17.12.102 -p 10000 
ServerC 172.17.12.103 tcp -h 172.17.12.103 -p 10000 


Client可以如下的连接方式: 
tcp -h 172.17.12.101 -p 10000:tcp -h 172.17.12.102 -p 10000:tcp -h 172.17.12.103 -p 10000 

或是 
tcp -h 172.17.12.101 -p 10000:tcp -h 172.17.12.102 -p 10000 

等多种情况,可以根据应用的具体要求合理有效的构造所需连接主机的字符串。 


这种连接方式是不是很cool。 

其实这种连接方式可以有效地利用ICE提供的load balancing功能,把Client的每个请求合理的分配到每个Server。从而有效地避免了Client大量请求对同一台Server的巨大压力。 


ICE的load balancing主要采用round-robin算法,round-robin是一种非常有效的负载均衡算法. 



大家会问了,如果某个Server如果宕机,那么这个Client还能正常工作么? 

    这个问题问得好,其实ICE自身提供一种极其强大容错技术功能。 
    具体体现在如果当某个Server(假设是ServerA)宕机之后,来自Client的请求分配到ServerA服务器上,Client会自动记录ServerA失效状态,会把请求再分配给可正常工作的Server(ServerB,ServerC),对于用户的每次请求都能分配到正常的服务主机上(除非A,B,C都同时宕机).当ServerA回复正常之后,Client会自动感知ServerA工作状态.Client的请求又可以有效地分配到上述A,B,C主机上.这一切对于开发者都是透明的. 

ICE所提供的集群功能和容错功能是极其强大的. 



   Client状态感知的变化和更新完全不需要Client重新启动。

你可能感兴趣的:(ZeroC ICE之旅)