1. 使用IceGrid会话进行资源分配

IceGrid提供了一个资源分配工具,来协调访问IceGrid应用程序的对象和服务端。要分配资源以供独占使用,首先,客户端必须通过使用IceGrid注册表或Glacier2路由器进行身份验证来建立会话,然后,客户端可以保留应用程序指示可分配的对象和服务器。客户端应该在不再需要的时候释放资源,否则,当客户端的会话终止或由于不活动而超时时,IceGrid会回收它。

一个可分配的服务端提供至少一个可分配的对象。当第一个可分配对象被声明时,对应服务端被认为是被分配的,并且直到所有分配的对象被释放才被释放。当服务端由客户端分配时,其他客户端不能分配其对象。

2. 创建一个IceGrid会话

客户端必须先创建一个IceGrid会话,然后才能分配对象。如果你已经配置了Glacier2路由,来进行IceGrid的会话管理器,则客户端的路由会话满足此要求。

在没有Glacier2的情况下,IceGrid客户端调用IceGrid注册表接口createSessioncreateSessionFromSecureConnection来创建一个会话:

module IceGrid 
{
    exception PermissionDeniedException
    {
        string reason;
    }

    interface Session extends Glacier2::Session
    {
        idempotent void keepAlive();
        ...
    }

    interface Registry
    {
        Session* createSession(string userId, string password)
            throws PermissionDeniedException;

        Session* createSessionFromSecureConnection()
            throws PermissionDeniedException;

        idempotent int getSessionTimeout();

        idempotent int getACMTimeout();

        ...
    }
}

createSession方法需要用户名和密码,并且如果客户端有权限创建会话,则返回会话代理。默认情况下,IceGrid不允许创建会话。你必须定义注册表的属性IceGrid.Registry.PermissionsVerifier,然后,使用权限验证对象的代理,通过createSession启用会话创建。

createSessionFromSecureConnection操作不需要用户名和密码,因为它使用SSL连接提供的凭据来认证客户端。与createSession一样,必须通过配置权限验证对象的代理来启用会话创建,以便客户端可以使用createSessionFromSecureConnection创建会话。在这种情况下,属性则是IceGrid.Registry.SSLPermissionsVerifier

要创建会话,客户端通过将知名的代理字符串“IceGrid/Registry”转换为communicator的代理对象来获取注册表代理,将代理向下转换到IceGrid::Registry接口,并调用其中一个方法。以下示例代码演示了如何在C++中执行此操作。该代码在其他语言映射中看起来非常相似。

//C++11
auto base = communicator->stringToProxy("IceGrid/Registry");
auto registry = Ice::checkedCast<IceGrid::RegistryPrx>(base); 
string username = ...; 
string password = ...; 
shared_ptr<IceGrid::SessionPrx> session; 
try
{ 
    session = registry->createSession(username, password); 
}
catch(const IceGrid::PermissionDeniedException& ex)
{ 
    cout << "permission denied:\n" << ex.reason << endl; 
}
//C++98
Ice::ObjectPrx base = communicator->stringToProxy("IceGrid/Registry");
IceGrid::RegistryPrx registry = IceGrid::RegistryPrx::checkedCast(base); 
string username = ...; 
string password = ...; 
IceGrid::SessionPrx session; 
try
{ 
    session = registry->createSession(username, password); 
}
catch(const IceGrid::PermissionDeniedException& ex)
{ 
    cout << "permission denied:\n" << ex.reason << endl; 
}

注册表对象的ID可能会根据它的配置设置而更改。

创建会话后,客户端必须保持活动状态,以防止它过期。你有两个选择让会话保持活着:

  1. 调用Registry::getSessionTimeout,并定期每1(或更少)秒钟调用Session::keepAlive
  2. 调用Registry::getACMTimeout,并在连接上配置ACM设置

我们推荐使用第二种方法,你可以按如下方式执行:

//C++11
int acmTimeout = registry->getACMTimeout();
if(acmTimeout > 0)
{
    auto conn = session->ice_getCachedConnection();
    conn->setACM(acmTimeout, Ice::nullopt, Ice::ACMHeartbeat::HeartbeatAlways);
}
//C++98
int acmTimeout = registry->getACMTimeout();
if(acmTimeout > 0)
{
    Ice::ConnectionPtr conn = session->ice_getCachedConnection();
    conn->setACM(acmTimeout, IceUtil::None, Ice::HeartbeatAlways);
}

