Institute of Computer Science
  1. Courses
  2. 2023/24 spring
  3. Development of web services and distributed systems (LTAT.06.018)
ET
Log in

Development of web services and distributed systems 2023/24 spring

  • Pealeht
  • Loengud
  • Praktikumid
  • Lahenduste Esitamine

Kolmas praktikum - RabbitMQ & kaugprotseduurid

Selles praktikumis vaatame kuidas luua lihtne hajussüsteem, mis võimaldab RPC kaudu välja kutsuda funktsioone teistes süsteemi sõlmedes. Me loome RPC lahenduse ise, ilma RPC teekide või vahevarade kasutamisetta, aga kasutame sõnumite edastamiseks klientide ja serverite vahel RabbitMQ maaklerit.

NB! Jätkame eelmises praktikumis kasutatud RabbitMQ keskkonna kasutamist.

Viited

  1. RabbitMQ Python teegi, Pika dokumentatsioon: https://pika.readthedocs.io/en/latest/intro.html
  2. Pika näited: https://pika.readthedocs.io/en/latest/examples.html

Probleemide korral kontrollige:

  1. Võimalikud probleemid ja nende potentsiaalsed lahendused osa praktikumi juhendi lõpus.
  2. Küsige otse #praktikum-3-rpc Zulip teemas.

Ülesanne 3.1: Uue RabbitMQ virtuaalse keskkonna seadistamine

Kasutame selles praktikumis sama RabbitMQ serverit mida kasutasime eelmine kord, aga loome uue RabbitMQ virtuaalse keskkonna. See aitab meil hoida eelmise hajusrakenduse järjekorrad ning Exhange'id eraldi selle praktikumis loodavatest.

Samuti loome uue kasutaja hspraks03, kellele anname õigused uut Virtuaalkeskkonda kasutada aga kellel ei ole õigusi RabbitMQ andministreerimisliidest kasutada ning kes ei saa ligi eelmise praktikumi keskkonnale ning andmetele. RabbitMQ'd kasutatavate rakenduste loomisel tuleks vältida administratsiooniõigustega kasutajate kasutamist (nagu me seda tegime eelmises praktikumis).

  • Logi sisse RabbitMQ administreerimise liidesesse: http://172.17.66.250:15600/ asendades aadressis asuva pordi (15600) väärtuse enda RabbitMQ pordiga, mille saite eelmise praktikumi alguses.
    • Täpse pordi väärtuse, kasutajanime ja parooli sai õppejõu käest eelmises kraktikumis. Igal tudengil on erinev keskkond.
    • See server on kätte saadav ainult Ülikooli võrgust.
      • Kontrollige, et kasutate Delta majas Eduroam võrku, või VPN'i.
        • UT public võrk ei ole piisav.
        • Eduroam võrk väljaspoolt Delta maja ei pruugi olla piisav.
      • Ülikooli VPN õpetus: https://wiki.ut.ee/pages/viewpage.action?pageId=17105590

Loome täiesti uue RabbitMQ virtuaalse keskkonna ja kasutaja selle praktikumi jaoks.

  1. Loo uus RabbitMQ Virtuaalne keskkond (Virtual Enviorenment)
    • Ava RabbitMQ Admin lehekülg (üleval keskel on link)
    • Vali Virtual Hosts (paremal ülevalpool on link)
    • Lisa uus Virtuaalne keskkond (Virtual Host)
      • Pane nimeks hspraks03
  2. Loo uus RabbitMQ kasutaja
    • Ava RabbitMQ Admin lehekülg (üleval keskel on link)
    • Username: hspraks03kasutaja
    • Parool vali ise vabalt, aga jäta see meelde kuna meil on seda hiljem vaja Python programmi jaoks seadistada
  3. Seadistame uuele kasutajale õigused kasutada ainult hspraks03 virtuaalkeskkonda
    • Klikki kasutaja nimel kasutajate administreerimisvaates
    • Vali Permissions
    • Vali VirtualHost hspraks03, jäta muud valikud samaks ja klikki nupul Set permission
    • Edaspidi kasutame selle praktikumis loodud rakendustes hspraks03kasutaja kasutajat.

Ülesanne 3.2: RPC Kliendi implementeerimine

Loome Python RabbitMQ põhise RPC Kliendi.

