IONA Orbix2000 Session Management
By chengxuwen
mailto:[email protected]
http://www.proinfo.com.cn
目录
5.2.2 代码实现(LeaseCallbackImpl类)
5.3 用IT_Leasing::Current
跟踪客户端Session
5.3.2 代码实现(PersonFactoryImpl类)
5.5.3 本例子的完全配置(%itadmin show session_management)
分布式系统与其它软件系统一样,运行时难免会出现一些错误。但同时分布式环境下的引起的错误往往比独立系统复杂很多,因为在分布式系统中,任何一个组件的失败都会潜在的导致整个系统的瘫痪。而资源的服务者与使用者往往身处独立的进程甚至主机中,资源使用者在失败前往往来不及宣告放弃使用资源便告终终止,导致正确运行的服务器中还留有不能被释放的资源。在Orbix2k中有多种方式可以实现服务端资源的回收,主要通过Servant Manager(包括Servant Activator,Servant Locator)实现,另外一种更为方便的方式就是本文中将要讲到的租借模式(Leasing Model)。
2. Orbix2k租借模式框架
2.1 概述
Orbix2k中把租借做为一个插件,通过检查客户端状况来管理服务端被客户端使用的资源。Orbix2k把这整套体系叫租借框架。当客户端启动时,它获得一个租借,然后定时续借。当客户端终止时,它会自动释放该租借。如果客户端崩溃了,它已来不及释放这个租借,这时服务端会在稍后检查到租借已过期。这样,无论客户端是正常还是非正常关闭都会被检查到。
2.2 什么叫Session Managemant
当客户端终止时,如何同时清除在服务端的客户端使用的资源,这是一个在CORBA应用中常常会遇到的问题。在服务端,基于Session的应用程序会分配给客户端请求的资源。为了避免服务端资源的过度膨胀,有必要建立一种检测客户端连接状况的机制。但是CORBA标准本身并没有提出统一的方法。
2.3 Orbix2k中租借的设计原则
Orbix2k中租借模式的设计满足如下特征:
l 客户端零影响
l IDL接口零影响
l 容易实现
l 与CORBA标准兼容
l 完全可配置
2.4 服务端动作
动作序列 |
描述 |
1 |
当服务端启动时,自动调用租借插件 |
2 |
初始化时,服务端公布租借,并将一个LeaseCallback对象绑定到名字服务中 |
3 |
服务端导出对象引用(IOR)时,租借插件自动把租借信息加到IOR中,当然这并不与CORBA标准冲突 |
2.5 客户端动作
动作序列 |
描述 |
1 |
同服务端一样,当客户端启动时,它自动加载租借插件 |
2 |
插件检查客户端将要使用的IOR,看是否有租借信息,如果有,则插件开始一个与公布这个IOR的服务端对应的session |
3 |
插件自动更新租借信息(续借) |
4 |
客户端关闭的两种情况: 正常关闭,插件自动释放租借信息 非正常关闭,服务端插件会检查到客户端没有再续借,于是,租借过期,服务端清除该客户端使用的资源 |
下面如图表示整个过程:
图一 客户端得到租借
客户端初始始化时开始租借插件:
客户端租借插件从名字服务中获得IT_Leasing::LeaseCallback对象引用
调用LeaseCallback对象的acquire_lease( ),客户端租借插件开始一个Session
图二 客户端续借
客户端定期续借,其中的时间间隔由配置量plugins:lease_ping_time决定。
图三 客户端关闭
客户端正常关闭,租借插件自动调用lease_release( )结束Session.
客户端非正常关闭,服务端的租借插件调用LeaseCallback对象的lease_expired( )以释放客户端使用的资源。这个调用的发生由配置量plugins:lease_reap_time决定。
//IDL
module LeaseTest{
exception PersonAlreadyExists { };
interface Person {
string name( );
};
interface PersonFactory {
Person create_person(in string name) raises (PersonAlreadyExists);
};
};
3.2 本例的意图
本例主要说明无论客户端创建多少个Person对象,无论以何种方式终止运行,服务端总会知道,并最终释放已无用的Person对象。这样,服务端保持内存的”干净”。
3.3客户端与服务端的交互
序列 |
描述 |
1 |
客户端调用create_person( )创建Person对象 |
2 |
客户端终止时,先前在服务端被创建的对象就不再需要保留在内存中,然后被释放 |
4.1 准备工作
客户端租借插件会不断的调用resolve( )从名字服务得到租借对象引用。因此,在客户端运行前,需要正确配置Locator,Activator和名字服务。
4.2 如何使用插件
在客户端使用插件唯一需要做的就是正确的将插件的信息加到配置库中。
4.3 配置量
要使用客户端的插件,下面这些变量需要配置:
表一 客户端使用的配置量
配置量 |
作用 |
plugins:lease:shlib_name |
插件对应的库名 |
Orb_plugins |
客户端启动时需要加载的插件列表 |
Binding:client_binding_list |
指定参与请求处理过程的插件 |
4.4 配置举例
#Orbix 2000 Configuration File
plugins:lease:shlib_name=”it_lease”;
orb_plugins=[“local_log_stream”,”lease”,”iiop_profile”,”giop”,”iiop”];
binding:client_binding_list=[“POA_Coloc”,”LEASE+GIOP+IIOP”,”GIOP+IIOP”];
5. 服务端: 使用租借插件
//IDL
module IT_Leasing
{
…
interface LeaseCallback
{
LeaseID acquire_lease( ) raise ( CouldNotAcquireLease);
void lease_expired(in LeaseID lease_id);
void lease_released(in LeaseID lease_id);
void renew_lease(in LeaseID lease_id) raises(LeaseHashExpired);
};
local interface ServerLeaseAgent
{
void advertise_lease(in LeaseCallback lease_callback) raises(CouldNotAdvertiseLease);
LeaseID manufacture_lease_id();
void withdraw_lease();
void lease_acquired(in LeaseID leaseid);
void lease_released(in LeaseID lease_id);
};
local interface Current : CORBA::Current
{
exception NoContext{ };
LeaseID get_lease_id( ) raise (NoContext);
};
…
};
LeaseCallback Interface : 服务端程序需实现IT_Leasing::LeaseCallback接口,用于处理租借插件发出的有关的事件。例如,当一个租借过期时,插件调用IT_Leasing::LeaseCallback::lease_expired()。
Server Lease Agent Interface :ServerLeaseAgent接口的实现由租借插件提供。服务程序通过调用ServerLeaseAgent Interface定义的操作与租借插件通讯。比如,服务程序调用IT_Leasing::ServerLeaseAgent::advertise_lease()初始化租借插件。
Current Interface :服务端用于获取哪些资源正与租借相关联的信息。或者说,它是用于服务端保持创建的资源与正在使用这些资源的客户端的关联关系。
具体过程是这样的:服务端要得到是哪个租借客户调用了某个操作,需要从IT_Leasing:Current对象中获取租借信息,而IT_Leasing.Current是从CORBA::Current中继承过来的,CORBA:Current的定义就是用于获取CORBA调用中的元信息。得到IT_Leasing:Current对象后,就可以调用get_lease_id()得到与调用相关的租借ID(lease ID)。
租借服务端实现的步骤:
步骤 |
动作 |
1 |
实现LeaseCallback接口 |
2 |
用IT_Leasing::Current 跟踪客户端Session |
3 |
发布租借 |
4 |
配置服务端的插件 |
5.2实现LeaseCallback接口
5.2.1 对象的实例
下面的两个对象实例会被LeaseCallbackImpl用到:
IT_Leasing::ServerLeaseAgent的对象引用。它用于与租借插件通讯 |
|
PersonFactoryImpl对象指针。用于创建新的Person对象 |
5.2.2 代码实现(LeaseCallbackImpl类)
extern IT_Leasing::ServerLeaseAgent_var leaseObj;//指向主程序(server.cxx/h)
…
// acquire_lease() -- Implements IDL operation
// "IT_Leasing::LeaseCallback::acquire_lease".
//
char*
LeaseCallbackImpl::acquire_lease()
IT_THROW_DECL((
CORBA::SystemException,
IT_Leasing::CouldNotAcquireLease
))
{
CORBA::String_var new_lease = leaseObj->manufacture_lease_id();
// inform the plugin that it should monitor the lifecycle
// and status of this new lease
//
leaseObj->lease_acquired(new_lease);
cout << "Acquire lease was called! Returning: " << new_lease << endl;
return new_lease._retn();
}
// lease_expired() -- Implements IDL operation
// "IT_Leasing::LeaseCallback::lease_expired".
//
// This method is called by the plugin when a particular
// lease has expired, giving the server a chance to evict
// the resources relevant to that lease. Here, we delegate
// that responsibility to the PersonFactory. Any servants
// relevant to that lease are subsequently evicted.
void
LeaseCallbackImpl::lease_expired(
const char* lease_id
) IT_THROW_DECL((
CORBA::SystemException
))
{
m_factory->owner_has_gone_away(lease_id);
}
// lease_released() -- Implements IDL operation
// "IT_Leasing::LeaseCallback::lease_released".
//
// This method is called by leasing clients when they shut
// down gracefully.
void
LeaseCallbackImpl::lease_released(
const char* lease_id
) IT_THROW_DECL((
CORBA::SystemException
))
{
cout << "The lease: " << lease_id;
cout << " was explicitly released by its client." << endl;
// Tell the plugin to stop monitoring the lifecycle
// of this lease
leaseObj->lease_released(lease_id);
m_factory->owner_has_gone_away(lease_id);
}
// renew_lease() -- Implements IDL operation
// "IT_Leasing::LeaseCallback::renew_lease".
//
void
LeaseCallbackImpl::renew_lease(
const char* lease_id
) IT_THROW_DECL((
CORBA::SystemException,
IT_Leasing::LeaseHasExpired
))
{
cout << "renew_lease() has been called for lease: " << lease_id << endl;
// Nothing to do, since the plugin has already intercepted
// this request and knows that the lease has been renewed.
}
5.3 用IT_Leasing::Current 跟踪客户端Session
5.3.1 概述
服务端通过IT_Leasing::Current接口跟踪每个客户端和它关联的资源。在本例中,资源就是Person对象(它是由LeaseTest::PersonFacrory接口创建)。每一个新创建的Person对象总是的当前客户端关联。
本例中,当前客户端session由当前的租借ID来标识。
5.3.2 代码实现(PersonFactoryImpl类)
…
// create_person() -- Implements IDL operation
//"LeaseTest::PersonFactory::create_person".
LeaseTest::Person_ptr
PersonFactoryImpl::create_person(
const char* name
) IT_THROW_DECL((
CORBA::SystemException,
LeaseTest::PersonAlreadyExists
))
{
LeaseTest::Person_var result = LeaseTest::Person::_nil();
try
{
cout << "LeaseTest::create_person(\"" << name << "\");" << endl;
/////////////////////////////////////////////////////////////////////////
// Now we attempt to determine if this method was called by
// a leasing client. If so, the appropriate LeaseID for this
// invocation will be available in the LeaseCurrent object.
//
CORBA::String_var owner = CORBA::string_dup("<unknown>");
try
{
CORBA::Object_var objref =
global_orb->resolve_initial_references("LeaseCurrent");
if (!CORBA::is_nil(objref))
{
IT_Leasing::Current_var current =
IT_Leasing::Current::_narrow(objref);
if (!CORBA::is_nil(current))
{
owner = current->get_lease_id();
}
}
}
catch (...)
{
cerr << "An unknown exception occurred while getting ServiceContext data." << endl;
}
/////////////////////////////////////////////////////////////////////////
// Create a new Person servant and activate it
//
PersonImpl* newPersonServant;
PortableServer::ObjectId_var oid;
CORBA::Object_var tmp_ref;
{
IT_Locker <IT_Mutex> lock(m_mutex);
// check for Person existence within this process
if (person_is_alive(name))
{
cout << "Person already exists!" << endl;
throw LeaseTest::PersonAlreadyExists();
}
else
{
// Person does not exist, so it is created and
// stored with the others, indexed by its name
//
newPersonServant = new PersonImpl(
name, owner
);
oid = m_poa->activate_object(newPersonServant);
tmp_ref = m_poa->id_to_reference(oid);
result = LeaseTest::Person::_narrow(tmp_ref);
assert(!CORBA::is_nil(result));
// store the new servant with the others
//
IT_String temp_string(name);
m_People[temp_string] = newPersonServant;
}
}
dump_people_to_screen();
}
catch (...)
{
cerr << "Unknown exception within create_person()" << endl;
}
return result._retn();
}
void
PersonFactoryImpl::owner_has_gone_away(
const char* owner
)
{
// Iterate through the people map and evict any people
// who were created by 'owner'.
//
IT_Locker <IT_Mutex> lock(m_mutex);
IT_String current_name;
People::iterator theIter = m_People.begin();
while (theIter != m_People.end())
{
current_name = (*theIter).second->owner();
if (current_name == owner)
{
// deactivate the servant before deleting it
//
PortableServer::ObjectId_var oid =
m_poa->servant_to_id((*theIter).second);
// deactivate the servant with the corresponding id on the POA
m_poa->deactivate_object(oid);
cout << "Deleting: " << (*theIter).first << endl;
delete (*theIter).second;
m_People.erase(theIter);
theIter = m_People.begin(); // iterator is invalidated
continue;
}
theIter++;
}
dump_people_to_screen();
}
5.4 发布租借
5.4.1 前期准备
由于LeaseCallback对象引用需要发布到Naming Service中。因此,在运行前需要正确配置Orbix2k的Locator,Activator Daemon以及Naming Serices并运行。
5.4.2 在哪儿发布
租借的发布做为一个初始功能,它应该放在main()中。并且在ORB::run()或ORB::perform_work()前执行完成。
5.4.3 代码实现(main()函数)
//C++
…
int
main(int argc,char **argc)
{
…
PersonFactoryImpl* the_PersonFactoryServant;
LeaseCallbackImpl* the_LeaseCallbackServant;
…
the_LeaseCallbackServant = new
LeaseCallbackImpl(the_PersonFactoryServant);
oid = my_poa->activate_object(the_LeaseCallbackServant);
tmp_ref = my_poa->id_to_reference(oid);
IT_Leasing::LeaseCallback_var the_LeaseCallbackObject = IT_Leasing::LeaseCallback::_narrow(tmp_ref);
// Contact the lease plugin and advertise a lease
try
{
tmp_ref = global_orb->resolve_initial_references("IT_ServerLeaseAgent");
leaseObj = IT_Leasing::ServerLeaseAgent::_narrow(tmp_ref);
leaseObj->advertise_lease(
the_LeaseCallbackObject
);
}
catch (CORBA::Exception &e)
{
cerr << "Error advertising lease: " << e << endl;
cerr << "Continuing without leasing." << endl;
}
…
}
…
5.5 配置服务端插件
5.5.1 概述
服务端配置变量用于初始化服务端插件并定制其行为。一部分变量被加进对象引用(IOR)中用于与客户端通讯。
5.5.2 配置变量
binding:server_binding_list |
用于指定将LEASE 拦截器加载到服务端 |
plugins:lease:lease_name_to_advertise |
绑定到Naming Service上的LeaseCallback对象名。该名字在每个服务程序中必须唯一 |
plugins:lease:lease_ping_time |
指定客户端续借的时间间隔 |
plugins:lease:lease_reap_time |
如果客户端在lease_reap_time时间间隔内没有续借,服务程序将会释放与对应客户端关联的资源 |
5.5.3 本例子的完全配置(%itadmin show session_management)
session_management
{
binding:client_binding_list = POA_Coloc, LEASE+GIOP+IIOP, GIOP+IIOP
binding:server_binding_list = LEASE,
plugins:lease:shlib_name = "it_lease"
plugins:lease:allow_advertisement_overwrites = true
event_log:filters = IT_LEASE=*
orb_plugins = local_log_stream, lease, iiop_profile, giop, iiop
server1
{
plugins:lease:lease_ping_time = 10000
plugins:lease:lease_reap_time = 20000
plugins:lease:lease_name_to_advertise = "PersonFactorySrv1"
}
server2
{
plugins:lease:lease_ping_time = 20000
plugins:lease:lease_reap_time = 40000
plugins:lease:lease_name_to_advertise = "PersonFactorySrv2"
}
}
1. IONA Technologies corporation, IONA Orbix 2000 Session Management Guide, C++ Edition
2. 王维汉,邸瑞华著,通用CORBA服务器资源回收框架研究
3. Prashant Jain, Evictor