1
0

make it short
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2020-05-12 13:43:57 +02:00
parent 517e6d5d22
commit 3080431fc3
4 changed files with 38 additions and 27 deletions

View File

@@ -1,8 +1,8 @@
% !TeX root = ../thesis.tex
\chapter{Az elvégzett munka és eredmények ismertetése}
\section{Az elvégzett munka és eredmények ismertetése}
\label{sec:second}
\section{Rendszer tervezése}
\subsection{Rendszer tervezése}
A \ref{fig:birbnetes-architecture} ábrán látható architektúrát logisztikai okokból kifolyólag a mesterséges intelligenciát megvalósító szoftver ismerete nélkül alkottuk. Úgy tekintettünk rá, mint egy fekete dobozra, amely képes fájlokat beolvasni valamilyen módon és a vizsgálat eredményét is közli a felhasználóval valamilyen módon. Fontos szempont volt, hogy az egyes mikroszolgáltatások belső működése tetszőlegesen refaktorálható legyen anélkül, hogy az másik komponensben módosítást tenne szükségessé.
Jelenleg a rendszer csővezetékként működik, egyik végén beérkeznek a bemeneti adatok, amin a mesterséges intelligencia klasszifikációt hajt végre, majd ennek az eredményét továbbítja a kimenetet feldolgozó szolgáltatások felé, akik a pipeline másik vége.
@@ -16,20 +16,20 @@ Jelenleg a rendszer csővezetékként működik, egyik végén beérkeznek a bem
A rendszer tervezésekor célunk volt a bővíthetőség minél jobb támogatása, ezért megadtuk a lehetőségét annak, hogy a beérkező hangfájlt több mesterséges intelligencia is megvizsgálja párhuzamosan, az ilyen lehetséges elágazási pontokon üzenetsort használtunk. Így, ha a jelenleg egyenes pipeline-t szeretnénk leágaztatni, a megfelelő helyekre fel kell iratkoztatni az új komponenseket. Lentebb olvashatók részletesen az általam javasolt komponensek.
\subsection{Input Service}
\subsubsection{Input Service}
Fogadja a bemeneti hangfájlokat, ezeket továbbítja a hosszú idejű tárolást megvalósító Storage Service felé. Ezen felül ellátja egy egyedi azonosítóval is és minimális validációt végez.
Kapcsolódik egy relációs adatbázishoz, amelyben lementi az információkat, amelyeket fogadott a hangfájllal együtt. Ezeket összerendeli az egyedi azonosítóval, amelyet ő adott a hangfájlnak.
Miután a Storage Service lementette a hangfájlt, a service publikál egy üzenetet az üzenetsorba, amely tartalmazza a mentett hangfájl címkéjét. A feliratkozott komponensek ezekután a tag használatával letölthetik a lementett hangot és folytathatják rajta a feldolgozást.
\subsection{Independent Results Service}
\subsubsection{Independent Results Service}
Feldolgozza a mesterséges intelligencia kimenetét, letárolja azt egy tetszőleges relációs adatbázisban. Lekérdezhető tőle - egymástól függetlenül - az egyes hangfájlokról hozott döntés. Az itt tárolt adatok összevethetők az Input Service-ben található adatokkal. Ez segíthet a hiba keresésben, valamint az itt található adatok segítségével a rendszerbe tanulás illeszthető.
\subsection{Results Statistics Service}
\subsubsection{Results Statistics Service}
Feldolgozza a mesterséges intelligencia kimenetét. Az eredményeket egy idősoros adatbázisban tárolja le. Ez az adatbázis sokkal alkalmasabb és hatékonyabb az eredmények "mérés" szerű kezelésén, de cserébe nem lehet lekérni tőle egyesével a hangfájlokról hozott döntéseket. Használata lehetővé teszi dashboardok készítését, ahol heat-map vagy más grafikonok segítségével tájékozódhat a felhasználó.
\section{API-k tervez\'ese}
\subsection{API-k tervez\'ese}
Mivel a projekten ketten dolgoztunk, fontos volt számunkra az egyes szolgáltatások API-jainak definiálása. Erre Swagger-t használtunk, ami egy jól dokumentált, nyitott definíciós eszköztár RESTful API-k leírására. Itt lényeges volt számomra, hogy az elvárt bemeneti formátumon felül minden lehetséges visszatérési státusz kódja és üzenetformátuma dokumentálva legyen az általam fejlesztett szolgáltatásoknak, ugyanis ez megkönnyíti a fejlesztést és a lehetséges félreértéseket is elkerüli. A rendszerben bevezettük a címkék vagy tagek fogalmát, amely egyedi azonosítója minden beküldött hangfájlnak. Az egyes tagekhez tárolt metaadatokat is le lehet kérdezni egy endpoint segítségével.
Az Input Service API-ján kifejezetten sokat gondolkodtam, ugyanis a fájlok és az azokat kísérő metaadatok fogadására több alternatíva létezik. Állományok feltöltése miatt adódik a http mulipart form használata, viszont a metaadatok kerülhetnek külön részbe a kérésnek, vagy egybe valamilyen JSON formátumú adatstruktúrában. Végül az utóbbi mellett döntöttem, ugyanis Pythonhoz rendkívül kiforrott JSON sémavalidációs könyvtárak érhetők el, ezzel szemben ilyen eszközt, ami elegánsan képes multipart formok sémáját validálni, nem találtam.
@@ -38,12 +38,12 @@ A Results Statistics Service nem szolgál ki REST-es API-t, csupán fogadja a me
Ez előbbivel szemben az Independent Results Service egyik legfontosabb tulajdonsága, hogy egy REST API-t nyújt. Itt kihasználva a relációs adatbázis által nyújtott lehetőségeket definiáltam olyan végpontokat, melyek visszaadnak minden pozitív vagy negatív eredményt, valamint adott dátum előtt, illetve után rögzített eredményeket. A cél az volt, hogy le lehessen kérdezni azegyes hangfájlokhoz tartozó adatokat, és ezt egy olyan endpoint segítségével lehet megtenni, amelyben a hangfájl tagje alapján azonosítható ez be.
\section{Fejleszt\'es folyamata}
\subsection{Fejleszt\'es folyamata}
Fejlesztés során igyekeztem arra figyelni, hogy az általam írt kód helyes legyen, ezért a projekthez beállítottam egy folyamatos integrációs rendszert, amely minden git commitra lefuttatott teszteket, és amennyiben a kód átment ezeken a tesztken, container image-et épített és publikált az általam beállított container registry-be. Később a Kubernetes rendszerbe is innen kerültek be az egyes mikroszolgáltatások.
Az egyes komponensek futásakor keletkező kivételeket és hibaeseményeket egy központi rendszerben gyűjtöttük, ami képes volt kimutatások készítésére és egyes eseményekről értesítések küldésére. Mivel a rendszer Kubernetesben futott, jelentősen megkönnyítette a hibakeresési folyamatot, hogy a rendszer képes volt rámutatni arra a kódsorba, amely a hibát kiváltotta, valamint az aktuális környezetet és a hibaüzenetet is tárolta.
\subsection{Input Service}
\subsubsection{Input Service}
Az Input Service implementálásához a Flask nevű Python web mikroframeworköt használtam. A Flask csak a webes rétegét valósítja meg egy alkalmazásnak, ORM-et (Object-relation mapping) vagy validációt nem nyújt a fejlesztőknek, viszont egyszerűen kiegészíthető tetszőleges beépülő modulokkal. Ebben a mikroszolgáltatásban viszont szükség volt adatbázissal történő kommunikációra és a kapott adatok sémájának validációjára.
Előbbire az SQLAlchemy nevű könyvtárat használtam, melynek kényelmes Flask-os pluginja van. Emiatt csupán definiálnom kellett az általam használt sémát, megadni a Flask-nak az adatbázis elérési helyét, ez után tetszőleges metódusban lehetett lekérdezni, beilleszteni és frissíteni rekordokat az adatbázisba.
@@ -66,7 +66,7 @@ A választás végül a RabbitMQ-ra esett, amely egy Erlang nyelven készült, n
A metaadatok validációjára Marshmallow-t használtam. Ez a könyvtár képes előre definiált séma alapján JSON-ből betölteni adatokat, valamint szerializálni őket. A fejlesztés során előkerült egy olyan probléma, hogy az SQLAlchemy segítségével lekérdezett rekordokat a Flask nem tudta automatikusan JSON-ba szerializálni a Python beépített szerializálójával. Erre is megoldást jelentett a Marshmallow, ugyanis létezik egy Marshmallow-SQLAlchemy nevű könyvtár, amely definiál olyan SQLAlchemy sémaosztályokat, amiket a Marshmallow képes JSON-be szerializálni és betölteni.
\subsection{Independent Results Service}
\subsubsection{Independent Results Service}
A mikroszolgáltatás architektúra lehetővé teszi divergens technológiák együttműködését. Ezt kihasználva az Independent Results Service mikroszolgáltatást nem Python, hanem Kotlin nyelven írtam. Ez azt jelentette, hogy a teljes eszköztár, melyet megismertem nem voltak használhatók e komponens fejlesztése esetében, viszont utóbbi programnyelvben elérhető coroutine-ok olyan előnyt jelentettek, ami miatt megérte megtanulni az új eszköztár használatát. Például a Kotlin esetében a webes logika megvalósítására a legnépszerűbb könyvtár a Ktor, melynek szolgáltatáskészlete hasonlít a Flaskhoz.
A Kotlin egy a Java Virtual Machine-t használó modern programnyelv, amelynek célja a Java hiányosságait, hátrányait javítani. A Java-hoz képest a legnagyobb különbség a null-safe viselkedése és a coroutine-ok használata. Utóbbi használatával könnyedén fejleszthető nagy teljesítményű alkalmazást. Mivel a Kotlin egy fiatal nyelv, valamint leginkább Android appok fejlesztésére használják, így az egyes könyvtárak nem feltétlen olyan fejlettek, mint a Python esetében. Ilyen volt például az általam használt ORM megoldás, az Exposed. Ennek előnye, hogy jól illeszkedik a kotlinos programozási paradigmákhoz, viszont nem képes connection poolingra másik library-k használata nélkül, a Postgresql-t viszont natívan támogatja.
@@ -77,7 +77,7 @@ A Kotlin használata akkor fizetődött ki, miután a REST API-t kiszolgáló r
A mikroszolgáltatás fejlesztése során sok időt töltöttem az adatbázis réteg fejlesztésével, mert nehézkesen tudtam csak működésre bírni az Exposed könyvtárat a connection poolinggal és a JSON szerializációval.
\subsection{Result Statistics Service}
\subsubsection{Result Statistics Service}
Timeseries adatbázist a rendszerben csak ez a mikroszolgáltatás használ, így ennek kiválasztása ezen komponens fejlesztése során történt. A kiválasztás során a szempontok csak a mikroszolgáltatás saját szempontjai voltak. Próbáltam kiválasztani a lehető legegyszerűbb megoldást, ugyanis nincs szükség például komplex adatstruktúrák támogatására, viszont a retention policy-k használatának lehetősége és a nagy teljesítmény követelmény volt.
Először a Prometheust vizsgáltam meg, amely egy népszerű timeseries adatbázis rendszer, amit főleg metrikák tárolására használnak. Emiatt támogatja a retention policy-ket, viszont nagy erőforrás lábnyomba van és a lehetőségeinek kis százalékát tudnám csak kihasználni.
@@ -90,7 +90,7 @@ A Result Statistics Service mikroszolgáltatást először C\# nyelven kezdtem e
E mikroszolgáltatás esetében az üzleti logika eleve nem bonyolult, az üzenetsoron érkező üzenetben található adatot az aktuális idővel megcímkézve be kell illeszteni az InfluxDB-be. Ezt viszont szerettem volna aszinkron módon megtenni, ugyanis elképzelhető az üzenetsoron nagy számú üzenet érkezése rövid idő alatt. Ennek implementációját is elvetettem, ugyanis az InfluxDB, ahogy kutatásom során kiderült, olyan nagy számú kérést képes feldolgozni rövid idő alatt, hogy nem érné meg aszinkron logikával bonyolítani a mikroszolgáltatást \cite{influxdb-performance} .
\section{Kubernetes}
\subsection{Kubernetes}
Az általunk használt Kubernetes klaszter egy fizikai számítógépen futott négy virtuális gépen. A rendszerben egy Master node és három Worker node volt. A tárterületet ugyanerről a fizikai gépről osztottuk ki a fürt számára NFS-sel, a Persistent Volume-okat statikusan definiáltuk. Az általam fejlesztett mikroszolgáltatásokat és az azokhoz kapcsolódó komponenseket magam telepítettem a klaszterbe.
Az általunk fejlesztett rendszer számára létrehoztam egy Kubernetes névteret, ahova telepítettük az általunk fejlesztett mikroszolgáltatásokat és minden általuk használt komponenst.
@@ -117,12 +117,12 @@ Megvizsgáltam továbbáa Gloo-t, aminek különleges előnye, hogy képes autom
A választásom végül a Kong-ra esett, mert számomra szimpatikus volt, hogy egy egyszerű NGINX webszerver segítségével oldja meg funkcióit. A telepítést ez után az Ingress objektumok definiálásával és a klaszterbe telepítésével folytattam.
\section{Elkészült rendszer próbája}
\subsection{Elkészült rendszer próbája}
A mikroszolgáltatások fejlesztése közben önmagukban teszteltem őket és próbáltam ki működésüket. A fejlesztési folyamat végén viszont közösen kipróbáltuk, hogy működnek együtt az általunk fejlesztett komponensek, milyen hibák jönnek itt elő.
Előkerültek olyan hibák, amik eltérő feltételezésekből következnek. Ezen esetekben egyeztettük a konvencióink, majd a javítás után újra teszteltük a működést.
\section{\"Osszefoglal\'as}
\subsection{\"Osszefoglal\'as}
A félév során számos új tudással bővültem, többek között elsajátítottam a Kotlin nyelv alapszintű működését, valamint megtanultam, hogy kell mikroszolgáltatás alapú rendszert tervezni, fejleszteni és az ezek Kubernetesbe telepítésével kapcsolatos megontolásokat is részletesebben megismertem. Több technológia működésébe nyertem betekintést, ezzel tágítva az eszköztáram.
Elkészítettem több újra használható Kubernetes Deploymentet és a hozzájuk tartozó egyéb API objektumokat, ami a későbbi munkám során segítségemre lehet. Megterveztem és végrehajtottam az általunk fejlesztett komponensek automatikus Kubernetesbe telepítését és a frissítések automatikus elvégzését.