完整word版ICE第二版模板.docx
《完整word版ICE第二版模板.docx》由会员分享,可在线阅读,更多相关《完整word版ICE第二版模板.docx(10页珍藏版)》请在冰豆网上搜索。
完整word版ICE第二版模板
第2章ZerocICE启程
2.1ZerocICE平台介绍
ZerocICE(以下简称ICE)师出名门,是由前CORBA专家MarcLaukien、MichiHenning及SSL安全调用,并且随着IT技术的变化和发展,ICE不断地推陈出新,每年都有新版本问世,从诞生到当下,十几年的历史,其王者地位无人撼动。
ICE
,因此在很多细节方面都有一些值得称道的做法,下面是其中一些关键特性。
∙支持多语言之间的RPC互通。
与众多平台不同,它的服务端也可以是几种语言开发,比如C、.NET、JAVA、Python等,不同语言开发的服务端与客户端可以完全互通,对于支持多语言的服务来说,是很难得的一个特性,省去了大量的开发成本和开发周期。
∙高性能RPC调用。
这点是业界公认的,一些大型联网游戏及Skype等对实时性要求很高的系统都采用了ICE平台,足以说明这一点。
笔者也曾做过简单对比,也验证了其高性能,而且在不同语言的客户端调用时,其性能仍然很好。
∙支持传统的RPC调用、异步调用、One-Way调用,批量发起请求,支持TCP通信、UDP通信适用于不同业务场景。
∙支持安全通信,ICE框架里提供了支持业界标准的SSL安全加密的可拔插插件。
并且多种编程语言都支持该特性。
∙多平台支持。
包括X86系统、ARM、移动设备等。
∙提供了强大的ICEGrid。
支持注册表主从备份,无单点故障,服务按需启动,随时扩容和迁移,完备的负载均衡机制无须客户端重启,自动感应服务位置的变化。
∙不断更新,与时俱进。
对近些年流行的JavaScript语言及新的移动平台的支持都及时跟上。
这里,笔者仅就多语言开发支持这一特性来分析ZerocICE平台所能带给你的额外价值,当你采用ICE框架开发一个服务后所能直接变现的承诺,在图2.1中完美诠释:
。
图2.1ICE多语言支持示意图
对于一个规模较大的平台来说,开发一个服务并不很难,但如何让多种语言都能很一致地调用你的服务并联调通过,则很不容易,即使对于SOAP这种看似很标准的接口来说,依然存在很多编程语言和SOAP框架的版本等兼容性问题。
而HTTPRest的接口,在联调时还是会碰到各种参数问题。
从经验来看,除非把一个现成的编译好的客户端代码发给对方,否则会开发一次,到处联调,形成平台开发的梦魇。
我们来看看ICE平台的组成,ICE平台从功能可以划分为以下几部分。
∙Slice工具。
将Slice语言定义的服务接口编译成各种具体语言的实现代码,属于开发环境的一部分。
∙ICE容器和命令。
包括ICEGrid、ICERegistry、ICENode、ICEAdmin、ICEPatch等命令,用于启动、管理ICEGrid,需要在运行ICE服务的机器上选择性部署其中的某一个或几个组件。
∙ICE运行库。
为一组API库,不同的语言有不同的实现,如Java对应Jar文件,C语言对应.so文件(在Windows下对应为.dll文件),这些运行库需要被ICE服务端程序和客户端程序所调用,以实现ICE内部的底层通信。
下面我们看看采用ICE平台开发一个具体项目时所要遵循的一般流程,如图2.2所示。
图2.2ICE跨语言开发流程示意图
这个开发流程示意图告诉我们,怎样从零开始,开展ICE跨平台的项目开发活动,简单的说,就是首先用Slice语言定义中立的服务接口文件,然后采用相应语言的命令行编译生成对应的程序骨架源文件,最后实现服务端业务代码开发,部署服务,然后客户端利用Ice提供的运行期客户端Library(JAR文件)实现远程服务方法调用,详细步骤如下所示:
∙分析和设计系统的服务:
采用面向服务架构或者是“微服务”的设计理念进行系统分析和设计,确定系统中的“服务”单元、每个服务的接口及服务之间的依赖关系。
∙服务接口定义:
采用ICESlice语言对服务接口进行定义,并用Slice工具编译成你所熟悉的开发语言(本书以Java为例)的实现代码,这些实现代码包括服务端和客户端骨架代码,可以认为是项目中的“公共”包。
∙服务端业务逻辑实现:
在Slice生成的服务端代码上进行业务逻辑代码的编写,在这个过程中除了在服务之间相互调用时用到ICE的一些API外,在绝大多数情况下,不会用到ICE的代码。
∙编写ICEGrid的服务描述文档:
xxxgrid.xml,此文档类似于J2EE的web.xml或EJB的服务描述文件,定义了每个服务的访问地址(Endpoint)、部署的节点(ICENode)、负载均衡策略(replica-group)等关键信息。
∙打包代码并部署到各个ICENode上,启动ICEGrid,借助ICE工具发布xxxgrid.xml,服务端工作至此基本完成。
很重要的一点是,借助ICE平台提供的工具,你可以很方便地将xxxgrid.xml中的服务重新规划和部署到新的节点上,而客户端无须重启和改变任何代码。
∙编写客户端软件,访问部署好的服务,并有针对性地做性能测试和调优。
初步了解了ICE的特性、组成部分及开发流程之后,让我们休息一会,因为接下来需要学习和理解ICE平台的几个重要术语和概念,这个是需要动脑筋的,随便看看绝对无法过关。
2.2ICE的概念和原理
一:
ICEObject
任何系统都会使用一些专有名词来阐明其原理和实现机制,最终,往往几个名词就概括了其背后庞大复杂的技术体系,比如现在流行的Hadoop、NoSQL、NewSQL、BigData等。
对于一个复杂的系统来说,准确理解和掌握其专有术语非常重要,不仅仅因为相关的技术文档里大量使用了这些概念和术语,而且因为在编程实践和问题排查过程中,这些概念和术语有助于我们推理、分析问题产生的根源和发现可能的解决方案。
作为一个复杂的RPC平台,ICE也创造了很多概念和术语,其中一个名词就是Slice,Slice模仿Cobra的IDL(InterfaceDefinitionLanguage)而来,与IDL相似,ICE采用编程语言中立的Slice这种接口描述语言来定义一个RPC服务接口,然后提供了指向具体编程语言的“翻译工具”——slice2XXX,该工具将Slice文件编译成相应语言的源码,这些源码中包括了客户端运行期Stub代码,以及服务器端的Skeleton框架代码。
要理解这一切背后的秘密,需要从ICE最根本的概念——ICEObject说起。
ICEObject具有以下特征。
∙拥有一个对象标识符ObjectIdentity来区别于其他类型对象,ICE的对象模型中要求对象标识符是全局唯一的,即没有任何对象的标识符相同。
∙一个ICEObject是一个可以对客户端请求进行应答的对象,这个对象可以是存在于“本地进程的地址空间”也可以是位于“远程地址空间”。
∙一个ICEObject拥有一个或多个接口,其中一个接口是其主要接口,是此对象区别于其他对象的主要特征,其余接口则被称为Facet。
一个ICEObject在服务端具体化为一个Servant实例,即我们用某种具体编程语言实现的一个Slice接口并新建的某个对象就是一个Servant。
而将ICEObject与Servant进行关联的“桥”则是我们接下来要理解的概念——ObjectAdapter,它是ICE运行时框架与用户应用程序代码之间的边界点,ObjectAdatper具有以下功能。
∙提供一个或多个通信端点(TransportEndpoint),客户端通过这些端点中的某个端点连接到一个具体的ICEObject对象,一个Endpoint由服务端所使用的通信协议、IP地址、端口等信息所组成,如default-h192.168.0.1-p1000,表明是采用默认的协议(TCP),绑定在192.168.0.1的端口1000上的一个通信端口。
∙绑定一个或多个Servant,每个Servant与一个ICEObject映射,将客户端针对某个ICEObject的请求派发映射到对应的Servant上,并完成整个请求流程的处理过程,包括底层通信。
∙协助生命周期管理,消除ICEObject与Servant在启动和销毁过程中所可能存在的竞争问题。
从上面的ObjectAdapter的功能来看,很多时候我们可以把ObjectAdapter与在它之上绑定的ICEObject做等价,因为ObjectAdapter是ICEObject的“宿主”,不但提供了ICEObject的访问地址(Endpoint),而且负责完成请求处理转发的流程。
因此,你会看到很多时候有这样的写法:
SimplePrinter@PrinterAdapter。
二:
IceProxy
接下来让我们看看ICEObject在客户端的代表——Proxy,简单地说,Proxy是客户端用来访问远程某个ICEObject的本地“代理”,Proxy存在于客户端的进程地址空间中,“代表”一个远程对象,当客户端调用远程对象的某个方法时,ICE运行时期的客户端代码库(ICERuntime)会完成如下具体工作。
∙定位远程对象ICEObject。
∙如果ICEObject所在的Server处于关闭状态,则自动激活此Server,并激活远程对象。
∙将方法的入参(传入到远程对象的参数)通过Socket传输到远程对象。
∙等待调用完成。
∙将方法的出参(返回给调用者的参数)返回给客户端,若发生异常则抛出调用异常。
作为远程ICEObject的本地“代理”,Proxy还持有如下重要信息。
∙远程Server的地址信息,用来初始化通信
∙用来定位ICEObject的对象标识符:
objectidentity。
∙可选的Facet标识符,用来确定引用ICEObject的哪个接口。
∙一个具体的Proxy可以用一个包括Endpoint信息的字符串描述,比如SimplePrinter:
default-p10000,表示为在远端的TCP端口10000上绑定的一个SimplePrinter对象的Proxy,代码中我们可以用这样的特定格式的字符串,来构造一个Proxy对象。
Endpoint通常可以理解为一个访问地址,在WebService中也有这个词:
“当我们Host一个WebService时,我们必须为其定义一个或多个Endpoint,然后Service通过这个定义的Endpoint监听来自Client端的请求”。
在ICE中,Endpiont有UDP或TCP两种,但基本上很少用UDP,因为在现在的高速网络带宽采用TCP长连接的情况下,UDP基本上没有什么优势了。
Proxy有DirectProxy与IndirectProxy两种:
前者的Proxy直接绑定某个远端Object的访问地址,如SimplePrinter:
default-p10000;后者则不绑定到远程Object的某个具体的通信地址上,而且有两种写法,其中第一种写法是直接饮用远程对象的标识符,如SimplePrinter,这种对象需要被定义为WellKnowObject,第二种写法是SimplePrinter@PrinterAdapter,即访问绑定到某个ObjectAdapter之上的某个对象,此时不需要ICEObject为WellknowObject。
对于IndirectProxy来说,由于没有远程对象的具体地址信息,因此,需要借助于寻址服务——LocationService来获取对应Object的通信地址。
第三:
LocationService
ICE提供的LocationService究竟是什么?
其实就是利用了ICE的注册表(Registry)来实现ObjectIdentity到Endpoint的查询服务,这个查询服务以及相关的API组成了ICE的LocationService组件,ICE的注册表里保持了ICEObject、ObjectProxy、Server等相关信息,属于ICEGrid体系的重要组成部分,而这种注册表组件也是绝大多数分布式系统的关键组件之一。
理解IndirectProxy对于理解和掌握ZerocICE来说非常重要,因为在ICEGrid这种分布式框架中,所有Proxy都是Indirect的,从而实现了复杂的负载均衡和故障恢复机制。
图2.3给出了IndirectProxy发起服务调用的过程。
图2.3ZerocICEIndirectProxy客户端调用原理图
其过程如下所述。
(1)客户端发起对远程ICEObject的方法InitialOp的调用。
(2)客户端寻址,这个过程非常类似于DNS寻址,LocationService则相当于DNS服务,寻址过程就是IndirectProxy向LocationService发出查询命令,而LocationService收到查询请求后,从注册表Registry中获取对应Object的地址信息并返回。
(3)客户端Proxy直接跟远程对象建立通信连接,实现调用。
第四:
总结
最后,我们给出一个包含了上述种种概念的示意图(见图2.4),来做一个总结,并对之前没有提到的几个概念做一个补充。
在ICE中,ICEObject、ObjectAdapter、Servant属于服务端的概念,它们存在于一个ICEServer中,这个Server容器通常是一个ICEBox进程。
ASM(ActiveServantMap)是一个对象标识符(ObjectIdentity)到对应的Servant的查询表(LookupTable),也就是ICEObject到Servant的映射表,当一个客户端在某个Endpoint上发起对某个ICEObject的请求访问时,ASM用来快速定位到具体的Servant上,以便高效派发请求。
图2.4ZerocICE核心概念示意图
最后,让我们来看看ICE的另外一个重要概念——Replication,该词的含义是让ObjectAdapter(及上面寄宿的ICEObject)“拥有”多个访问地址。
其目标是在多个机器上部署相同的Server来实现服务的负载均衡和容错机制,另外,当其中一台机器宕机时,客户端仍然可以通过其他机器正常访问这些对象。
当我们用下面的字符串来构造一个Proxy时,这个Proxy就具备了Replication功能:
SimplePrinter:
tcp-hserver1-p10001:
tcp-hserver2-p10002
除了这种简单的方式,ICE还支持另外一种高级的更符合大规模分布式部署的Replication方式:
ReplicationGroup,一个ReplicationGroup具备唯一的名字,并且绑定一组相关的ObjectAdapter,Proxy则通过绑定到这个ReplicationGroup上来实现负载均衡,如我们定义一个名为SimplePrinter@PrinterAdapters的RepGroup,Proxy访问这个Group的时候,通过ICE的LocationService来解析地址并实现访问,其原理就是上面介绍过的IndirectProxy机制,这里的不同之处只有一点:
ReplicationGroup返回的是一组可用地址信息,以实现负载均衡和容错机制。
看完本节,如果你已经对在本节中出现的这些术语的含义及ICE的实现原理有了清晰的认识和理解,那么恭喜你顺利通关,准备开始扬帆出发吧!
但你若此刻头昏脑胀,一团乱麻,则也不必担心,休息一天,明天重新读一遍,因为以下代码绝对不会死循环:
While(notunderstand)
{
Tryreadagain.
}
//初始化通信器
ic=Ice.Util.initialize(args);
//传入远程服务单元的名称、网络协议、IP及端口,构造一个Proxy对象
Ice.ObjectPrxbase=ic.stringToProxy("MyService:
default-p10000");
//通过checkedCast向下转型,获取MyService接口的远程,并同时检测根据传入的名称
//获取服务单元是否OnlineBook的代理接口