NB! Selles praktikumis aktiveerime ka Python logimise. Lisaks sellele, et see aitab meie programmidel paremini logida infot ja veateateid, annab see meile võimaluse ka RabbitMQ spetsiifilist logide sisu näha.

  1. Tõmmake alla Pythoni rpc kliendi skeleton: rpcklient.py
    • PS! "..." koodis tuleb asendada teie poolt kirjutatud koodiga.
    • NB! asendage koodis RabbitMQ serveri IP ära!
  2. Implementeerime puuduvad osad:
    • if __name__ == _main_: meetod hoolitseb programmi käivitamise eest
      1. broker_port väärtus peaks olema see port, mida te saite eelmise praktikumi käigus (56YZ).
      2. routing_key väärtus peaks olema funktsiooni nimi, mida me soovime välja kutsuda. Hiljem, serveri programmis peame kasutama sama nime järjekorra nimena. Jätke see meelde.
      3. RabbitMQRpcClient() klassi objekt valmistab ette RPC objekti mille kaudu saame funktsiooni välja kutsuda.
      4. sisend on argument meie funktsioonile. Kuna andmeid peab saatma hiljem RabbitMQ sõnumina, siis loome Python sõnaraamatu (dictionary), mis sisaldab kõiki funktsiooni argumente. Siin on argumendid:
        • raamat: Gutenberg raamatu id (nagu esimeses praktikumis)
        • sone: Sõne, mida soovime raamatust otsida.
        • json.dumps() funktsiooni abil konverteeritakse see objekt string väärtuseks ning hiljem saab seda sama moodi tagasi JSON tüüpi objektiks konverteerida.
    • class RabbitMQRpcClient(object) klassis:
      • ef __init__(self, broker_host, broker_port, credentials, routing_key): meetod
        1. Seadistame ühenduse loomise:
          •         self.connection = pika.BlockingConnection(
                        pika.ConnectionParameters(host=broker_host, port=broker_port, virtual_host= "hspraks03", credentials=credentials))
            
          • virtual_host on siin varasemalt loodud virtuaalse keskkonna nimi
          • Ülejäänud väärtused on samad eelmise praktikumi koodile.
        2. Seadistame kanali loomise:
          • self.channel = self.connection.channel()
        3. Seadistame järjekorra loomise:
          • result = self.channel.queue_declare(queue='', exclusive=True)
          • Siin on järjekorra nimeks tühi sõne, mis tähendab seda, et RabbitMQ seadistab meie kliendile unikaalse genereeritud järjekorra.
          • exclusive=True tulemusena teised kliendid seda järjekorda kuulata ei saa.
          • Sellesse järjekorda saabuvad hiljem serveri vastused meie kliendile.
        4. automaatselt genereeritud järjekorra nime saame kätte läbi result objekti nii:
          • result.method.queue
          • Selle peaks seadma klassi muutuja self.callback_queue väärtuseks.
        5. Alustame vastuste kuulamist, kuhu peaksid hiljem jõudma serveri vastused meie RPC väljakutsetele:
          •         self.channel.basic_consume(
                        queue=self.callback_queue,
                        on_message_callback=self.on_response,
                        auto_ack=True)
      • def on_response(self, ch, method, props, body) meetod
        • Seda meetodit me muutma ei pea, siin kontrollitakse kas saabunud sõnum vastab päringule, mis sellest objektist saadeti.
      • def call(self, n): meetod
        • Genereerime uue identifikaatori sõnumile, mille me serverile saadame:
          • self.corr_id = str(uuid.uuid4())
          • Selle abil saab päringud ning vastused "kokku viia"
        • Publitseerime sõnumi
          •         self.channel.basic_publish(
                        exchange='',
                        routing_key=self.routing_key,
                        properties=pika.BasicProperties(
                            reply_to=self.callback_queue,
                            correlation_id=self.corr_id,
                        ),
                        body=str(n))
            • exchange väätus peab jääma tühjaks süneks ('') - See määrab selle, et kasutame RabbitMQ default Exchange'i (AMQP default)
            • routing_key on see väärtus, mille varasemalt seadistasime main blokki sees. See määrab serveri järjekorra, kuhu sõnum jõuab, ning selle kaudu selle, mis funktsiooni soovime välja kutsuda.
            • properties kaudu paneme paika ka järjekorra nime, kuhu server peaks meie päringu tulemuse tagasi saatma. See sai seadistatud __init__ funktsioonis
            • Sarnaselt, correlation_id määrab selle konkreetse väljakutse sõnimi unikaalse ID (mille me varasemalt genereerisime)
            • n on sisend(id) funktsioonile, mille edastame RabbitMQ funkrsioonina.

Ülesanne 3.3: RPC Serveri implementeerimine

