在Tiny的并行计算中,引用了远程方法调用工程,就是这里说的TinyRMI,当时在写测试用例的时候,只是在单机进行了测试,一切安好,但是Dawn在使用时,在多机进行试用,结果就出现了问题,最后花了不下一人周,才解决了Dawn发现的问题,最终解决了问题,也发现了RMI中的一些坑。可能有的人已经走过了,有的人如果没有碰到,也可能会掉同样的坑,因此把它成文,以飨读者,避免上同样的当。
此文的形成离不开Dawn的深入测试与分析,在此表示深深感谢!
功能需求
期望对Jdk中的Rmi进行一定的封装提供以下特性:
- 支持本地对象注册与注销
- 支持远程对象注册与注销
- 支持断线重连
由于网络故障,导致连接断开,在网络故障恢复之后,可以继续正常访问
由于RmiServerLocal停止,重新启动后,客户端注册的对象要继续可以正常访问
由于RmiServerRemote停止 ,重新启动后,客户端注册的对象需要重新注册
-
支持对象校验
如果某些对象已经失效,服务器端可以把它从注册表去除,以避免别人拿到失效的对象
接口设计
075159_D7O2_1245989.png (29.68 KB, 下载次数: 0)
下载附件
2015-5-26 22:45 上传
可以看到RmiServer是继承了Serializable和Remote接口的一个接口,它提供了注册对象及取消注册对象的多个方法。当然也提供了一些辅助方法,看起来还是非常简单的。
另外还有一个辅助接口Verifiable,对于加入的远程对象,如果实现了此接口,则可以对其有效性进行验证,如果已经失效,将被自动从注册无中去除。
- /**
- * 是否可验证,实现了此接口的类,可以进行校验
- */
- public interface Verifiable {
- /**
- * 校验,如果校验时不出现异常,就表示是OK的
- *
- * @throws RemoteException
- */
- void verify() throws RemoteException;
- }
复制代码
当然,要加入到RmiServer中,也要有一定的约束,因此设定了接口RemoteObject
- public interface RemoteObject extends Serializable, Remote {
- }
复制代码
好的,至此为止,接口就算设计完了。代码实现
第一版代码实现,偶预想的非常简单,如何获取Registry作为一个抽象方法由子类实现,其它都是针对Registry进行的操作,就放在抽象类中实现,分分钟写好,然后本地测试通过,洋洋自得中,却蒙蒙然不知犯下了严重的错误.....
在单机环境下,测试都是好的,不管是RMI自己的测试用例还是复用它的并行计算工程。
但是Dawn在使用的时候,采用了Linux机器两个物理机进行测试,问题出现了,错误信息如下:
- java.rmi.AccessException: Registry.Registry.bind disallowed; origin / 192.168.xxx.xxx is non-local host
-
复制代码
我们用物理的两台计算机进行测试,也有同样的问题。
于是Baidu、谷歌都用上了,查找了终于找到原因:
Registry只有本地的才可以对注册表进行修改,远程的只能用来查看。
于是把RmiServerLocal作为一个远程对象提供出来,让RmiServerRemote来调用,心想这样总可以了吧??但是还是不行,还是同样的问题。
仔细阅读JavaDoc文档和找到的一些材料,才理解了,这个bind过程只能在RmiServerLocal所在的机器中执行,即使是通过远程服务调用,它还是认为是在RmiServerRemote中调用的......这尼玛的坑爹了,这个RMI这么难用,设计者知道么?
这次改进,远程机注册的时候,只是添加到RmiServerLocal中的一个Queue中,然后在RmiServerLocal所在机器开一个扫描线程,来进行bind,unbind操作,这样总保证是在Local中执行了。
测试一下,确实OK了......还没有高兴半下,Dawn报过来,又出问题了。
Windows作Server,Linux做客户端的时候是OK的,但是Linux只要做服务器端就还是不行。
继续查找原因,看到资料说是因为Linux查找到IP与外部访问的IP不对应导致,需要修改/etc/hosts文件中的127.0.0.1到外部方面的IP地址。
修改之后,问题得到解决。
测试过程
初步跑通之后,接下来就是各种各样的测试及各种各样的问题。
由于采用了异步注册的关系,导致注册时间过后一小段时间才可以访问注册到的对象。
有对象访问冲突问题,等等等等,总之就是测了改,改了测,最后终于修正完毕,终于有一个稳定的可用的版本出现了。
最后,由于原来的设想的代码共用基本上没有复用的价值了,因此RmiServerLocal和RmiServerRemote都是各自的实现,不再有共同的基类。
经验总结
- 测试用例的编写一定要充分覆盖。
- 涉及到网络方面的测试,不能仅在本地测试通过就可以,一定要用真实的环境进行测试。
-
不同的操作系统处理还是有一些不同,不要太迷信Java的一次编写到处使用,事实是到处可以跑,在大多数情况下也是可以正确的跑的,但是有些外部条件不同,可能会导致故障的出现。
关于RMI:
- 如果是客户端仅调用服务器端提供的对象,那么是非常简单的。
-
如果是客户端也要向服务器注册远程对象,那么就需要采用异步的方式,搞一下注册或注销队列。
代码本身不复杂,需要的同学,请自行查看源代码。
https://git.oschina.net/tinyframework/tiny/tree/master/framework/org.tinygroup.rmi
分享到:
相关推荐
在"Lab1-RMI-code_layersmab_rmi_"这个实验中,我们将深入探讨RMI的基本概念、工作原理以及如何创建一个简单的RMI客户端和服务器。 1. **RMI基本概念**:RMI允许一个Java对象在一台机器上执行另一个Java对象的方法...
远程异常是服务器端抛出的异常,会被封装在`java.rmi.RemoteException`或其子类中,传递回客户端。 7. **安全性**:RMI支持基于Java安全模型的安全策略。通过设置权限、签名和证书,可以限制远程对象的访问权限。 ...
Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种分布式计算技术,它允许在不同的Java虚拟机之间进行远程对象的方法...熟练掌握RMI可以帮助你更好地设计和实现高可用、可扩展的分布式系统。
spring rmi 2.5.x版本与3.0.x版本不兼容解决方案
Java Applet和RMI(Remote Method Invocation)是Java平台上的两个核心技术,它们在分布式系统和网络应用程序中扮演着重要角色。本项目结合这两者,实现了跨主机的通信功能,为理解这两种技术的协同工作提供了很好的...
xmemcached1.3.5源码-附带自己写的RMI调用它的JMX服务,使用RMI调用JMX服务的详细过程,完整的eclipse工程,直接导入即可用。还用一些运行截图,很有用。 自己写的例子,类名是BaseExample 和RMITest.
Durham大学的这个教程详细介绍了如何在Java环境中有效地使用RMI,使得不同Java虚拟机(JVM)上的对象可以相互调用方法,跨越网络进行通信,极大地拓展了Java应用的可扩展性和灵活性。 1. **RMI的基本概念** - 远程...
因而在开发网络分布式应用的时候,可以用它自身的机制实现分布式计算,一种基于Java的远程方法调用(RMI)为我们开发企业分布式应用提供了行之有效的解决方案。
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用
jar包,亲测可用