在连接上启用心跳,Ice会按照给定的超时值,定期自动发送心跳消息。服务端忽略这些消息,但它们的作用是保持会话活着。

如果会话超时,或者客户端通过调用destroy方法来显式终止会话,则IceGrid会自动释放使用该会话分配的所有对象。

3. 控制IceGrid会话的访问

如上所述,你必须使用至少一种权限验证对象的代理来配置IceGrid注册表,以启用会话创建:

  • IceGrid.Registry.PermissionsVerifier

该属性提供实现了接口Glacier2::PermissionsVerifier对象的代理。定义这个属性允许客户使用createSession创建会话。

  • IceGrid.Registry.SSLPermissionsVerifier

该属性提供实现了接口Glacier2::SSLPermissionsVerifier对象的代理。定义这个属性允许客户使用createSessionFromSecureConnection创建会话。

IceGrid提供了内置权限验证对象:

  • 用于TCP/IP的空权限验证程序。该对象接受任何用户名和密码,只能用于不需要访问控制的安全环境。通过定义以下配置属性,来选择验证对象:
IceGrid.Registry.PermissionsVerifier=<instance-name>/NullPermissionsVerifier

请注意,你必须将正确的实例名称替换为对象ID类别。

  • SSL的空权限验证程序,类似于TCP/IP的权限验证程序。通过定义以下配置属性,来选择验证对象:
IceGrid.Registry.SSLPermissionsVerifier=<instance-name>/NullSSLPermissionsVerifier
  • 基于文件的权限验证程序。此对象在包含username-password对的文件中使用访问控制列表。密码文件的格式与Glacier2密码文件的格式相同。 通过使用密码文件的路径名,定义配置属性IceGrid.Registry.CryptPasswords,来启用验证实现。请注意,如果你使用IceGrid.Registry.PermissionsVerifier指定权限验证者对象的代理,则忽略此属性。

你也可以实现你自己的权限验证器对象

4. 使用IceGrid会话分配对象

客户端使用从createSessioncreateSessionFromSecureConnection返回的会话代理来分配对象。代理支持如下所示的Session接口:

module IceGrid 
{
    exception ObjectNotRegisteredException
    {
        Ice::Identity id;
    }

    exception AllocationException
    {
        string reason;
    }

    exception AllocationTimeoutException extends AllocationException 
    {
    }

    interface Session extends Glacier2::Session 
    {
        idempotent void keepAlive();

        Object* allocateObjectById(Ice::Identity id)
            throws ObjectNotRegisteredException, AllocationException;

        Object* allocateObjectByType(string type)
            throws AllocationException;

        void releaseObject(Ice::Identity id)
            throws ObjectNotRegisteredException, AllocationException;

        idempotent void setAllocationTimeout(int timeout);
    }
}

如前所述,客户端负责通过定期调用keepAlive使会话保持活动状态。

allocateObjectById方法分配并返回给定ID可分配对象的代理。如果给定的ID中没有可分配的对象已经注册,则客户端将收到ObjectNotRegisteredException。如果对象不能分配,客户端会收到AllocationException。分配尝试可能会失败,原因如下:

  • 该对象已被会话分配
  • 该对象由另一个会话分配,在配置的分配超时期限内不可用
  • 回话被销毁了。

allocateObjectByType方法分配并返回用给定类型注册的可分配对象的代理。如果有多个可分配对象已使用给定类型注册了,则注册表将随机选择一个。如果没有给定类型的对象可以分配,客户端会收到AllocationException。分配尝试可能会失败,原因如下:

  • 没有对象与给定的类型注册
  • 给定类型的所有对象都已被分配(通过此会话或其他会话),并且在配置的分配超时期间内没有任何对象可用
  • 回话被销毁了。

releaseObject方法释放会话分配的对象。如果给定的ID中没有可分配的对象注册,客户端会收到ObjectNotRegisteredException;如果对象没有被会话分配,则抛出AllocationException。会话销毁后,IceGrid会自动释放所有分配的对象。

setAllocationTimeout用来配置分配方法的超时。如果客户端调用allocateObjectByIdallocateObjectByType时没有对象可用,则IceGrid会等待指定的超时时间,等待可分配对象可用。如果超时过期,则客户端收到AllocationTimeoutException

5. 使用IceGrid会话分配服务端

客户端不需要明确分配服务端。如果一个服务端是可分配的,IceGrid将隐式地分配给声明服务端为可分配对象中的第一个客户端。同样,当它的所有可分配对象被释放时,IceGrid会释放服务端。

