1. 对象适配器复制
作为Ice定位服务的实现,IceGrid支持对象适配器复制。应用程序使用描述符定义它的副本组和它参与对象的适配器,并且IceGrid会自动生成服务端配置。
2. 部署副本组
定义副本组的描述符可以有选择地声明已知对象,也可以配置组以确定定位请求期间的行为。请看这个例子:
<icegrid>
<application name="ReplicaApp">
<replica-group id="ReplicatedAdapter">
<object identity="TheObject" type="::Demo::ObjectType"/>
</replica-group>
<node name="Node">
<server id="ReplicaServer" activation="on-demand" exe="/opt/replica/bin/server">
<adapter name="TheAdapter" endpoints="default" replica-group="ReplicatedAdapter"/>
</server>
</node>
</application>
</icegrid>
适配器的描述符声明自己是副本组ReplicatedAdapter
的成员,但该副本组必须之前已经通过副本组描述符创建。
副本组ReplicatedAdapter
声明一个已知对象,以便TheObject
形式的间接代理相当于间接代理TheObject@ReplicatedAdapter
。由于这个例子只在副本组中定义了一个适配器,因此代理TheObject
也等同于TheObject@TheAdapter
。
3. 副本组成员资格
对象适配器通过在适配器的ReplicaGroupId
配置属性中指定组ID来加入副本组。在IceGrid描述符中标识对象适配器的副本组,会导致该节点在其为服务端生成的配置文件中包含等效的ReplicaGroupId
属性。
默认情况下,IceGrid注册表要求静态定义副本组的成员资格。为标识副本组的对象适配器创建描述符时,注册表将该适配器添加到组的有效成员列表。在适配器激活过程中,当它向注册表中描述它的端点时,同时声明副本组中成员身份的适配器将根据注册表的内部列表进行验证。
在正确配置的IceGrid应用程序中,这个活动没有发生,但是在某些情况下验证可能会失败。例如,如果在不通知注册表的情况下更改适配器的ID,则适配器激活将失败,比如手动修改由节点生成的服务器配置文件。
当IceGrid注册表完全作为位置服务使用时,激活也可能失败,在这种情况下,描述符还没有被创建,因此注册表里面还没有复制组或其成员的信息。在这种情况下,适配器激活会导致服务端接收NotRegisteredException
,除非注册表配置为允许动态注册,你可以通过定义以下属性来执行动态注册:
IceGrid.Registry.DynamicRegistration=1
通过这种配置,只要适配器里面声明了成员身份,就会隐式创建副本组,并允许任何适配器参与。
使用动态注册会经常导致注册表中废弃的副本组和适配器累积。IceGrid管理工具允许你检查和清理注册表的状态。
4. 在Ripper中使用副本组
复制完美的适合Ripper。编码器工厂对象的集合应该被视为一个逻辑对象,复制使这成为可能。
4.1. 将副本组添加到Ripper部署
添加副本组描述符到应用程序很直接:
<icegrid>
<application name="Ripper">
<replica-group id="EncoderAdapters">
<object identity="EncoderFactory" 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>
新的描述符添加名为EncoderAdapters
的副本组,并通过IDEncoderFactory
注册一个已知对象。服务端模板中的适配器描述符已更改为在副本组中声明其成员资格。
4.2. 在Ripper客户端中使用副本组
与展示查询知名对象的示例相比,我们客户端的新版本变得更加简单:
//C++11
auto obj = communicator->stringToProxy("EncoderFactory");
auto factory = Ice::checkedCast<Ripper::MP3EncoderFactoryPrx>(obj);
auto encoder = factory->createEncoder();
//C++98
Ice::ObjectPrx obj = communicator->stringToProxy("EncoderFactory");
Ripper::MP3EncoderFactoryPrx factory = Ripper::MP3EncoderFactoryPrx::checkedCast(obj);
Ripper::MP3EncoderPrx encoder = factory->createEncoder();
客户端不再需要使用IceGrid::Query
接口,而只需创建一个知名对象的代理,并让Ice运行时与位置服务透明地交互。为了响应EncoderFactory
的定位请求,注册表返回包含两个对象适配器端点的代理。客户端的Ice运行时随机选择一个端点,这意味着我们现在已经失去了一些功能,与之前选择端点时考虑系统负载的例子相比。在讨论负载均衡时,我们将学习如何纠正这种情况。