31.10.1999
Erkki Pulliainen
Teemu Koponen
Tietotekniikan osasto
Teknillinen Korkeakoulu
erkki.pulliainen@hut.fi
tkoponen@iki.fi
Tämä dokumentti antaa suppean katsauksen hajautettuun oliomallinnukseen ja laskentaan käyttäen RMI ja CORBA tekniikkaa. Kummankin tekniikan pääpiirteet käydään läpi sekä arkkitehtuuri kuvataan yleisesti. Dokumentissa annetaan lyhyet esimerkit kummankin tekniikan käytöstä Java-kielellä. Tämän lisäksi tekniikoita verrataan lyhyesti dokumentin loppuosassa.
1 Johdanto
2 RMI - Olioiden hajautus Javalla
2.2 RMI:n käyttö
3.2 CORBA:n käyttö
5 RMI-IIOP - Hajautustekniikoiden yhdistäminen
Hajautetulla laskennalla voidaan jakaa ohjelmien suoritusta, resursseja sekä tietoa eri koneille, siten että järjestelmän toiminta säilyy yhtenäisenä. Hajautuksen toteutus tehokkaasti, luotettavasti, läpinäkyvästi ja skaalautuvasti on kuitenkin hankalaa. Ensimmäinen yleinen teknologia hajautukseen oli RPC (Remote Procedure Call), joka kuitenkin mahdollisti hyvin vain muissa koneissa olevien funktioiden kutsumisen, eikä soveltunut olioiden siirtoon kovinkaan hyvin [2].
Hajautetulla oliomallinnuksella tarkoitetaan, että hajautus tapahtuu jakamalla olioita eri koneille ja mahdollistaen eri koneista sijaitsevien olioiden käytön muista koneista käsin. Oliot hajautetaan verkon kautta, kukin sijaitsee fyysisesti omassa koneessaan, mutta olion käyttäjät havaitsevat olion aivain kuin se olisi samassa koneessa. Hajauttamalla olioita voidaan lisätä hajautuksen läpinäkyvyyttä ohjelmassa. [3]
Hajautuksen toteutus on ongelmallista, ja tästä syystä löytyykin tarvetta yhteiselle arkkitehtuurille ongelman ratkaisuun. Toteutusta hankaloittavat mm. joskus korkeasta vasteajasta johtuvat ongelmat, verkkovirheet, kuorman jako eri koneille oikeassa suhteessa sekä hajautuksessa olevien tapahtumien oikea järjestys. [4]
Olioiden hajautukseen löytyy eri tekniikoita, joista tässä käsitellään
OMG:n (Object Management Group) CORBA (Comman Object Request Broker
Architecture) sekä Javan Remote Method Invocation (RMI). Muitakin tekniikoita
löytyy, tärkeimpänä esimerkkinä Microsoftin DCOM, joka on hajautettu
laajennus Microsoftin COM (Component Object Model) arkkitehtuuriin [1].
2 RMI - Olioiden hajautus Javalla
Javan RMI tarjoaa yksinkertaisen ja suoraviivaisen mallin Javalla laadittujen olioiden hajautukseen. RMI on alunperin tarkoitettu puhtaasti Java ympäristöön, mutta Javan JNI (Java Native Interface) rajapinnan käyttö mahdollistaa liittymisen myös muilla kielillä laadittuihin järjestelmiin [6]. Tämä on kuitenkin huomattavasti monimutkaisempi tapa hajauttaa eri ohjelmointikielillä laadittuja olioita kuin esimerkiksi CORBA, josta enemmän luvussa 3.
RMI-ohjelmoijien on kuitenkin mahdollista käyttää myös CORBA-olioita
käyttämällä RMI-IIOP-tekniikkaa. Tällöin on mahdollisuus generoida
tarvittava IDL-koodi suoraan Java-koodista, joskin Java-ohjelman on
noudatettava tiettyjä vaatimuksia, jotka aiheutuvat CORBA:sta. [8]
2.1 RMI:n yleinen arkkitehtuuri ja toiminta
RMI järjestelmä koostuu kolmesta tasosta, stub/skeleton layer, remote/reference layer ja transport layer. Nämä tasot ovat toisistaan riippumattomia ja kukin voidaan korvata toisen tyyppisellä toteutuksella tarvittaessa. Esimerkiksi TCP-protokolla on vain yksi tapa toteuttaa alimman tason toiminnallisuus.
Kun jotain toisessa koneessa olevaa oliota kutsutaan, suoritetaan kutsu kutsujan koneessa olevaan stubiin, joka olion toiminnallisuuden toteutuksen sijaan välittää kutsun eteenpäin toisessa koneessa sijaitsevaan olion skeletoniin, joka vastaanottaa kutsun ja välittää sen edelleen varsinaiselle oliolle, joka suorittaa kutsun, ja vastaus lähetetään edelleen skeletonin kautta takaisin stubille ja sieltä varsinaiselle kutsujalle. Sekä skeleton että stub ovat luokkia, jotka toteuttavat hajautettavan olion rajapinnan.
Parametrien ja paluuarvojen välitykseen RMI:ssä käytetään olioiden
serialisaatiota, eli mikäli parametrina välitettävää oliota ei
ole tarkoitus hajauttaa, lähetetään siitä ainoastaan kopio. Tämä on
huomattavasti tehokkaampaa kuin lähettää viittaus jokaiseen
olioon. Parametrina välitettävän olion tila ei tällöin tietysti muutu,
vaikka sitä kutsuttavassa metodissa muutettaisiinkin. Tämä voi aiheuttaa
jossain määrin sekaannusta. [7]
2.2 RMI:n käyttö
RMI:n käyttö on verrattain helppoa muihin ratkaisuihin verrattuna, kuten Java-ohjelmointi yleisesti muutenkin. Jokaisen hajautettavan olion tulee olla määriteltäväksi rajapintana, joka johdetaan Remote-rajapinnasta. Tämä merkitsee rajapinnan hajautettavaksi. Lisäksi jokaisen rajapinnan metodin tulee heittää RemoteException poikkeus. Kaikki metodeissa käytettävät parametrit sekä paluuarvot tulee olla serialisoituvissa (paitsi ne, jotka hajautetaan). [6]
Esimerkki hajautettavasta luokasta tarjotaan alla. String luokka on serialisoituvissa, joten se voidaan antaa paluuarvona.
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
Oliot, joita voidaan hakea verkon yli, johdetaan yleisesti
UnicastRemoteObject-luokasta, tosin omaakin toteutusta
tarvittavista metodeista voi käyttää, mikäli perintä ei tule kysymykseen.
Alla on annettu ylläesitetyn esimerkkirajapinnan toteutus. Tämä olio täytyy ajaa RMI kääntäjän läpi (rmic), joka luo tarvittavat stub- ja skeletonluokat. Kun rajapinta on kerran määritelty, on sitä hankala muuttaa. Toista menetelmää, dynaamista, tutkitaan CORBA:n yhteydessä.
public class HelloImpl extends UnicastRemoteObject implements Hello {
public HelloImpl() throws RemoteException {
super();
}
public String sayHello() {
return "Hello World!";
}
public static void main(String args[]) {
HelloImpl obj = new HelloImpl();
Naming.rebind("//myhost/HelloServer", obj);
}
}
Tietokoneessa, joka tarjoaa olioita muille (eli toimii serverinä),
pyörii RMIRegistry, johon hajautettavat oliot rekisteröityvät. Tähän
rekisteröidään hajautettavat oliot, joiden instansseja voidaan
suoraan hakea verkon yli. Näille annetaan nimi, ja olio voidaan hakea
tämän jälkeen yksinkertaisella metodikutsulla.
Hello obj = null;
...
obj = (Hello)Naming.lookup("//myhost/HelloServer");
String message = obj.sayHello();
...
3 Olioiden hajautus CORBA:lla
OMG on verrattain uusi organisaatio, joka tuottaa spesifikaatioita ja
standardeja olio-ohjelmoinnin tarpeisiin. CORBA on OMG:n vuonna 1991 laatima
konkreettinen spesifikaatio rajapinnoista ja palveluista joita eri
ORB:ien on toteutettava. Sittemmin useat tahot ovat ryhtyneet tarjoamaan
tuotteita CORBA-spesifikaation mukaisia tuotteita. [9]
3.1 CORBA:n yleinen arkkitehtuuri ja toiminta
CORBA koostuu viidestä pääkomponentista, jotka ovat;
CORBA tarjoaa kaksi tapaa, millä asiakas voi lähettää pyyntöjä, staattisen ja dynaamisen (static invocation ja dynamic invocation). Staattisessa tavassa asiakkaalla on rajapintaspesifinen stubi samaan tapaan kuin RMI:ssä, dynaamisessa taas rajapinta voi muuttua, eikä asiakkaan ole pakko tuntea rajapintaa tarkkaan tehdessään kutsuja.
Olion viittaus identifioi olion yksikäsitteisesti, muttei sen rajapintaa ja sen tarjoamia palveluja. IDL on kieli, jolla rajapinta voidaan määritellä. Kieli muistuttaa C++:aa tai Javaa. IDL tukee rajapintojen perintää samaan tapaan kuin Javassa. IDL-kääntäjät kääntävät IDL-kielisen rajapinnan kullekin ohjelmointikielelle. Näin CORBA:a voidaan käyttää millä tahansa ohjelmointikielellä.
Interface Repository vastaa rajapintojen tallennuksesta ja tarjoamisesta käyttäjille. Tätä voidaan käyttää rajapinnan selaamiseen ja ORB:it voivat käyttää repositorya tarkistaakseen pyyntöjen parametrien tyyppejä. Tärkein repositoryn käyttö on tarjota mahdollisuus suorittaa tyyppitarkistus DII:n kautta lähetetyille pyynnöille.
Dynamic Interface Invocation mahdollistaa asiakkaille pyyntöjen lähetyksen olioille, joiden rajapintaa asiakas ei täysin tunne käännösaikana. Asiakas voi selata rajapintaa DII:n avulla. DII:n käyttö on kuitenkin raskasta, ja normaalisti käytetään sen sijaan staattisia IDL stubeja.
Object Adapter tarjoaa tavat, joilla eri oliototeutukset käyttävät ORB
palveluja, kuten olioiden luontia ja olioiden metodikutsuja. [9]
3.2 Corban käyttö
Käytettäessä CORBA:a olioista on luotava IDL-rajapinta, joka
käännetään kohdekielelle. Tässä esimerkissä käytetään Javaa. Alla
esitetään lyhyt IDL:llä kirjoitettu esimerkkirajapinta.
module HelloApp
{
interface Hello
{
string sayHello();
};
};
Tämä koodi ajetaan idltojava kääntäjän lävitse, joka generoi
halutut rajapinnat Javalle, skeletonin, stubin, sekä muutaman muun
luokan. Skeleton luokan nimi on _HelloImplBase, josta johdetaan
varsinainen toteutus. [5]
class HelloServant extends _HelloImplBase
{
public String sayHello()
{
return "\nHello world !!\n";
}
}
Tämän jälkeen voidaan tarjota olio ulkomaailmaan seuraavankaltaisella
koodilla [5], jonka tarkempiin yksityiskohtiin ei tässä
puututa. Periaate on sama kuin RMI:tä käytettäessä.
public class HelloServer {
public static void main(String args[])
{
// create and initialize the ORB
ORB orb = ORB.init(args, null);
// create servant and register it with the ORB
HelloServant helloRef = new HelloServant();
orb.connect(helloRef);
// get the root naming context
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
// bind the Object Reference in Naming
NameComponent nc = new NameComponent("Hello", "");
NameComponent path[] = {nc};
ncRef.rebind(path, helloRef);
// wait for invocations from clients
java.lang.Object sync = new java.lang.Object();
synchronized (sync) {
sync.wait();
}
}
}
Tämän jälkeen olion voi hakea kohdekoneesta ja sen palveluja voidaan
käyttää:
// create and initialize the ORB
ORB orb = ORB.init(args, null);
// get the root naming context
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
// resolve the Object Reference in Naming
NameComponent nc = new NameComponent("Hello", "");
NameComponent path[] = {nc};
Hello helloRef = HelloHelper.narrow(ncRef.resolve(path));
// call the Hello server object and print results
String hello = helloRef.sayHello();
System.out.println(hello);
Esimerkin käyttö tapahtuu käynnistämällä nimipalvelu (vastaava kuin
RMIRegistry) ja ajamalla HelloServer-luokka, minkä jälkeen
Hello-luokkaa voidaan käyttää verkon yli. [5]
CORBA:n suurin etu on sen saatavuus monille ohjelmointikielille ja
hyvä skaalautuvuus suuriinkin järjestelmiin. CORBA ei kuitenkaan
tarjoa hajautettua roskienkeruuta. Lisäksi poikkeusten käyttö on
jonkin verran hankalaa, koska poikkeusluokkia ei voi juurikaan periä.
Kehitystyö CORBA:lla on selvästi hankalampaa kuin RMI:llä. [3]
Lähdeluettelo
| [1] | Alho, K., A Comparison of CORBA, DCOM and RMI, 14.1.1998 [viitattu 29.10.1999]
< http://wwwseg.cs.hut.fi/~kta/corba-comparison/> |
| [2] | Kahle, R.S., Create Distributed Apps with RMI, JavaPro, 1998, February/March
[viitattu 29.10.1999]
< http://www.java-pro.com/archives/1998/jp_febmar_98/rk0298/rk0298.htm> |
| [3] | Raj, G.S., A Detailed Comparison of CORBA, DCOM and Java/RMI, 28.9.1998 [viitattu 30.10.1999]
< http://www.execpc.com/~gopalan/misc/compare.html> |
| [3] | Rao, P., Using Java: Java RMI, CORBA or COM?, USENIX - Using Java 13, 13.11.1998 [viitattu 30.10.1998]
< http://www.usenix.org/publications/java/usingjava13.html> |
| [4] | Schmidt, D. C., Developing Distributed Object Computing
Applications with CORBA,
16.4.1997 [viitattu 30.10.1999]
< http://www.cs.wustl.edu/~schmidt/corba4.ps.gz> |
| [5] |
Sun Microsystems, Java IDL Documentation, 21.10.1999 [viitattu 30.10.1999]
< http://java.sun.com/products/jdk/1.2/docs/guide/idl/index.html> |
| [6] | Sun Microsystems, Java Remote Method Invocation - Distributed Computing for Java, 21.5.1999 [viitattu 29.10.1999]
< http://java.sun.com/marketing/collateral/javarmi.html> |
| [7] | Sun Microsystems, Remote Method Invocation Specification, 18.3.1997 [viitattu 29.10.1999]
< http://java.sun.com/products/jdk/1.1/docs/guide/rmi/spec/rmiTOC.doc.html> |
| [8] | Sun Microsystems, RMI-IIOP Programmer's Guide, 29.10.1999 [viitattu 29.10.1999]
< http://java.sun.com/products//jdk/1.3/docs/guide/rmi-iiop/rmi_iiop_pg.html> |
| [9] |
Vinoski, S., Distributed Object Computing With CORBA, C++ Report, 1993,
July/August [viitattu 30.10.1999]
< http://www.cs.wustl.edu/~schmidt/docwc.ps.gz> |