分布式计算在企业应用程序开发世界中变得越来越重要。 如今,开发人员不断需要解决以下问题:如何通过将应用程序扩展到单个节点之外来增强可伸缩性? 如何保证高可用性,消除单点故障并确保满足客户的SLA?
对于许多开发人员而言,解决该问题的最自然的方法是将体系结构分为在不同服务器之间分布的组件或服务组。 尽管这并不奇怪,但考虑到大多数开发人员所拥有的CORBA,EJB,COM和RMI的传统,如果您决定走这条路,那么您会遇到很多麻烦。 在大多数情况下,这样做是不值得的,它会给您带来更多无法解决的问题。 ”
另一方面,分布式计算和Java自然地结合在一起。 作为自下而上设计的第一种语言,考虑了网络,Java使计算机之间的协作变得非常容易。 如果考虑一下,即使在浏览器中运行的最简单的applet也是分布式应用程序。 运行浏览器的客户端下载并执行其他系统提供的代码。 但是,如果没有Java的可移植性和安全性保证,即使是这个简单的applet也将无法实现:applet可以在任何平台上运行,并且不能破坏其主机。
cajo项目是一个小型图书馆,可实现强大的动态多计算机协作。 它非常易于使用,但性能无与伦比。 它是一个独特的“嵌入式”分布式计算框架:这意味着它对您的应用程序没有任何结构上的要求,也没有对源代码进行更改。 它允许多个远程JVM作为一个无缝地协同工作。
项目所有者约翰·凯瑟琳诺声称“山上之王! ;-)”并挑战所有愿意证明Java中存在与cajo同样灵活和一样快的分布式计算框架的人 。
说实话,我个人对约翰的话深信不疑。 我坚信如果您让我逐步介绍此客户端-服务器示例,您也将如此。 您会惊讶cajo框架多么简单和灵活:
Server.java
import gnu.cajo.Cajo; // The cajo implementation of the Grailpublic class Server {public static class Test { // remotely callable classes must be public// though not necessarily declared in the same classprivate final String greeting;// no silly requirement to have no-arg constructorspublic Test(String greeting) { this.greeting = greeting; }// all public methods, instance or static, will be remotely callablepublic String foo(Object bar, int count) {System.out.println("foo called w/ " + bar + ' ' + count + " count");return greeting;}public Boolean bar(int count) {System.out.println("bar called w/ " + count + " count");return Boolean.TRUE;}public boolean baz() {System.out.println("baz called");return true;}public String other() { // functionality not needed by the test clientreturn "This is extra stuff";}} // arguments and return objects can be custom or common to server and clientpublic static void main(String args[]) throws Exception { // unit testCajo cajo = new Cajo(0);System.out.println("Server running");cajo.export(new Test("Thanks"));}
}
通过以下方式进行编译:
javac -cp cajo.jar;. Server.java
通过以下方式执行:
java -cp cajo.jar;. Server
如您所见,只有2个命令:
Cajo cajo = new Cajo(0);
cajo.export(new Test("Thanks"));
我们可以将任何POJO(普通的Java旧对象)公开为分布式服务!
现在是Client.java
import gnu.cajo.Cajo;import java.rmi.RemoteException; // caused by network related errorsinterface SuperSet { // client method sets need not be publicvoid baz() throws RemoteException;
} // declaring RemoteException is optional, but a nice reminderinterface ClientSet extends SuperSet {boolean bar(Integer quantum) throws RemoteException;Object foo(String barbaz, int foobar) throws RemoteException;
} // the order of the client method set does not matterpublic class Client {public static void main(String args[]) throws Exception { // unit testCajo cajo = new Cajo(0);if (args.length > 0) { // either approach must work...int port = args.length > 1 ? Integer.parseInt(args[1]) : 1198;cajo.register(args[0], port);// find server by registry address & port, or...} else Thread.currentThread().sleep(100); // allow some discovery timeObject refs[] = cajo.lookup(ClientSet.class);if (refs.length > 0) { // compatible server objects foundSystem.out.println("Found " + refs.length);ClientSet cs = (ClientSet)cajo.proxy(refs[0], ClientSet.class);cs.baz();System.out.println(cs.bar(new Integer(77)));System.out.println(cs.foo(null, 99));} else System.out.println("No server objects found");System.exit(0); // nothing else left to do, so we can shut down}
}
通过以下方式进行编译:
javac -cp cajo.jar;. Client.java
通过以下方式执行:
java -cp cajo.jar;. Client
客户端可以通过提供服务器地址和端口(如果有)或使用多播来查找服务器对象。 为了找到合适的服务器对象,使用“ 动态客户端子类型 ”。 对于所有不知道“ 动态客户端子类型化 ”代表什么的人,John Catherino在其相关博客文章中解释道:
“服务对象通常会实现大型的,丰富的接口。 有时,服务对象实现多个接口,将其功能分组为不同的逻辑问题。 通常,客户端只需要使用接口的一小部分即可。 或一些逻辑分组接口中的某些方法来满足其自身的需求。
客户端从服务对象定义的接口定义其自己的接口的能力在Java中称为子类型化。 (与子类形成对比)但是,与常规Java子类型不同; 动态客户端子类型化意味着创建一个完全不同的界面。 使此子类型成为动态的原因在于,它可以与原始的未经修改的服务对象一起使用。
对于客户端的复杂性管理,这可能是一种非常有效的技术。”
真的不是很酷吗??? 我们只需要定义客户端“需要”使用的接口并找到符合客户端规范的适当服务器对象。 从我们的示例中派生出以下命令即可完成此任务:
Object refs[] = cajo.lookup(ClientSet.class);
最后但并非最不重要的一点是,我们可以通过发出以下命令来创建服务器对象的客户端“代理”,并像普通的本地对象引用一样远程调用其方法:
ClientSet cs = (ClientSet)cajo.proxy(refs[0], ClientSet.class);
而已。 这些允许在分布式JVM之间实现完全的互操作性。 没有比这更容易的了。
就性能而言,我对提供的示例进行了一些初步测试,并在以下系统上获得了12000 TPS的平均分数:
Sony Vaio具有以下特征:
- 系统:openSUSE 11.1(x86_64)
- 处理器(CPU):Intel(R)Core(TM)2 Duo CPU T6670 @ 2.20GHz
- 处理器速度:1,200.00 MHz
- 总内存(RAM):2.8 GB
- Java:OpenJDK 1.6.0_0 64位
为了方便起见,我提供了用于执行压力测试的代码段:
int repeats = 1000000;
long start = System.currentTimeMillis();
for(int i = 0; i < repeats;i ++)cs.baz();
System.out.println("TPS : " + repeats/((System.currentTimeMillis() - start)/1000d));
编码愉快! 并且不要忘记分享!
贾斯汀
- Java最佳实践–高性能序列化
- Java最佳实践– Vector vs ArrayList vs HashSet
- Java最佳实践–字符串性能和精确字符串匹配
- Java最佳实践–队列之战和链接的ConcurrentHashMap
- Java最佳实践– Char到Byte和Byte到Char的转换
- 如何在不到1ms的延迟内完成100K TPS
- 提升您的休眠引擎
翻译自: https://www.javacodegeeks.com/2011/01/cajo-easiest-way-to-accomplish.html