Kihagyás

Objektumorientált szoftvertervezés - 5. előadás
Elosztott OO

  • hálózati kommunikáció esetén felmerülő problémák és megoldások

Helyi hívás vs távoli hívás

Helyi hívás

  • kliens és szerver azonos memória-térben vannak
  • kliens objektumnak közvetlen mutatója van a szerver interfészére
  • hívás közvetlenül történik
  • image-20201117102648069

Távoli hívás

  • kliens és szerver objektum külön memóriatérben vannak
  • két objektumnak hálózati kapcsolaton keresztül kommunikál
  • cél: kliens olyan interfészt lásson, mintha helyi hívást intézne
    • ezt egy proxy objektum biztosítja → kliens hívásából hálózati üzenet = sorosítás
    • ezt egy adapter fogadja → visszasorosítja, majd továbbítja a szerver interfészen keresztül a szervernek
  • image-20201117103116848

Kérdések:

  • hogyan definiáljuk a szerver interfészt?
    • ugyanazon a programnyelven? → programnyelv interfészét használhatjuk
    • különböző programnyelven? → programnyelvektől független interfész leírókkal
  • hogyan találjuk meg a szervert?
    • kliens tudja hol van → kliensnek config fájljában van
    • logikai név alapján → ezt a fordítást egy névszerver végzi
    • interfész alapján → treading service interfész specifikációból fizikai címet készít (pl időjáros cucc interfész kell)
  • hogyan implementáljuk a proxy-t?
    • feladata: szerver megkeresése, kapcsolat felépítése, paraméterek és eredmények sorosítása
    • megvalósítás: proxy + adapter tervezési minta
  • hogyan implementáljuk az adaptert?
    • feladata: kliens kapcsolat fogadása, szerver objektum példányosítása, kliens kérdések továbbítása függvényhívásként a szerver objektumhoz, paraméterek és eredmények sorosítása, több kérdés kezelése párhuzamosan
    • megvalósítás: adapter tervezési minta
  • hogyan sorosítsuk az adatokat?
    • memóriában lévő adat bájtfolyammá és vissza
    • teljes hierarchiát kell leírni majd azt rekonstruálni a másik oldalon
    • 2 fajta:
      1. bináris sorosítás → gyors, hatékony, kevés memóriát használ, DE bináris kompatibilitást feltételez a kliens és szerver közt, pl ha ugyanazon programnyelven készültek
      2. szöveges sorosítás → emberileg is olvasható (XML, JSON), lassabb, kevésbé hatékony, több memóriát eszik, DE programnyelvek közt kompatibilis, és időtálló
  • hogyan kezeljük a memóriát?
    • ki foglalja le és ki szabadítja fel a bemenő és kimenő paramétereket
    • modern nyelvekben: GC
    • régebbi nyelvekben: objektum tulajdonosának egyértelműsítésével
      • pl eredményt: proxy foglalja, kliens szabadítja
  • hogyan szolgálunk ki több klienst?
    • egy szálú szerver →  nincs konkurencia probléma
      • blokkoló → újabb kéréseknek várakozni kell, míg a jelenlegi kiszolgálásra nem kerül (ilyet nem szoktunk csinálni → nem hatékony)
      • nem blokkoló → pl nodejs, hatékonyabb de komplex callback programozáson alapuló modellt igényel
    • több szálú szerver → védeni kell a több szál által használt adatokat
      • kliensként külön szál → könnyen túlterheli a szervert
      • thread pool → amíg van szabad szál, addig tud kiszolgálni, jól kihasználja a szerver erőforrásait
  • hány objektumpéldány kell a szerverből?
    • egy szerver példány → singleton, jó ha nincs kliens függő állapot
    • kliensenként egy → kliens specifikus állapotot is tud tárolni, DE nem skálázható (újrainduláskor elveszhet), lezáró szükséges
    • object pool → kiszolgáló szerver objktumokhoz rendeljük a klienseket, így kérések szeparálva futnak, de nincs kliens specifikus állapot. Ez jól skálázható
  • hogyan őrizzük meg az állapotot hívások között?
    • szerver memóriájában → minden kliens saját szerver objektum példánnyal rendelkezzen
    • minden hívásban átküldjük → működik, ha nem túl nagy ez az állapot (pl böngészú cookie-k)
    • adatbázisban → jól skálázódik, de a kliensnek azonosítani kell tudnia magát (kell seccion id)
  • hogyan kommunikáljunk, ha valamelyik oldal nem elérhető?
    • szinkron hívásnál (kliensnek azonnal kell válasz) → nem tudunk kommunikálni
    • aszinkron hívás (ráér a válasz)
      • ha nincs megbízható köztes szereplő
      • ha van megbízható köztes szereplő → megoldható a szétcsatolt kommunikáció (köztes szereplő vigyáz addig az adatra). Nehézség a visszaérkező válaszok párosítása a hozzájuk tartozó kérdésekkel
  • hogyan kezeljük a szinkron hívásokat?
    • általában folyamatosan fennálló kapcsolat kell
    • kliens elküldi a kérdést, blokkolva vár a válaszra
    • szerver fogadja a kérdést, és kiszolgálja:
      • szinkron módon
      • aszinkron módon
  • hogyan kezeljük az aszinkron hívásokat?
    • ha nincs megbízható köztes szereplő
      • call-back
      • periodikus pollozás
    • ha van megbízható köztes szereplő
      • üzenetek: sok forrás (kliens), egy cél (szerver)
        • kliensek egy sorba küldik a kérdéseket, a szeverek meg ebből veszik ki
        • image-20201117141936514
        • egy üzenetet csak egy szerverpéldány dolgozhat fel (más nem kaphatja meg)
      • események: egy forrás (publisher), sok cél (subscriber)
        • image-20201117142037486
        • minden eseményt minden feliratkozó megkap, és általában a fogadók nem küldenek választ