Loome Python RabbitMQ Serveri.

  1. Tõmmake alla Pythoni rpc kliendi skeleton: rpcservert.py
    • PS! "..." koodis tuleb asendada teie poolt kirjutatud koodiga.
    • NB! asendage koodis RabbitMQ serveri IP ära!
  2. Implementeerige programmis puudu olevad osad:
    1. lae_alla_raamat_ja_otsi_sone meetod.
      • See on meie RPC meetod/protseduur, mida soovime kliendi rakenduse seest välja kutsuda.
      • See meetod saab sisendiks kaks parameetrit:
        • raamat:
          • sone
      • See meetod peaks alla laadima Gutenberg repositooriumist raamatu, mille id on raamat muutuja väärtus, ning loendama, mitu korda muutuja sone väärtus leidub selles raamatus.
      • Saate uuesti ära kasutada funktsiooni, mille tegiste esimeses praktikumis.
      • Tulemuseks peaks olema üks int tüüpi väärtus.
    2. def on_request(ch, method, props, body) meetod:
      • see meetod sisaldab serveri koodi RabbitMQ sõnumite kuulamiseks, lae_alla_raamat_ja_otsi_sone funktsiooni välja kutsumiseks ning tulemuse tagasi saatmiseks RabbitMQ kaudu
      • on_request(ch, method, props, body) meetod käivitatakse iga unikaalse MQTT sõnumi peal.
      • argumendid muutuja sisaldab sõnumi sisu, mis on konmverteeritud python sõnaraamatu objektiks. Ehk selleks objektiks, mida klient saatis ning mis sisaldab sõne ja raamatu id väärtust.
      • Kutsuge välja lae_alla_raamat_ja_otsi_sone õigete argumentidega, tulemuseks on muutuja response väärtus
      • Publitseerime tulemuse tagasi kliendile:
        •     ch.basic_publish(exchange='',
                               routing_key=props.reply_to,
                               properties=pika.BasicProperties(correlation_id = \
                                                                   props.correlation_id),
                               body=str(response))
        • routing_key väärtuseks seame selle sõnumi saatnud kliendi unikaalse järjekorra nime, mille saame kätte läbi Properties tüüpi props muutuja nii props.reply_to. Selle reply_to väärtus seadistatakse kliendi programmis, ning pannakse sõnumiga kaasa. Tänu sellele teab meie server automaatselt kuhu tulemus tagasi saata.
    3. if __name__ == _main_: meetod:
      • broker_port väärtus peaks olema see port, mida te saite eelmise praktikumi käigus (56YZ) ning mille ka kliendi rakenduses seadistasite.
      • queue väärtuseks seadistake funktsiooni nimi, mida see server serveerib.
        • See peab olema sama mis kliendi pool on seadistatud routing_key väärtuseks!
      • Loome ühenduse:
        •     connection = pika.BlockingConnection(
                  pika.ConnectionParameters(host=broker_host, port=broker_port, credentials=credentials, virtual_host= "hspraks03"))
          
        • virtual_host on siin varasemalt loodud virtuaalse keskkonna nimi, sama mis kliendi koodis
        • Ka ülejäänud väärtused on samad eelmise praktikumi ja kliendi koodis kasutatavatele väärtustele.
      • Loome uue kanali ning asume kuulama sisse tulevaid sõnumeid:
    channel = connection.channel()
    channel.queue_declare(queue=queue)
    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue, on_message_callback=on_request)
  • Iga sisse tuleva sõnumi peal sellesse järjekorda kutsutakse välja on_request() meetod.

Ülesanne 3.4: RPC lahenduse testimine

Testige, et õnnestub Nii serverit kui ka klienti tööle panna

  1. Pange paika Keskkonna muutujad parooli ning kasutajanime jaoks mõlema programmi jaoks!
    • PyCharm programmis saate seda teha Run Configurations vormi kaudu Environment Variables välja kaudu
    • Linux Käsureal: Enne programmi jooksutamist saate muutujaid paika panna nii: export MUUTUJA=VÄÄRTUS
    • Windows käsureal: Enne programmi jooksutamist saate muutujaid paika panna nii: set MUUTUJA=VÄÄRTUS
  2. Käivitage kõigepealt server
  3. Seejärel käivitage klient
  4. Kontrollige, et ei teki kummaski veateateid.
    • Klient peak suhteliselt kiiresti tulemuse tagastama ning programmist väljuma.
  • Tehke ekraanivaated olukorrast kus on näha, et õnnestus nii serveri kui klienti korrektselt käivitada

Lahenduse esitamine

Praktikumi lahendusena tuleb esitada:

  1. Kood ja näidisväljundid (teksti või ekraanivatena) loodud programmidest 3.2 ja 3.3 ülesannetes
  2. Ekraanivaated ülesandes 3.4
  3. Failid tuleks kokku pakkida üheks Zip failiks enne üles laadimist.
You must be logged in and registered to the course in order to submit solutions.

Võimalikud probleemid ja nende potentiaalsed lahendused.

  • Kui saate veateate pika.exceptions.IncompatibleProtocolError: StreamLostError: ('Transport indicated EOF',)
    • Siis tuleks kontrollida kas kasutate õiget porti (56YZ) (Ei tohi kasutada adminisitreerimise veebiliidese porti)
  • Kui klient jääb ootama ning ei paista midagi tagastavat:
    • Uuriga RabbitMQ administreerimise liideses, kas ja kuhu (Exchange, queue) andmed kohale jõuavad
    • Kontrollige üle kas marsruutimise võtmed ja queue väärtused on korrektsed.
    • Kontrollige üle, et exchange väärtus on koodis tühi sõne ("")
  • Institute of Computer Science
  • Faculty of Science and Technology
  • University of Tartu
In case of technical problems or questions write to:

Contact the course organizers with the organizational and course content questions.
The proprietary copyrights of educational materials belong to the University of Tartu. The use of educational materials is permitted for the purposes and under the conditions provided for in the copyright law for the free use of a work. When using educational materials, the user is obligated to give credit to the author of the educational materials.
The use of educational materials for other purposes is allowed only with the prior written consent of the University of Tartu.
Terms of use for the Courses environment