Cajo,用Java完成分布式计算的最简单方法

Cajo是一个小型库,提供了一种强大的动态多计算机协作方式,使得Java的分布式计算变得简单易用,无需对应用程序结构或源代码进行更改。通过Cajo,可以轻松地将普通Java对象暴露为分布式服务,实现无缝协作。本文通过一个服务器-客户端示例展示了Cajo的灵活性和易用性,并提及了其出色的性能表现。
摘自Jonas Boner在2006年5月1日发布在TheServerSide.com的文章“ Distributed Computing Easy”中的介绍部分:

分布式计算在企业应用程序开发世界中变得越来越重要。 如今,开发人员不断需要解决以下问题:如何通过将应用程序扩展到单个节点之外来增强可伸缩性? 如何保证高可用性,消除单点故障并确保满足客户的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 Grail

public class Server {

   public static class Test { // remotely callable classes must be public
      // though not necessarily declared in the same class
      private final String greeting;
      // no silly requirement to have no-arg constructors
      public Test(String greeting) { this.greeting = greeting; }
      // all public methods, instance or static, will be remotely callable
      public 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 client
         return "This is extra stuff";
      }
   } // arguments and return objects can be custom or common to server and client

   public static void main(String args[]) throws Exception { // unit test
      Cajo 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 errors

interface SuperSet {  // client method sets need not be public
   void baz() throws RemoteException;
} // declaring RemoteException is optional, but a nice reminder

interface 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 matter

public class Client {
   public static void main(String args[]) throws Exception { // unit test
      Cajo 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 time

      Object refs[] = cajo.lookup(ClientSet.class);
      if (refs.length > 0) { // compatible server objects found
         System.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));

编码愉快! 并且不要忘记分享!

贾斯汀

相关文章 :

翻译自: https://www.javacodegeeks.com/2011/01/cajo-easiest-way-to-accomplish.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值