服务端分配在两种情况下很有用:

  • 只有可分配的服务端才能使用会话激活模式,在这种模式下,客户端分配服务端时按需激活服务端,并在释放时停用服务端。
  • 一个可分配的服务端可以用IceSSLGlacier2进行保护,以便其对象只能由分配它的客户端调用。

6. 分配资源的安全考虑

IceGrid的资源分配工具允许客户端协调对对象和服务端的访问,但是不会对客户端调用分配的对象有任何限制;任何具有分配对象的代理的客户端都可以在它上面调用一个方法。IceGrid假定客户端正在相互合作,并且尊重分配语义。

为了防止未经授权的客户端调用分配的对象或服务端上的方法,可以使用IceSSLGlacier2

  • 使用IceSSL,你可以使用属性IceSSL.TrustOnly.ServerIceSSL.TrustOnly.Server.AdapterName来保护对服务端或特定对象适配器的访问。例如,如果使用会话激活模式配置服务器,则可以将IceSSL.TrustOnly属性之一设置为${session.id}变量,该变量在为会话激活服务端时被替换为会话ID。如果IceGrid会话是从安全连接创建的,则会话ID将是与安全连接关联的专有名称,这将有效的限制服务端或通过IceGrid建立回话的客户端的适配器的访问。

  • 使用Glacier2,你可以使用Glacier2过滤机制来保护对已分配对象或已分配服务端的对象适配器的访问。默认情况下,使用Glacier2路由器创建的IceGrid会话会自动访问分配的对象、可分配的对象、某些知名对象以及分配服务端的对象适配器。

7. 部署可分配资源

Allocatable对象使用类似于知名对象描述符的描述符进行注册。Allocatable对象不能被复制,因此只能在对象适配器描述符中指定。

通过设置服务端描述符的allocatable属性,可以将服务端指定为可分配的。

作为一个例子,下面的应用程序定义了一个可分配的服务端和一个可分配的对象:

<icegrid> 
    <application name="Ripper"> 
        <node name="Node1"> 
            <server id="EncoderServer" 
                exe="/opt/ripper/bin/server" 
                activation="on-demand"
                allocatable="true"> 
                <adapter name="EncoderAdapter" id="EncoderAdapter" endpoints="tcp"> 
                    <allocatable identity="EncoderFactory" type="::Ripper::MP3EncoderFactory"/> 
                </adapter> 
            </server> 
        </node> 
    </application>
</icegrid>

8. 在Ripper中使用资源分配

我们可以使用MP3编码器对象工厂的分配工具来协它的访问。首先,我们需要修改描述符来定义一个可分配的对象:

<icegrid> 
    <application name="Ripper"> 
        <server-template id="EncoderServerTemplate"> 
            <parameter name="index"/> 
            <server id="EncoderServer${index}" 
                exe="/opt/ripper/bin/server" 
                activation="on-demand"> 
                <adapter name="EncoderAdapter"  endpoints="tcp">
                    <allocatable identity="EncoderFactory${index}"
                        type="::Ripper::MP3EncoderFactory"/> 
                </adapter> 
            </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>

接下来,客户端需要创建一个会话并分配一个对象工厂:

//C++11
auto obj = session->allocateObjectByType(Ripper::MP3EncoderFactory::ice_staticId());
try
{
    auto encoder = factory->createEncoder(); 
    // 使用编码器编码一个文件
}
catch(const Ice::LocalException& ex) 
{
    // 编码时有问题,我们捕捉这个异常,并释放对象工厂
}
session->releaseObject(obj->ice_getIdentity());
//C++98
Ice::ObjectPrx obj = session->allocateObjectByType(Ripper::MP3EncoderFactory::ice_staticId());
try
{
    Ripper::MP3EncoderPrx encoder = factory->createEncoder(); 
    // 使用编码器编码一个文件
}
catch(const Ice::LocalException& ex) 
{
    // 编码时有问题,我们捕捉这个异常,并释放对象工厂
}
session->releaseObject(obj->ice_getIdentity());

当不再需要的时候,释放一个分配的对象是非常重要的,这样其他客户端就可以使用它。如果你忘记释放一个对象,它将保持分配,直到会话被销毁。

Copyright © github.com/weiofcn 2017 all right reserved,powered by GitbookLast modified time: 2017-12-21 13:30:06

results matching ""

    No results matching ""