分布式計算在企業應用程序開發世界中變得越來越重要。 如今,開發人員不斷需要解決以下問題:如何通過將應用程序擴展到單個節點之外來增強可伸縮性? 如何保證高可用性,消除單點故障并確保滿足客戶的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