




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、ICE系列培训(三)鲍齐权统一网管平台专项培训内容1. ICE运行时2. 动态ICE3. 连接管理4. Freeze Map1.1 概述本章主要介绍ICE运行时的一些内部细节:通信器ICE上下文对象适配器连接超时对象标识单向、数据报、批量调用Current对象定位服务Servant自动重试ICE线程模型字符串编码代理插件开发1. ICE运行时1.2 通信器通信器Ice:Communicator是Ice运行时的主入口点,其实例与一些运行时资源关联在一起:客户端线程池对象适配器服务端线程池配置属性对象工厂日志记录器统计对象缺省路由器缺省定位器插件管理器1. ICE运行时1.2 通信器注意:不同通信
2、器的对象适配器以及ICE对象是相互独立的;不同通信器使用其自己的线程池,互不干扰;通常情况下,一个服务器中使用一个通信器即可;某些情况下多通信器更有用:例如,IceBox对每个Ice服务使用不同的通信器这样保证不同服务间互不干扰;1. ICE运行时1.2 通信器通信器接口:module Icelocal interface Communicatorstring proxyToString(Object *obj);Object *stringToProxy(string str);通信器提供大量接口来操作它所关联的运行时资源,后面介绍各个资源时再介绍。1. ICE运行时1.3 通信器的初始化在
3、创建通信器时,ICE运行时初始化了一系列通信器特性,这些特性影响通信器的行为;注意:这些特性生命期随通信器生命期一起,通信器创建后就不能更改了。因此,你必须在创建通信器时设置好这些特性; 初始化使用Ice:initialize函数:namespace Ice CommunicatorPtr initialize(int&, char*, const InitializationData& = InitializationData(), Int = ICE_INT_VERSION); CommunicatorPtr initialize(StringSeq&, const
4、 InitializationData& = InitializationData(), Int = ICE_INT_VERSION); CommunicatorPtr initialize(const InitializationData& = InitializationData() Int = ICE_INT_VERSION); 1. ICE运行时1.3 通信器的初始化通信器创建时可以定制下列特性: 属性集合属性集合 日志接口日志接口 状态接口状态接口 宽宽/ /窄字符集转换器窄字符集转换器 线程通知线程通知hookhook 分派器分派器 类装载器(仅类装载器(仅java
5、java) 1. ICE运行时1.3 通信器的初始化要建立这些特性,你需要填充一个InitializationData结构: namespace Ice struct InitializationData PropertiesPtr properties; LoggerPtr logger;StatsPtr stats;StringConverterPtr stringConverter;WstringConverterPtr wstringConverter;ThreadNotificationPtr threadHook; DispatcherPtr dispatcher; ; ; 1.
6、ICE运行时示例:运行时属性集可从文件中读取InitializationData initData;initDperties = createProperties();initDperties-load(configFile);1.3 通信器的初始化例如:定制一个类型为MyLogger的日志记录器 Ice:InitializationData id;id.logger = new MyLoggerI; Ice:CommunicatorPtr ic = Ice:initialize(argc, argv, id);1. ICE运行时例如,我们的总线客户端的通信器是在下
7、面所示函数内初始化的:void CBusClientForRpcClient:ClientInit(const string &strUnmBusRegistryServerAddress, const string &strClientName)Ice:InitializationData initData;m_poVar-m_poRpcCommunicator = Ice:initialize(initData);1.4 对象适配器对象适配器是位于Ice运行时和实际服务提供对象(Servant)之间,实现以下职责:(1)将Ice对象(培训一中有介绍什么是Ice对象和Serv
8、ant)映射到Servant,并分派请求给Servant;(2)辅助Ice对象和Servant的生命期操作;(3)提供传输端点;注意:每个通信器可拥有一个或多个对象适配器;每个对象适配器可拥有一个或多个Servant;每个对象适配器可拥有多个传输端点,这些传输端点代表的是通向同一组对象的不同路径;每个对象适配器可非强制性拥有自己的线程池(通过.ThreadPool.Size设置)如果设置了适配器自己的线程池,那么给对象适配器的分配操作将使用自己线程池中的线程,而不会使用通信器中的线程池。1. ICE运行时1.4.1 活动Servant映射表每个对象适配器都维护有一个活动Servant映射表(A
9、SM)。对于收到的客户端请求,对适配器会根据对象标识到ASM中查找正确的Servant来分派这个请求。注意:如果客户端请求包含的对象标识无法在ASM中找到正确的Servant,则适配器会返回ObjectNotExistException异常给客户端(适配器没有使用Servant定位器时)1. ICE运行时1.4 对象适配器1.4.2 ServantsServant是位于服务端,为客户端提供实际服务业务的Ice对象实例,它使用具体语言实现Ice接口。注意:同一Servant可注册给多个对象适配器;Ice:ObjectAdapterPtr adapter = communicator()-crea
10、teObjectAdapter(Hello);/ ServantDemo:HelloPtr hello = new HelloI; adapter-add(hello, communicator()-stringToIdentity(hello);adapter-activate();1. ICE运行时1.4 对象适配器HelloI实现的接口Slice定义:module Demo interface Hello idempotent void sayHello(int delay); void shutdown(); ;接口实现:class HelloI : public Demo:Hello
11、;1.4.3 对象适配器的创建及提供的接口对象适配器的创建:使用通信器提供的方法::Ice:ObjectAdapterPtr createObjectAdapter(const :std:string&);:Ice:ObjectAdapterPtr createObjectAdapterWithEndpoints(const :std:string&, const :std:string&);:Ice:ObjectAdapterPtr createObjectAdapterWithRouter(const :std:string&, const :Ice:Rou
12、terPrx&);对象适配器提供了大量本地接口可用来访问适配器:module Ice local interface ObjectAdapter string getName(); Communicator getCommunicator(); / . ; ; 1. ICE运行时1.4 对象适配器示例: Ice:ObjectAdapterPtr adapter = ic-createObjectAdapterWithEndpoints( SimplePrinterAdapter, default -p 10000);1.4.4 Servant的激活与解除激活Servant激活:告知Ic
13、e运行时某个Servant的存在(加入ASM)。解除激活:将Servant从ASM中移除。对象适配器提供了add函数来激活和解除Servant:Object *add(Object servant, Identity id);Object *addWithUUID(Object servant);void remove(Identity id);1. ICE运行时1.4 对象适配器1.4.4 Servant的激活与解除激活注意:不允许使用同一标识激活多次;不同标识可用来激活同一Servant多次,这种情况下同一Servant将表现为多个Ice对象;addWithUUID会自动为Servant生
14、成一个UUID作为对象标识。Demo:HelloPtr hello = new HelloI; / Servant adapter-add(hello, communicator()-stringToIdentity(hello);1. ICE运行时1.4 对象适配器1.4.5 对象适配器状态对象适配器具有三种状态:保持状态(holding);活动状态(active);不活动状态(inactive)。1. ICE运行时1.4 对象适配器1.4.5 对象适配器状态保持状态(holding)处于保持状态的适配器,任何到来的请求客户端都会收到TimeoutException或ConnectTimeo
15、utException异常。注意:出于保持状态下面向流协议的适配器(TCP/IP),服务端运行时会停止从相应的传输端点读数据,同时也会拒绝客户端的连接请求。对象适配器提供的操作:void Ice:ObjectAdapter:hold();该操作或将适配器置为hold状态,但是不会等待已有请求的完成,会立即返回。void Ice:ObjectAdapter:waitForHold();该操作会阻塞调用线程,知道所有已有请求完成。1. ICE运行时1.4 对象适配器1.4.5 对象适配器状态活动状态(active)活动状态下的适配器可以接收并分派请求到servant注意:新创建的适配器初始化状态是
16、Holding状态;双向连接的适配器不需要激活(双向连接参见1.7);并置调用(collocated invocation)即使适配器没有激活调用也会成功,除非你禁用了并置调用优化。对象适配器提供的操作: void Ice:ObjectAdapter:activate();激活对象适配器,例如:Ice:ObjectAdapterPtr adapter = communicator()-createObjectAdapter(Hello); Demo:HelloPtr hello = new HelloI; / Servant adapter-add(hello, communicator()-
17、stringToIdentity(hello); adapter-activate(); / 激活适配器1. ICE运行时1.4 对象适配器1.4.5 对象适配器状态不活动状态( inactive )不活动状态下,适配器在概念上已经被销毁了。一旦适配器处于不活动状态,那么它将不能再被重新激活对象适配器提供的操作: void Ice:ObjectAdapter:deactivate(); void Ice:ObjectAdapter:waitForDeactivate(); void Ice:ObjectAdapter:isDeactivated(); void Ice:ObjectAdapte
18、r:destroy();1. ICE运行时1.4 对象适配器1.4.6 Endpoints(端点)Endpoints:由:传输协议、主机名、端口组成;格式:protocal h host addr1 p port No.: protocal h host addr2 p port No.一个对象适配器维护有两组传输端点:一组用于对象适配器监听新的连接物理传输端点;一组嵌入适配器创建的代理对象中,用于客户端通信使用(发布端点)published endpoints; (大多数情况下,这两组端点是一样的,但它们是可以独立配置的)1. ICE运行时1. ICE运行时1.4 对象适配器1.4.6 En
19、dpoints(端点)物理端点(Physical Endpoints )物理传输端点是对象适配器用来接收客户端请求用的; 可由:name.Endpoints属性或createObjectAdapterWithEndpoints方法进行设定;例如:Hello.Endpoints=tcp -p 10000:udp -p 10000:ssl -p 10001注意:(1)如果端点中定义了主机名,那么对象适配器只能监听该网络接口上的请求;(2)如果端点中未定义主机名,但是属性Ice.Default.Host定义了,那么对象适配器将监听Ice.Default.Host定义的主机名的端点;(3)如果上面两者
20、都未定义,那么对象适配器将监听所有网络接口;1. ICE运行时1. ICE运行时1.4 对象适配器1.4.6 Endpoints(端点)注意:(4)如果要强制对象适配器监听所有网络接口,则可定义端点中的主机名为或*;(5)如果端点中指定了主机名,但是没有指定回环接口,那么回环接口是不会被监听的,必须加入后才能监听回环接口:MyAdapter.Endpoints=tcp h p 9999:tcp h p 9999(6)如果端点中没有指定端口,则对象适配器会使用系统选择的一个端口进行监听(该端口不固定);1. ICE运行时1. ICE运行时1.4
21、 对象适配器1.4.6 Endpoints(端点)发布端点(Published Endpoints ) 对象适配器创建代理对象时,需要发布它的传输端点,但是它不能发布它的物理传输端点;例如,一个服务运行在防火墙后的私有网络内,它的适配器的物理端点使用的是私有网络的地址,如果将物理端点发布在对象适配器创建的代理中,那么公共网络中的客户端是无法使用的。 这种情况下适配器必须在它的代理中发布能够指引客户端通过防火墙的端点。 使用name.PublishedEndpoints配置发布端点; 如果未配置上述属性,则适配器会使用物理端点(注意:除非只有回环接口,否则回环接口不会被发布)例如: MyAdap
22、ter.Endpoints=tcp h p 9999 MyAdapter.PublishedEndpoints=tcp h corpfw p 25000 表示连接在主机名为corpfw端口25000的客户端会被转发到适配器的物理端点上(私有网络上的端点)。1. ICE运行时1. ICE运行时1.4 对象适配器1.4.6 Endpoints(端点)发布端点还可用于多服务负载平衡时: 假设有两个状态无关的服务运行在两个不同的主机上以实现负载平衡。一般情况下客户端使用的代理对象的端点同时包含两个服务的端点,这样Ice运行时可以随机选择一个服务建立连接。 但是,如果客户端调用了服务的
23、某操作后,该操作返回了一个该服务的代理对象。那么,客户端使用这个返回代理对象调用操作时Ice运行时会始终选择返回该代理的服务端(因为返回的代理中只有创建它的服务端端点),无法负载平衡。 这种情况下要负载平衡可以配置服务端适配器的发布端点,让发布端点同时包含两服务:(假设两个服务一个叫sun1,一个叫sun2) 1. ICE运行时1. ICE运行时1.4 对象适配器对于sun1 MyAdapter.Endpoints=tcp h sun1 p 9999 MyAdapter.PublishedEndpoints=tcp h Sun1 p 9999:tcp h Sun2 p 9999对于sun2 M
24、yAdapter.Endpoints=tcp h sun2 p 9999 MyAdapter.PublishedEndpoints=tcp h Sun1 p 9999:tcp h Sun2 p 99991.4.6 Endpoints(端点)刷新端点 主机的网络接口列表可能会动态改变。例如,笔记本电脑从一个无线网络移动到另外的无线网络时。 这时对象适配器提供刷新网络接口列表的方法: local interface ObjectAdapter void refreshPublishedEndpoints(); / ; 注意:刷新时机由应用程序自己决定; 只有那些发布端点中没有配置主机地址或配置的是
25、全部地址(*或)的对象适配器,该刷新才有效。1. ICE运行时1. ICE运行时1.4 对象适配器1.4.6 Endpoints(端点)端点的超时属性 作为防备恶意客户端的手段,建议在物理端点中指定超时时间。 超时会影响那些Ice运行时通常不希望长时间阻塞的任务:向socket写回应消息或等待SSL磋商完成等。如果没有设置超时,那么运行时会无限等待。这样一些恶意客户端就能够大量消耗资源。端点中使用-t参数设置超时MyAdapter.Endpoints=tcp p 9999 t 50001. ICE运行时1. ICE运行时1.4 对象适配器1.4.6 Endpoints(端点)路由
26、器如果对象适配器配置了路由器,那么适配器的发布端点会影响路由器(详见手册42章关于如何使用路由器配置对象适配器)1. ICE运行时1. ICE运行时1.4 对象适配器1.4.7 创建代理 对象适配器接口提供多种方法创建代理对象(不管对象id表示的Servant是否是激活的): Object * ObjectAdapter:createProxy(Identity id);它返回直接代理还是间接代理由对象适配器的配置决定。如果对象适配器是用的适配器id,则返回间接代理;如果对象适配器没有id,那么该接口使用适配器发布端点返回一个直接代理; Object * ObjectAdapter:creat
27、eDirectProxy(Identity id); 该接口直接返回一个直接代理,代理端点为适配器的发布端点;Object * ObjectAdapter:createIndirectProxy(Identity id); 返回一个间接代理。直接代理其内部保存有某个对象的标识,以及它的服务器的运行地址;间接代理其内部保存有某个对象的标识,以及对象适配器名(object adapter name)。1. ICE运行时1. ICE运行时1.4 对象适配器1.4.8 使用多对象适配器 一个典型的服务实现很少需要使用多个对象适配器。如果你正考虑使用多个对象适配器,则建议你考虑是否用到了下列情况:(1)
28、. 你需要一个细粒度的对象访问控制。例如,已可能有一个适配器仅绑定一个安全的端点来限制访问一些管理对象,其它的适配器绑定到非安全端点上用来访问其它对象;(2). 针对不同集合的对象,你需要控制线程池中线程数量。例如:某个特定的适配器上的对象不需要并发处理,而是设置多个适配器,每个适配器有各自的线程池,这样可用于解决死锁;(3). 你需要针对某一组对象能够暂时禁用它上面的新请求。这可以通过设置相应的对象适配器的状态为Holding来完成;(4). 当你在Glacier2中使用一个Ice路由器时能设置不同请求路径时可以考虑使用多适配器; 如果你的应用中没有上述情形,则你无须使用多适配器; 1. I
29、CE运行时1. ICE运行时1.4 对象适配器1.5 对象标识(Object Identity)每一个Ice对象都有如下定义的一个对象标识:module Ice struct Identity string name; string category; ; ; 标识可以用字符串标示:category/name通信器成员函数:string identityToString(Identity id);Identity stringToIdentity(string id);可用于相互转换1. ICE运行时示例:Demo:HelloPtr hello = new HelloI; / Servant/
30、 下面用“hello”字符串作为对象标识adapter-add(hello, communicator()-stringToIdentity(hello);1.6 Ice:Current对象每个传给服务端骨架操作的最后一个参数都是Ice:Current对象;module Ice local dictionary Context; enum OperationMode Normal, Nonmutating, Idempotent ; local struct Current ObjectAdapter adapter; 分派该操作的对象适配器Connection con; 接收该请求的连接信息
31、Identity id; 处理当前请求的对象标识string facet; (参见33章)string operation; 当前调用的操作名OperationMode mode; 调用模式Context ctx; 当前调用上下文(参见手册32.12)int requestId; 请求ID用来关联请求和请求回应; ; 1. ICE运行时例如: virtual void sayHello(:Ice:Int, const :Ice:Current& = :Ice:Current() = 0;1.7 Servant定位器 Servant定位器是一个注册到对象适配器的对象,当到来的请求在ASM
32、中无法找到正确的Servant时,会调用该定位器对象,由定位器对象返回一个正确的Servant来处理这个请求。没有定位器时:(1)每个Ice对象都由一个不同的Servant表示;(2)每个Ice对象对应的Servant必须驻留在内存中; 如果Servant的数量很多时,会面临内存压力问题;使用Servant定位器:允许Servant实例数量小于Ice对象数量;运行时由定位器根据需要实例化Servant。1. ICE运行时1.7 Servant定位器 要实现定位器,你需要继承自Ice:ServantLocator,并实locate,finished,deactivate方法。 如果到来的请求在A
33、SM中找不到Servant,则Ice运行时会掉调用locate方法; locate返回一个Servant,Ice运行时会将请求分派给该Servant,请求完成后,Ice运行时会调finished; 定位器销毁时deactivate会被调用。1. ICE运行时1.7 Servant定位器定位器的线程保证:同步操作Ice运行时保证,调用locate和finished是配对的且在同一线程内的;异步分派的操作Ice运行时不保证调用locate和finished是同一线程;如果在locate和finished中访问了共享数据,则必须加以保护。1. ICE运行时1.7 Servant定位器向对象适配器注册
34、一个定位器:使用对象适配器方法void addServantLocator(ServantLocator locator, string category);进行注册。注意:必须提供category实参,它决定这个定位器要负责的Ice对象标识(那些对象标识与定位器category匹配的Ice对象才会触发该定位器的locate调用)1. ICE运行时1.8 缺省Servants还可以使用缺省Servants来解决Servants量很大的问题。它根据请求对象标识的不同改变其行为。可通过对象适配器方法:void addDefaultServant(Object servant, string cat
35、egory);添加缺省Servant。注意:缺省Servant需要保护共享数据。1. ICE运行时1.9 服务器实现技术1.9.1 渐进初始化如果使用了Servant定位器,locate方法返回的Servant实例只能用于当前请求(Ice运行时不会将该Servant加入ASM)。所以,Servant的初始化是分散到每次请求调用中的,而不是服务启动时(也可以在locate首次实例化了某Servant后将其加入ASM,这样后面的调用请求不再需要初始化该Servant了);内存需求也有所降低,因为只有那些被访问到的Servant才会被实例化。1. ICE运行时1.9 服务端实现技术1.9.2 缺省S
36、ervants针对不同的请求,缺省Servant能充当不同角色。根据访问对象标识改变其行为。例如:我们目前的服务端中使用了类似的实现方式(虽然不是使用的缺省Servant,但只使用了一个Servant对象来处理所有请求)bool CBusClientForRpcServer:RegisterRpcService(const string &strAppName, const CRpcObjectPtr &rpcObject)CRpcObjectAdapterPtr poAdapter = m_poVar-m_poMainAdapter;poAdapter-add(rpcObje
37、ct, m_poVar-m_poRpcCommunicat-stringToIdentity(strAppName);poAdapter-activate();return true;1. ICE运行时1.9 服务端实现技术1.9.3 混合途径及缓存(Hybrid Approaches and Caching)即:一些性能要求较高的Servant可直接加入ASM中,其它不经常访问的对象可通过缺省Servant实现。1. ICE运行时1.9 服务端实现技术1.9.4 Servant逐出器(Servant Evictors)逐出器是维护有servants 缓存的servant 定位器。 只要有请求
38、到达(也就是说, Ice run time 调用了locate),逐出器就在它的缓存中检查,看是否能找到可用于该请求的servant。如果有,它就返回这个已经在缓存中实例化的servant ;否则,它实例化一个servant,并把它增加到缓存中。 缓存是一个按照“最近最少使用”(LRU)顺序维护的缓存:最近最少使用的servant 处在队列的尾部,最近使用最多的servant 处在队列的头部。如果某个servant 被从缓存中返回,或增加到缓存中,它就会从当前的队列位置移到队列头部,也就是说,“最新”的servant 总是在头部,“最老”的servant 总是在尾部。 队列的长度可以配置,并决
39、定会有多少servant 存放在缓存中;如果针对某个Ice 对象的请求在内存中没有对应的servant,且缓存满了,逐出器就会在队尾移除最近最少使用的servant,给要在队头实例化的servant腾出空间。 1. ICE运行时1.9 服务端实现技术1.9.4 Servant逐出器(Servant Evictors)逐出器的实现和实现定位器一样,只是该定位器中需要增加一个“最近最少使用”(LRU)队列来缓存实例化过的Servant。class EvictorBase : public Ice:ServantLocator / ;1. ICE运行时1.10 Ice线程模型Ice天生是一个多线程平
40、台,不存在单线程的Ice服务。你必须考虑并发问题。 例如:请求可能被并发分派。1. ICE运行时1.10.1 线程池介绍每个通信器创建两个线程池:1. 客户端线程池;(响应请求回应、AMI回调)2. 服务端线程池;(分派请求、双向连接回应)缺省情况下,这两个线程池被通信器的所有适配器共享。如果需要,你可以为某个对象适配器配置私有的线程池;如果线程池中线程耗尽,则新的请求会被阻塞; 默认池中线程数为1.1. ICE运行时1.10 ice线程模型1.10.2 配置线程池每个线程池有一个唯一的名字;有下列属性可设置:Name.SizeName.SizemaxName.SizeWarnName.Sta
41、ckSizeName.SeralizeName.ThreadIdleTime 客户端和服务端线程池的名字为: Ice.ThreadPool.Client和Ice.ThreadPool.Server如果要监视线程池活动情况,可打开属性Ice.Trace.ThreadPool属性。 动态线程池:由name.Size、name.Sizemax、name.ThreadIdleTime决定 (Ice运行时会按这些参数配置,动态决定池中的线程数)1. ICE运行时1. ICE运行时1.10 ice线程模型例如,我们的Ice服务配置如下:1.10.3 适配器线程池 缺省情况下对象适配器和通信器是共享线程池的
42、。但是,在某些特殊情况下配置对象适配器自己的线程池也是很有用的: 1. 当对象适配器的并发要求和通信器的并发要求不一致时; 2. 确保对某个适配器的Servants的请求分派有最小数量的线程可用; 使用adapter.ThreadPool属性进行配置:adapter.ThreadPool.Sizeadapter.ThreadPool.SizeMax1. ICE运行时1. ICE运行时1.10 ice线程模型1.10.4 设计考虑不合理的线程池配置可能会导致严重的性能问题。设计应用时可考虑如下一些问题:(1) 只有1个线程的线程池的影响. 一次只有一个消息能被分派。这样做可以不必考虑线程安全问题
43、,但是它消除了可能的并行分派,这在多CPU的系统上将带来性能瓶颈; .一次仅有一个AMI响应可被处理。你必须增加客户端线程池大小以便多个AMI回调能并发处理; .嵌套双向调用将受到限制。单线程的情况下最多只能有1层双向嵌套调用;需要注意:通信器的客户端和服务端线程池缺省的最大线程数是1个,使用时需要注意。1. ICE运行时1. ICE运行时1.10 ice线程模型1.10.4 设计考虑(2) 使用多线程的线程池当配置线程池支持多个线程时也就意味着ICE运行时会并发的分派操作调用以及并发的处理AMI回调。这虽然会增加线程安全问题上的设计考虑,但是它所带来的可伸缩性和更高的吞吐量也是显而易见的。具
44、体线程池最大线程数是多少也是需要精心考虑的。例如,超过实际处理器数量的线程数可增加系统的响应性。但是过多的线程数也会起副作用。建议在真实使用环境下来测试系统最佳的线程数。 1. ICE运行时1. ICE运行时1.10 ice线程模型1.10.4 设计考虑(3) 序列化时的考虑当使用多线程线程池时,线程调度的不确定性会导致调用分派顺序可能和调用到来时的接收顺序不一致。有些应用不允许这种情况,例如一些事物处理服务必须保证顺序。有两种方式可以解决这个问题:1. 使用单线程的线程池;2. 使用Serialize属性(poolname.Serialize)配置多线程的线程池来处理序列化请求。 在客户端避
45、免并发调用也可以避免上述问题,但会降低客户端的性能。 打开Serialize属性会增加处理延迟减小服务吞吐量。如果服务端必须保证客户端请求顺序,一个比较好的做法是序列化配合使用异步分派排队到来的请求,将请求排队放入一个队列,然后由其它线程来执行这些请求。 1. ICE运行时1. ICE运行时1.10 ice线程模型1.10.5 嵌套调用 嵌套调用:一个Ice操作发生在另一个Ice操作的上下文中。 注意:如果有嵌套调用,则需要注意避免潜在的死锁肯能。例如,调用时路径出现环路。 这张图中操作A嵌套双向调用了操作B,但是操作B尝试嵌套回调时发生死锁。因为,通信器缺省最大线程数是1个,所以服务A中仅有
46、的一个线程正忙于等待操作B的调用完成,因此没有线程来处理服务B的回调操作。这时客户端因为服务A阻塞,所以它也被阻塞。 在这种场景下有多种方法可以避免死锁发生: (1)增加服务A的线程池的最大线程数量; (2)使用单向调用; (3)另外再创建一个对象适配器用于回调;(另外的适配器配置有自己的线程池) (4)操作A实现为异步分派和调用: 将操作A实现为AMD方式,调用操作B实现为AMI方式。这样服务A中的线程不用一直 阻塞去等待操作B的完成。 1. ICE运行时1. ICE运行时1.10 ice线程模型1.10.5 嵌套调用是否使用嵌套调用:是否设计成嵌套调用需要考虑一些因素: (1)线程池的配置
47、是否能满足嵌套调用要求; (2)双向连接所带来的复杂性,因此你必须小心处理线程的使用; (3)各通信模块中的同步问题也需要考虑,为了同步所加入的锁也可能导致死锁。所以,在嵌套调用的情况下,跟踪调用路径来避免死锁会变得很复杂。1. ICE运行时1. ICE运行时1.10 ice线程模型1.10.6 向用户线程分派调用 缺省情况下操作调用和AMI回调以及操作分派所使用的线程都是Ice运行时线程池中的线程。这样做很方便,不用考虑线程的创建和销毁。 但是Ice运行时线程数量有限,当运行时线程耗尽后将无法继续接收新的调用和分派。 例如,我们的目前的服务端实现中使用了一个自己的线程池,所有到来的调用请求会
48、先放入一个请求队列中,然后由服务端自己的线程池去处理请求。这样,Ice运行时的线程池中始终有空闲线程可用于接收新的请求。virtual bool Dispatch(const CRpcDispatchResultPtr &pCallback, const std:string &strOperationName,const BYTE_VECTOR &oInStream)GetLogger().debug(Operation %s Dispatch, strOperationName.c_str();bool bOk = RequestHandlerMgr:get_mut
49、able_instance().AddRequest(pCallback, strOperationName, oInStream);if (!bOk)UnknownDispatch(pCallback, strOperationName, oInStream);return bOk;1. ICE运行时1. ICE运行时1.10 ice线程模型1.11 代理的使用及配置(Proxies) 代理对象能够使得远程调用像本地调用一样简单。事实上,处理远程调用只是代理对象的众多职责之一。 代理还封装了连接远程对象所需的足够信息,包括标识、地址信息(传输端点)等。 代理方法还提供了访问配置及连接信息的功
50、能,以及创建新代理对象的功能。代理负责所需的新连接的建立。 代理分成两类: 直接代理其内部保存有某个对象的标识,以及它的服务器的运行地址;(ObjectIdent:tcp h p 9999)间接代理其内部保存有某个对象的标识,以及对象适配器名(object adapter name)(ObjectIdent或ObjectIdentAdapterName)。1. ICE运行时1.11 代理1.11.1 获取代理字符串表示的代理: 通信器的stringToProxy方法可从代理的字符串标识创建一个代理对象: Ice:ObjectPrx p = communicator-string
51、ToProxy(“ident:tcp p 5000”);代理属性: 除了上述硬编码方式表示代理对象,还可通过配置属性将代理外部化。例如,可以定义一个属性包含代理字符串标识: MyApp.Proxy-ident:tcp p 5000可以使用通信器的propertyToProxy方法从配置属性得到代理对象。1. ICE运行时1.11 代理例如: 配置文件中配置了代理 Hello.Proxy=hello:tcp -p 10000通信器初始化时加载了这个该配置文件 initDperties-load(configFile);使用通信器方法propertyToProxy创建代理HelloP
52、rx twoway = HelloPrx:checkedCast( communicator()-propertyToProxy(Hello.Proxy);1.11.1 获取代理通过工厂方法创建代理 代理提供一些方法允许改变已有的代理的某些特性,得到新的代理。因为代理本身是不可变的,工厂方法会返回新的代理对象。 例如: ice_oneway方法返回一个单向调用代理对象。 注意:如果原代理的配置和新代理配置不一样,则返回的是一个新代理对象实例。 checkCast和uncheckedCast方法也可以认为是工厂方法,因为他们也会返回新代理对象。 HelloPrx twoway = HelloPr
53、x:checkedCast(communicator()-propertyToProxy(Hello.Proxy)-ice_twoway()-ice_timeout(-1)-ice_secure(false); if(!twoway) cerr argv0 : invalid proxy ice_oneway(); HelloPrx batchOneway = twoway-ice_batchOneway(); HelloPrx datagram = twoway-ice_datagram(); HelloPrx batchDatagram = twoway-ice_batchDatagram
54、();1. ICE运行时1.11 代理1.11.3 代理的端点 代理传输端点是位于客户侧的并等同于对象适配器的传输端点。代理传输端点标识了同远程对象通信用的协议信息。例如:tcp h p 10000这个端点标示一个远程对象,改对象可通过tcp协议连接,该对象处于主机上,端口10000。代理对象必须至少能获取到一个端点。 直接代理对象可包含1个或多个端点: MyObject:tcp h p 10000:ssl h o 10001如果直接代理不含有-h项,则Ice运行时将使用属性Ice.Default.Host。如果Ice.Default.Host也未定义,则localhost网络接口将被使用。
55、间接代理只有对象标识或还有适配器名,它使用定位服务来动态获取传输端点。 MyObject或MyObjectAdapterName1. ICE运行时1.11 代理1.11.4 端点过滤 代理的配置决定了它的端点如何使用。例如,一个配置为安全通信的代理它的端点必须使用安全协议,如SSL。 如下表中列出了一些工厂方法返回的代理对象其端点必须根据该代理对象的配置来使用。1. ICE运行时1.11 代理1.11.4 端点过滤例如:Ice_secure()返回的代理对象只使用安全协议的端点.如果没有正确协议的端点可用,则连接建立时会收到NoEndpointException异常。 1. ICE运行时1.1
56、1 代理1.11.5 缺省值与覆盖 理解代理是如何受Ice配置属性设置影响的是很重要的。相关属性可分为两类:缺省值和覆盖值(defaults and overrides)。 缺省属性缺省属性 缺省属性影响那些由Ice调用、stringToProxy或propertyToProxy创建的代理对象,不影响工厂方法创建的代理。 覆盖属性覆盖属性 设置覆盖属性将导致Ice运行时忽略与之对应的代理设置而直接使用覆盖属性设置。例如:Ice.Override.Secure=1 指示Ice运行时只使用安全端点,相当于对每个代理调用ice_secure(true)。但是这个属性不会改变已存在的代理的设置,而是指
57、示Ice运行时使用安全端点而不去理会代理自身的安全设置。 1. ICE运行时1.11 代理1.12 Ice:Contextmodule Ice local dictionary Context; 上下文就是一个把串映射到串的词典,或者从概念上说,上下文就是一系列名- 值对。 每当有请求要发往服务器时,这个词典的内容(如果有的话)都会随同请求一起整编,也就是说,如果客户在上下文中放入一些名- 值对,并在发出调用时使用这个上下文,服务器就将能使用客户所发送的这些名- 值对。 上下文提供了一种手段,可以把数量不限的参数从客户发往服务器,而不必在操作的型构中提到这些参数。例如:PersonPrx p
58、= .;Address a = .;Ice:Context ctx;ctxwrite policy = immediate;p-setAddress(a, ctx);/ 在服务端,Current c;Ice:Context:const_iterator i = c.ctx.find(write policy); 1. ICE运行时1.12 Ice:Context注意:通过使用Ice:Context,在处理每一个请求时,它们可以向服务端传入一些上下文信息。上下文的设计用途是传送简单的token (比如事务标识符),你应该只把上下文用于这样的目的,而不要把它用于其他目的。 例如,如果服务端设计上必
59、须接收上下文,但是它是无法强制客户端调用时一定会传入上下文的,如果客户端没有发送上下文信息,服务端可能无法工作或异常。1. ICE运行时1.13 具有超时的代理代理方法Ice:ObjectPrx ice_timeout(Ice:Int t) const;会根据一个已有代理创建一个具有超时的代理,参数t以毫秒为单位,-1表示没有超时。如果在超时代理上调用的操作没有在超时时间内完成,客户端会收到异常。注意:连接的建立和关闭也有超时: ConnectTimeoutException: 连接无法在制定时间内建立; CloseTimeoutException:连接无法在指定时间内关闭。同样支持覆盖属性来
60、设置超时时间: Ice.Override.Timeout Ice.Override.ConnectTimeout(设置了覆盖参数后,代理自身的超时设置会被覆盖)1. ICE运行时1.13具有超时的代理注意: 这些超时是“软”超时,也就是说,它们不是精确的、实时的超时(精确度受制于底层操作系统的能力)。 Ice run time把超时当作是严重的出错:例如,超时会导致客户端的连接关闭。 超时应该被用于防止客户在“服务器发生错误”的情况下无限期地阻塞; 1. ICE运行时1.14 单向调用单向调用客户端发送调用后不关心任何服务端回应,服务端也不会给客户端任何回应,客户端不关心调用是否成功。单向调用(客户端侧) 在客户端,调用的发送是通过把请求写到客户的本地传输缓冲区来完成的;一旦本地传输机制接受了调用,调用就会完成,并把
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高层住房施工安全协议书4篇
- 外聘专家聘用合同范本
- 私人木工施工合同范本
- 房地产配套工程施工合作合同6篇
- 苏州市高二上学期语文期末考试试卷及答案
- 2025年皮肌炎的试题及答案
- 焊工考证题库及答案
- 2025年陕西省建设系统事业单位人员招聘考试题库及答案解析
- 2025年小学试卷试题及答案
- 按摩师考试题及答案
- 北京版小学一至六年级英语词汇
- 2024年新青岛版(六三制)五年级上册科学全册知识点(新修改)
- 《中国近现代史纲要》课件-第一章
- 小学三年级数学口算天天练A4纸直接打印
- TSG+23-2021气瓶安全技术规程
- 酒店代运营合同范本
- 家庭医生签约服务培训
- 农商行年度工作总结
- 环保药剂招商加盟合作协议
- 五年级下册脱式计算练习100道及答案
- 环境的调研报告
评论
0/150
提交评论