Technológiák elosztott kommunikáció megvalósításához

  • Konkurens és elosztott minták
    • szálak közti szinkronizáció, használt erőforrásokra a kölcsönös kizárást, kliensektől beérkező kérések lekezelése
    • image-20201117142342639
  • Sorosítás
    • image-20201117142420504
    • bináris: java / .net serialization
    • szöveges: XML, JSON
  • objektum-relációs leképzés
    • image-20201117142542722
    • javaban JPA, .net-ben EntityFramework
  • kommunikációs technológia és keretrendszer
    • image-20201117142644350
    • programnyelvfüggő megoldás → java / .net RMI
    • SOAP web services, XML-re épül
    • REST services, főleg JSON-ra esetleg XML-re épül

SOAP webszolgátlatások

  • XML-re épülő, programnyelvektől és oprendszertől független kommunikációs szabvány
  • típusos api-ja van mind .net mind java-hoz
  • a cserlégetett XML-ek szabványát adja csak meg
  • image-20201117142943029
  • XML előállítása és feldolgozása NEM feladata!
  • image-20201117143209793
    • WSDL interfész leíró → megadja, hogy rajta milyen függvények milyen paraméterekkel hívható, ezek milyen kivételeket dobhatnak
  • image-20201117143543360
    • import → kisebb részekre feldaraboláshoz
    • types → saját összetett típusok megadása
    • message → szolgáltatás által elfogadott és visszaküldött üzenetek definiálása
    • portType → szolgáltatás interfésze, azaz a rajta meghívható üzenetek
    • binding → protokoll konfigurálása
    • service → konkrét URL-t tartalmazza, ahol a szolgáltatás meghívható

REST szolgáltatások

  • HTTP protokoll kibővítése, hálózati üzenetekért felelős
  • bármely HTTP protokollal való kommunikációra képes alkalmazás tud REST-el kommunikálni
  • OpenAPI-t érdemes használni (REST interfész leírás)
  • image-20201118192005203
  • image-20201118192028686
  • GET kérés
    • image-20201118192106234
  • POST kérés
    • image-20201118192130725
    • felhasználónév-jelszót csak POST-al ajánlott küldeni
    • újraküldésnél vigyázni kell (ne fizessünk duplán)
  • előnye: böngészőből is egyszerűen tesztelhető
  • példák
    • GET /api/movies → összes filmet adja vissza
    • GET /api/movies/12 → adott azonosítójú filmet kapunk vissza
    • GET /api/movies?orderby=title → összes film cím alapján rendezve
  • PUT → erőforrás frissítése, vagy ha nincs ilyen még akkor létrehoz egy ilyet
  • DELERE → erőforrás törlése, gyűjteményeken általában nem működik
  • eredmény elvárt formátumát megadhatja a szerver → HTTP "Accept" fejléccel
  • választ a HTTP törzsben kapjuk
    • típus a Content-Type fejlécben található