CORBA ja RMI - Hajautetut oliomallit

31.10.1999

Erkki Pulliainen
Teemu Koponen
Tietotekniikan osasto
Teknillinen Korkeakoulu
erkki.pulliainen@hut.fi
tkoponen@iki.fi

Tiivistelmä

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.


Sisällysluettelo

1 Johdanto

2 RMI - Olioiden hajautus Javalla

2.1 RMI:n yleinen arkkitehtuuri ja toiminta

2.2 RMI:n käyttö

3 Olioiden hajautus CORBA:lla

3.1 CORBA:n yleinen arkkitehtuuri ja toiminta

3.2 CORBA:n käyttö

4 RMI:n ja CORBA:n vertailua

5 RMI-IIOP - Hajautustekniikoiden yhdistäminen

Lähdeluettelo

Lisätietoja


1 Johdanto

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; ORB (Object Request Broker) huolehtii nimensä mukaisesti pyyntöjen välittämisestä olioille ja vastausten välittämisestä takaisin asiakkaille. Ennen kuin asiakas voi lähettää pyynnön oliolle, sillä täytyy olla viittaus siihen. Niin kauan kuin viittaus on olemassa, ORB säilyttää olion instanssin ja välittää tälle olioon kohdistuvat pyynnöt. Linkit voivat olla pysyviä, ORB tarjoaa tavan konvertoida viittaukset merkkijonoiksi, jotka voidaan myöhemmin muuttaa takaisin varsinaisiksi olioiksi.

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]

5. RMI:n ja CORBA:n vertailua

Vaikkakin RMI on helppokäyttöinen, se ei ole saataville muille kielille kuin Javalle. Lisäksi RMI:n käyttö ei välttämättä ole aina intuitiivista, esimerkiksi olioiden kopioiden välitys parametreina voi aiheuttaa ongelmia koodin toimiessa eri tavalla kuin mikäli ei käytettäisi RMI:tä. Olioiden kopioiden välitys kuitenkin parantaa suorituskykyä, koska kaikkia olioita ei tarvitse hajauttaa niitä käytettäessä. Suorituskyky voi kuitenkin pudota rajusti ohjelman koon ja monimutkaisuuden kasvaessa. Poikkeusten hallinta toimii mallikkaasti, sillä myös poikkeukset serialisoidaan. Lisäksi myös roskienkeruu tapahtuu hajautetusti.

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>

Lisätietoja

The CORBA FAQ - Frequently Asked Questions
Usein esitettyjä kysymyksiä CORBA-tekniikasta
The Common Object Request Broker: Architecture and Specification
CORBA:n arkkitehtuuri
Java Distributed Computing FAQs - RMI FAQs
Usein esitettyjä kysymyksiä RMI-tekniikasta
What's New in CORBA 3
Selostus CORBA 3:n uusista piirteistä