摘要:
通过使用JDK 1.3中引入的RMI和Proxy API,本篇文章讨论了一种答应一台或多台servlet服务器在一台或多台对话服务器上维护对话信息的技术,采用这种技术后,单一点故障就不会再出现了。
假如系统中有一台或多台servlet服务器,对话信息只存在于运行着JVM的一台servlet服务器上,而不会被传输给其他servlet服务器。假如该servlet服务器当机或因为维护而被关机,任何保存在对话中的信息都会丢失。假如一个系统中有多台servlet服务器,一个带有对话的用户需要访问对话中的任何信息,都需要被重新定向到同一台servlet服务器。曾经有专家建议采用关系数据库保存所有的对话信息,但这仍然存在单一点故障的危险,那就是运行关系数据库的服务器。而且假如数据库出了故障,所有的servlet服务器就都不能再访问对话信息了。另外,在数据库中保存可串行化的对象在有些数据库中是比较难以实现的。
多服务器对话治理的另一个可能的途径是利用JavaSpaces API来维护对话对象中的记录。当然,假如运行JavASPaces的服务器由于维护或故障而被关机,也会丢失所有的对话信息,我们再一次碰到了单一点故障的问题。
要实现带有N个节点的分布式对话服务器,我们必须解决如下的三个问题:
━━如何建立一个库来存贮对话信息。
━━如何对分布式对话信息存贮库进行同步。
━━在一个对话信息存贮库脱离网络后,如何使该服务器从下一个对话信息存贮库中访问对话信息。
Mnemosyne的简介
我们用来存贮对话信息的库是Mnemosyne界面的执行。执行Mnemosyne的对象负责治理对话信息存贮库中的所有对象,任何试图写、访问或删除库中对象的对象都必须调用Mnemosyne的相应的方法来实现相应的操作。
一个对象要存贮在Mnemosyne,就必须执行Memory界面,该界面定义了equalsMemory()操作来探测二个内存对象是否相同,这就使 Mnemosyne判定出应当把哪个对象返回给read要求或take要求。Memory界面也可以进行串行化扩充,以便我们可以用RMI在网络上传输该对象。
Mnemosyne使用三种界面表达其状态。
1、CommonContext界面存贮Mnemosyne的全部信息。每个Mnemosyne都有一个CommonContext对象的实例,以便read、write、take Memory对象时在各个方法之间进行同步。在write或者take说Memory对象时,CommonContext对象既定义“silent”方法也定义“loud”方法,当在不进行事件通知的情况下添加对象时,就会用到“silent”方法。例如,当Mnemosyne对象接收到WriteRemoteEvent(向一个远程Mnemosyne对象写对象的告示。)事件后,假如它也希望向CommonContext对象写另一个对象,它就无需通知其他的远程CommonContext对象,最初的Mnemosyne已经通知了它们,因此这种写是通过调用CommonContext对象的silentWrite()方法“静静静”地完成的。而“loud”方法则在有对象第一次被添加时将这一事件的具体信息通知所有被调用的监听对象。
2、Transaction对象用于在read、write、take Memory对象时进行分布式事务处理,这意味在Mnemosyne对象上可能会有多步骤的操作。
3、TransactionContext界面治理分布式事务,使得系统可以中止或提交一个事务。
保持Mnemosynes的同步是通过synchronize()和notify()这二个由 Mnemosyne定义的方法完成的。synchronize()可以使一个本地的Mnemosyne与其他Mnemosyne的Vector保持同步(这些Mnemosyne可以是本地的或远程的,为简明起见,我们假定它们是远程的。)下面是synchronize()的一个例子:
public void synchronize(Vector Mnemosynes)
throws RemoteException, TransactionException
{
file:// MatchAllMemory对象是一个有效类
file://对任何二个Memory对象进行比较
MatchAllMemory matchAllMemory = new MatchAllMemory();
file:// 从Primary中获得所有Memory
Mnemosyne Mnemosyne = (Mnemosyne) Mnemosynes.firstElement();
Vector allMemories = Mnemosyne.readAll(matchAllMemory,null);
commonContext.silentWriteAll(allMemories);
// 注册进行发送、接收事件
Enumeration enumeration = Mnemosynes.elements();
while(enumeration.hasMoreElements())
{
Mnemosyne nextMnemosyne = (Mnemosyne) enumeration.nextElement();
file://注册接收通知
nextMnemosyne.addTakeRemoteEventListener(this, matchAllMemory);
nextMnemosyne.addWriteRemoteEventListener(this, matchAllMemory);
file:// 注册发送通知
addTakeRemoteEventListener(nextMnemosyne, matchAllMemory);
addWriteRemoteEventListener(nextMnemosyne, matchAllMemory);
}
// ...
}
本地的Mnemosyne对象读取Vector中第一个Mnemosyne对象的所有Memory对象,并采用“silent”方法将它们写到其CommonContext对象中。然后,本地Mnemosyne将自己作为TakeRemoteEventListener和WriteRemoteListener添加到所有的远程Mnemosyne中,这就意味着任何对远程Mnemosynes的take或read操作都将调用本地Mnemosyne的notify()方法。最后,本地Mnemosyne将远程Mnemosyne添加到其TakeRemoteEventListeners和WriteRemoteListeners队列中,确保对本地Mnemosyne的write或take操作都会通知远程Mnemosyne。