% !TeX root = ../thesis.tex
%----------------------------------------------------------------------------
\chapter{Alkalmazás komponensek dinamikus ütemezése}
\label{chapter:dynamic_scheduling}
%----------------------------------------------------------------------------

Az előző fejezetekben ismertetett, átalakított alkalmazások jól ki tudják használni a peremhálózati informatikai infrastruktúra adta lehetőségeket. Mint azt a \aref{sec:peremhalozati_rendszerek}.\ alfejezetben is ismertettem, a peremhálózati rendszerek és a hagyományos adatközpontok több dologban különböznek. Egyik ilyen különbség a telepítésük sűrűsége. Ez a tulajdonság lehetővé teszi, hogy a megvalósított alkalmazás szempontjából bizonyos szolgáltatásokat a felhasználókhoz \enquote{közel} futtasson. Ennek a \enquote{közelségnek} önmagában számos előnye tud lenni, mint például a csökkentett hálózati késleltetés és terhelés. Tipikusan a peremhálózati infrastruktúrákra jellemző, hogy a felhő végtelennek tűnő számítási kapacitásához képest erősen limitált erőforrások állnak rendelkezésre.

Könnyen beláthatjuk ezekből adódóan, hogy fontos szerepe van annak a kérdésnek, hogy egyes szolgáltatásokat mikor és melyik peremhálózati rendszeren futtatunk, vagy hogy megéri-e kihelyezni őket a felhő által nyújtott futtatókörnyezetből. Egy rosszul megválasztott szolgáltatás elhelyezés könnyen lehet, hogy az előnyök teljes ellentétét idézi elő megnövekedett költségek mellett. Mivel a peremhálózati rendszerek sokkal nagyobb számban állnak rendelkezésre és a helyes elhelyezés is kockázatos feladat, ezért az elhelyezési feladatokat minden esetben \enquote{kézzel} megoldani jelentős kihívást tud jelenteni.

Megoldást jelenthet a problémára ha az egyes szolgáltatás komponenseket automatikusan tudjuk peremhálózati infrastruktúrába kihelyezni. Egy olyan ütemező algoritmusra van szükség, amely képes kiválasztani az ideális futtatási helyet a megfelelő komponenseknek és automatikusan áthelyezni (azaz ütemezni) oda. Így nincs szükség emberi beavatkozásra a megfelelő peremhálózati adatközpont kiválasztásához.

A dinamikus ütemezés több kérdést és problémát is felvet, hiszen nem egyértelmű, hogy melyik alkalmazás szempontjából mi számít ideális környezetnek. Illetve, ha tudjuk, hogy mi számít ideális környezetnek, hogy tudjuk felmérni, hogy melyik környezet lehet ideális jelölt az alkalmazás futtatására.

Ebben a fejezetben megvizsgálom a dinamikus áthelyezés megvalósításának lehetőségét a korábban ismertetett alkalmazásokon, illetve egy egyszerű megoldást is tervezek, amely a probléma megoldását mutatja be.

\section{Alkalmas felhő keretrendszer kiválasztása}
\label{sec:cloud_framework}


\Aref{sec:frameworks}.\ alfejezeteben több keretrendszert is megvizsgáltam. Ezek közül a \textit{KubeFed}-et választottam.

A kiválasztásnál elsősorban azt vettem figyelembe, hogy milyen lehetőségeket adnak az egyes keretrendszerek a szolgáltatások dinamikus átütemezésére felhő és perem, illetve perem és perem adatközpontok között.

A \textit{KubeFed} mellett a \textit{Kubeedge} volt a másik keretrendszer, amely ideálisnak tűnt, ám mélyebb vizsgálatot követően elvetettem. Ennek oka a korábban is ismertetett hiányosságai és kezdetleges állapota volt. 

Az \textit{EdgeX Foundry} és \textit{Porject EVE} használatát korán elvetettem. Tipikusan erős különbségeket feltételeznek a perem és a felhő adatközpontokkal szemben támasztott elvárásoktól. Emiatt olyan megoldásokat kínálnak, amelyek teljesen más igényeket próbálnak kielégíteni, mint amiket az én eredeti problémafelvetésem támaszt. Emiatt ezeknek a megoldásoknak a használata csak felesleges nehézségeket jelentene.

A megvizsgált \acrshort{paas} rendszereket azért nem szerettem volna használni, mert célom volt egy teljesen nyílt megoldás készítése, ami nyílt szoftverekre épül és nem függ egy konkrét megoldástól, továbbá így előfizetésre se volt szükségem.

A \textit{KubeFed} saját ütemezőt nem implementál (mint ahogy egyik másik vizsgált megoldás sem). Viszont az általa megvalósított egységes vezérlő felületnek köszönhetően nagyon könnyen képesek vagyunk az egyes komponenseket adatközpontokra mozgatni, így könnyen tudunk olyan saját ütemezőt készíteni, ami megvalósítja a feladatot. Emiatt választottam ezt a keretrendszert és azt, hogy saját ütemezőt készítek.

\section{Szolgáltatás létesítés és mozgatás \textit{KubeFed} környezetben}

Konténerizált alkalmazás környezetben egy futó konténer mozgatása csak korlátozott értelemben lehetséges. Mivel az alkalmazás nem egy virtualizált hardveren, hanem magán a hoszt operációs rendszeren fut egy konténerizált környezetben, így nincs egyszerű mód arra, hogy egy alkalmazást a memória tartalmával együtt mozgassunk, úgy, hogy az egy másik hoszton ugyanúgy tudja folytatni a működését. 

Ezért az áthelyezés az adott konténer leállítását és egy másik hoszton (másik klaszterben) való elindítását jelenti. Ez állapotmentes szolgáltatásoknál nem jelent nagyobb problémát, hiszen nincs belső állapot amit meg kell őrizni a mozgatás során. Belső állapottal rendelkező alkalmazások esetén viszont ez komplex problémát is jelenthet akár. 

Állapotmentes szoftverek esetén lehetőségünk van arra, hogy a konténerek \enquote{mozgatása} alatti kieséseket minimalizálhatjuk azzal, hogy az új konténereket előbb indítjuk el, mint hogy a régit leállítanánk. Ez idő alatt lehetőség van a még futó kéréseket befejeznie a leállítandó alkalmazásnak, miközben az új kérések már az újonnan indított alkalmazáshoz érkeznek. Egy ilyen átterheléses áthelyezés időbeni lefutását mutatja be \aref{fig:workload_move}.\ ábra. Ideális esetben egy ilyen mozgatás teljes mértékben szolgáltatás kiesés nélkül megoldható.

\begin{figure}[h!]
	\centering
	\includegraphics[width=0.7\textwidth]{figures/workload_move}
	\caption{Állapotmentes alkalmazás mozgatása \enquote{A} hosztról \enquote{B} hosztra.}
	\label{fig:workload_move}
\end{figure}

Az átterheléses mozgatás belső állapottal rendelkező alkalmazások esetén nem könnyen oldható meg, hiszen a belső állapot szinkronizálása komoly feladat és többnyire nem is oldható meg az alkalmazás közreműködése nélkül.


Az alkalmazások leállítását és másik klaszterben való elindítását a \textit{KubeFed} teljes mértékben támogatja. Az összes federált \acrshort{api} objektum esetén lehetőséget ad arra, hogy kiválasszuk, hogy melyik klaszterben hozza létre. De még arra is lehetőséget nyújt, hogy bizonyos tulajdonságait az objektumoknak klaszterre szabva változtassuk meg. 

Ezeknek a konstrukcióknak a segítségével az ütemező szoftvernek csak egy \acrshort{api} hívást kell intéznie a \textit{Kubernetes} \acrshort{api}-hoz, és ezzel meg tudja változtatni az ütemezést. A fentebb vázolt átterheléses mozgatást magától nem tudja megvalósítani a \textit{KubeFed}, de megfelelő \acrshort{api} hívásokkal ez is megoldható.

\section{Alkalmazás komponensek dinamikus ütemezésének vizsgálata}

Egy alkalmazás komponens dinamikus ütemezésének megvalósítása nagyon sok esetben támogatást igényel az alkalmazástól. Annak eldöntése, hogy mikor ütemezzük a komponenseket, hova, és mit nyerünk az ütemezéssel, mind-mind az alkalmazás saját tulajdonságaitól és belső működésétől függ. 

Emellett a konkrét ütemezés megvalósítása is erősen függ az alkalmazás tulajdonságaitól,  működésétől.

A következőkben a korábban bemutatott alkalmazásokat fogom megvizsgálni abból a szempontból, hogy ezeket a problémákat hogyan lehet megoldani, illetve milyen támogatásra van szükség az alkalmazástól.

\subsection{Intelligens madárhang felismerés}

Ebben az alkalmazásban a peremhálózati adatközpontba egy előszűrést megvalósító komponens kerül. Ennek a komponensnek a feladata, hogy a sok \acrshort{iot} eszköz által feltöltött hangminták által generált hálózati terhelést csökkentse azzal, hogy intelligens felismerést futtatva csak a releváns hangmintákat küldi tovább.

Ez a komponens állapotmentes, két kérés teljesítésének eredménye egymástól teljesen független. Ennek köszönhetően könnyen skálázható több példányra, hogy képes legyen nagy mennyiségű klienst kiszolgálni. Mivel a peremhálózati adatközpontokban -- a felhőhöz képest -- általában korlátozottan állnak csak rendelkezésünkre erőforrások, ezért nem tudjuk tetszőlegesen skálázni a feldolgozó szolgáltatásunkat. 

Előfordulhat olyan helyzet, amikor a peremhálózat kifogy a számítási kapacitásból. Ilyen esetben is szeretnénk legalább annyi terhelést megtartani a használt peremhálózati adatközpontban, amennyit az teljesíteni képes, a fennmaradó terhelést pedig szeretnénk átütemezni egy másik peremhálózati adatközpontba vagy végszükségben a felhőbe. Ezzel annyi sávszélesség kihasználtságot lehet megtakarítani, amennyire csak képesek vagyunk.

\subsubsection{Ütemezési döntés meghozása}

Ebben az alkalmazásban azt szeretnénk megvalósítani, hogy ha egy adatközpontban fogytán van a számítási kapacitás, akkor más adatközpontokhoz tudjunk fordulni a feladataink végrehajtásával. Ebből következik, hogy szükségünk van arra, hogy mérjük egy adatközpont terheltségét. 

A futó előszűrő szoftver komponens teljesítőképességéről egy jó jellemző a várakozási sorának hossza. \Aref{sec:prefilter_service_implementation}.\ alfejezetben ismertetettek szerint a szolgáltatás fenntart egy várakozási sort, ahol a feldolgozásra váró adatokat állítja sorba. Ideális esetben, ha miden beérkező kérést időben el tud látni, akkor ennek a sornak a hossza stabil 1 körüli érték. Ha a szolgáltatás teljesítőképessége végéhez közeledik, akkor elkezdenek felgyűlni a feladatai, ezáltal a sorhossz monoton növekedésnek indul.

 Ahhoz, hogy gyűjteni tudjuk a futó szolgáltatások belső sorhosszát, támogatásra van szükség az előszűrő szolgáltatástól.

\subsubsection{Ütemezés megvalósítása}

Mivel az előszűrő szolgáltatás állapotmentes működést valósít meg, ezért könnyedén lehet mozgatni az egyes adatközpontok között, illetve több példányban is futtatni egyszerre.

Az \acrshort{iot} eszközök egy előre beállított címre küldik a hangmintákat. Ez a cím az egyes adatközpontoknál más és más lehet. Mivel a szolgáltatásokat adatközpontok között mozgatjuk, ezért támogatásra van szükség az eszközök részéről is, hogy dinamikusan meg tudjuk változtatni a küldés célját.


\subsection{Robot vezérlés}

A felhő alapú robotkarok alkalmazásánál a peremhálózati adatközpontba egy vagy több alacsony szintű mozgást vezérlő komponens kerülhet. Ezek egymással egy osztott memóriát megvalósító \textit{Redis} adatbázison keresztül kommunikálnak. Ezek a komponensek belső állapottal rendelkeznek. Létrehozásukkor megkezdik a hozzájuk rendelt \textit{program} letöltését és futtatását. Ha a \textit{program} véget ért, akkor a komponensek kilépnek.

\subsubsection{Ütemezési döntés meghozása}

Ebben az alkalmazásban annak a megállapítása, hogy milyen logika alapján lehet eldönteni, hogy hol futtassuk az alkalmazásunkat jelentősen egyszerűbb: A valósidejű vezérléshez az elérhető legkisebb késleltetést kell elérnünk. Ahhoz, hogy meg tudjuk állapítani, hogy melyik az a peremhálózati adatközpont, amely ilyen tulajdonságokkal rendelkezik, ismernünk kell a robotkarokat tartalmazó telephely és az összes számításba jövő peremhálózati adatközpont közötti késleltetést.

Ha ezt ismerjük, akkor egy egyszerű minimum függvényt használva, ki tudjuk választani az ideális futtatás helyét.

\subsubsection{Ütemezés megvalósítása}

A vezérlést megvalósító komponens belső állapottal rendelkezik, futás közbeni átütemezése ezért nem megvalósítható. A robotkarok mozgatása nem engedhet meg kiesést, hiszen a vezérlés elvesztése akár katasztrofális következményekkel is járhat. A belső állapottal rendelkező komponensek áthelyezése kiesés nélkül viszont komplex feladat.

Mivel \aref{sec:edge_layer_plans}.\ alfejezetben kikötöttük, hogy minden programnak biztonságos állapotba kell helyeznie a robotkarokat lefutása végén, illetve ebből az ismert állapotból kezdje meg a vezérlést, ezért lehetőségünk van arra, hogy két lefutás között helyezzük át a programot. 

Az áthelyezés így jelentősen leegyszerűsödik, hiszen csak arra van szükség, hogy a vezérlő komponenseket a megfelelő adatközpontban indítsuk el.

A vezérlést megvalósító szolgáltatás komponensek indításáért ebben az alkalmazásban külön szolgáltatás felel, ezért ez az a szoftverkomponens, amelynek támogatnia kell a dinamikus ütemezési döntések alkalmazását. 

\section{Ütemező rendszer}
\label{sec:scheduler}

Bár a két alkalmazás működése és igényei jelentősen eltérnek, szerettem volna egy olyan rendszert megalkotni, amelynek segítségével mindkét alkalmazás ütemezése megoldható. A szoftver tervezése során figyelembe vettem azokat a közös funkcionalitásokat, amelyeket mindkét alkalmazás egyformán használ. Emellett szétválasztottam azokat a komponenseket, amelyek alkalmazás specifikus funkciót valósítanak meg.

\subsection{Metrikák gyűjtése és kiértékelése}

Mindkét alkalmazásban közös, hogy az ütemezési döntéseket az alakhamzásból gyűjtött metrikákra alapozza. Ezek a metrikák, bár eltérő tulajdonságokat írnak le, gyűjtésük és kiértékelésük szempontjából nem különböznek egymástól.

A gyűjtött metrikák minden esetben idősoros adatként kezelhetőek. Az idősoros adatok olyan mérések, amelyek meghatározott időközönként rögzítésre kerülnek. Egy rögzített adatpont mindig időhöz kötötten reprezentálja a megfigyelt pillanatnyi állapotot \cite{timeseries_basics}. Az alkalmazásaink állapotát idősoros adatként gyűjtve képesek vagyunk a döntési logika felépítésénél többfajta statisztikai kiértékelést is a döntések alapjául venni.

A metrikák gyűjtésére és kiértékelésére így egy központi megoldást terveztem. Gyűjtés során az egyes alkalmazás komponensek vagy mérő szoftverek elküldik a központi rendszerbe, amely idősorosan tárolja az adatokat. Ha egy ütemezési döntést végző szolgáltatásnak szüksége van arra, hogy a rögzített adatokon készített kiértékelést használja (például átlagolt értéket egy meghatározott időtartamra), akkor innen le tudja kérni.

Ezt a szolgáltatást mindkét alkalmazás egyformán tudja használni.

\subsection{Ütemezési algoritmus}
\label{sec:scheduling-algo}

Bár a robotkarokat vezérlő alkalmazásnál az ütemezést megvalósító algoritmus meghatározott fix időpontokban egy egyszerű minimum keresés a madárhang felismerő rendszer esetén, ennél összetettebb megoldásra van szükség. 

Ebben az esetben nem csak a konténerek ütemezésére van szükség az egyes adatközpontok között, hanem arra is, hogy az \acrshort{iot} eszközök konfigurációját is frissítsem. Emellett az ütemezési események generálása sem előre meghatározott. Az algoritmusnak folyamatosan figyelnie kell a rendszer állapotát és szükség esetén be kell tudnia avatkozni.

Egy ilyen viselkedést megvalósító naiv algoritmust terveztem, amely a próbálgatás módszerével keresi a szolgáltatások megfelelő elosztását a peremhálózati adatközpontok és a felhő között, és az ezekhez kapcsolódó \acrshort{iot} eszközök között.

Ahhoz, hogy a folyamatos felügyelet megvalósuljon, egy periodikusan futó algoritmust terveztem, amely rögzített időközönként felméri a rendszer állapotát és szükség esetén képes szolgáltatásokat mozgatni és konfigurációt frissíteni az eszközökön. 

Az algoritmus periodikus futása során fel kell tudnia mérni, ha kedvezőtlen rendszer állapot áll fenn és döntést kell hoznia annak megoldása érdekében. A madárhang elemző rendszer esetében ilyen kedvezőtlen állapot, ha a komponensek belső sorhossza monoton növekedésnek indul. Ilyen helyzetben a rendszer működése instabil. Stabilnak azt az állapotot tekinthetjük, amikor a sorhossz csökken, vagy konstans értékhez közelít.

A sorhossz növekedésének detektálásához kihasználtam az idősoros adatokon végezhető kiértékelési lehetőségeket. Az algoritmus periodikus futása során az elmúlt időszak (konfigurálható időre visszamenően) deriváltját kérdezi le. Ebből adódóan, ha a derivált értéke nagyobb mint 0, akkor feltételezhető az instabil állapot, 0 és annál kisebb értékek esetén a rendszer stabilnak mondható.

Ha az algoritmus többszöri futás esetén is nullánál nagyobb értéket kap a sorhossz deriváltjára, akkor megkezdi a javító folyamatot. Ez a folyamat egy kiválasztott eszköz által küldött adatokat irányítja át másik felhőbe. Mielőtt frissíti az eszköz konfigurációját, ellenőrzi hogy az új cél-adatközpontban fut-e a szolgáltatás egy példánya. Ha nem, akkor előbb elindítja azt, és miután az készen áll az adatok fogadására, csak akkor ütemezi át a a küldést.

Ez a viselkedés hasonlít a korában ismertetett átterheléses mozgatásra. Azaz, ha mozgatni kell, akkor csak azután teszi meg, hogy az \enquote{új} szolgáltatás készen áll, ez idő alatt a \enquote{régi} szolgáltatás dolgozza fel a kéréseket, így kiesés nélkül vihető véghez a szolgáltatások mozgatása.

A jelenlegi megoldásomban egy fix rangsort használ annak eldöntése, hogy melyik adatközpontba kezdje el átütemezni a terhelést az algoritmus. A működése során egy előre rögzített listán minden egyes lehetőséget megvizsgál stabilitás szerint és ez alapján választja ki az ideális jelöltet. 

Ilyen szintű naiv megoldás szuboptimális eredményt hozhat, hiszen könnyen belátható, hogy hajlamos a vibrációra, azaz amikor egy terhelést folyamatosan oda-vissza ütemez két adatközpont között. Ez akkor fordulhat elő, ha egy adatközpont működése stabil, de plusz egy egységnyi terhelés (esetünkben egy \acrshort{iot} eszköz által küldött hangminták) már instabillá teszi.

Ennek a jelenségnek az elkerülésére az algoritmus megjelöli, ha egy adatközpontban instabil működés miatt el kellett mozgatnia onnan terhelést. Ez a jelölés egy idő után lejár, ideális esetben azután, hogy a rendszer ismét elérte a stabil állapotot. Mivel a stabil állapot nem vezet átütemezéshez, ezért itt már nincs jelentősége a jelölésnek.

Átütemezés után az újonnan indított szolgáltatás is automatikusan elkezdi küldeni a belső állapot információit, az ütemező algoritmus pedig automatikusan elkezdi figyelemmel kísérni a változásokat. Ezek után kezdődik elölről az algoritmus futása.

\subsection{Kommunikációs interfész}

Úgy terveztem, hogy az ütemező rendszerrel kívülről \acrshort{http} \acrshort{api} segítségével lehessen kommunikálni. A rendszer megvalósít interfészeket a metrikák beküldésére és kiértékelésére. Emellett az \acrshort{iot} eszközök esetében egy táblázatot tart fenn arról, hogy melyik eszközt melyik adatközponthoz rendeli. 

Azt, hogy ennek a táblázatnak a tartalmát hogyan szinkronizáljam az eszközök beállításaival, két megoldást vizsgáltam meg. Ez a két megoldás a \textit{push} (amikor az algoritmus direktben értesíti az eszközöket) és a \textit{pull} (amikor az eszközök periodikusan kérdeznek le információt). 

Míg a \textit{push} alapú megoldás megoldás esetén a rendszer azonnal képes lehet értesíteni az eszközöket, sokkal komplexebb megoldást igényel, hiszen kezelni kell azokat a hiba lehetőségeket, amelyek felmerülhetnek a kommunikáció során és biztosítani, hogy ezeknek ellenáll az információ továbbítás.

Ezzel szemben \textit{pull} alapú megoldás esetén az eszközök ezt az információt működésük során periodikusan lekérhetik, és ennek megfelelően állíthatják át küldésük célcímét. Ebben az esetben a két lekérdezés között eltelt idő miatt nagyobb késleltetéssel értesülnek a változásról az eszközök, hiszen a táblában változott bejegyzésről csak a következő lekérésben tudnak értesülni. Emellett a folyamatos periodikus lekérdezés felesleges terhelést is jelent az ütemező rendszer számára, hiszen akkor is teljesítenie kell a kéréseket, ha nem változott semmi a konfigurációban. Cserébe ebben az esetben nem okoz nagy problémát, ha egy frissítés nem jut el az eszközhöz, vagy a frissítés pillanatában éppen nem elérhető az eszköz. A folyamatos lekérdezés miatt idővel konvergálni fog a helyes konfigurációhoz. 

A konfiguráció leküldéséhez a periodikus lekérdezést választottam. Ennek oka az, hogy implementációja jelentősen könnyebb, mint az értesítési mechanizmus esetén. Emellett a konfiguráció változtatás nem időérzékeny: az átterheléses mozgatás miatt bizonyos mértékű késleltetés nem okoz problémát. 

\subsection{Rendszer implementáció}

Az ütemező rendszerem megvalósítását \textit{Kubernetes} környezetben futtatható mikroszolgáltatás architektúrára terveztem. A rendszer vázlatos felépítése \aref{fig:turbomemer}.\ ábrán látható. Az egyes szolgáltatások és egyéb szoftver komponensek implementációját a következő alfejezetekben részletezem.

\begin{figure}[h!]
	\centering
	\includegraphics[width=0.5\textwidth]{figures/turbomemer-legit}
	\caption{Ütemező rendszer szolgáltatásainak áttekintése}
	\label{fig:turbomemer}
\end{figure}

\subsubsection{Mérési adat kezelő komponens}
\label{sec:birb-latency-collector}

Ez a szolgáltatás egy kívülről is elérhető interfészt valósít meg. Feladata a rendszer állapotát leíró mért adatok gyűjtése és azokról kiértékelések szolgáltatása. Ennek megvalósítására egy idősoros adatbázist használ. Az általam választott idősoros adatbázis az \textit{InfluxDB}.

Azért választottam az \textit{InfluxDB}-t, mert egy hatékonyan működő adatbázis sok hasznos funkcióval. Ilyen például a 2-es verzió óta beépített adatvizualizáció, így közvetlenül lehet a szoftvert arra használni, hogy a rögzített méréseket megtekintsük. Saját lekérdező nyelvén pedig sokféle adat aggregáció, transzformáció és kiértékelő funkcionalitás érhető el.

Új mérések érkezésekor a szolgáltatás eltárolja az információkat az adatbázisban. Ha szükség van kiértékelésre, akkor az \textit{InfluxDB} saját lekérdezőnyelvére fordítja a kérést, és az adatbázis szoftverben futtatja azt le, így hatékonyan és egyszerűen tudja megkapni a kiértékelt adatokat, amelyeket válaszul ad a kérésre.

Ezt a szolgáltatást a robotkarok vezérlését megvalósító alkalmazás közvetlenül tudja használni az ütemezési döntés meghozatalára.

\subsubsection{Ütemezés nyilvántartó komponens}
\label{sec:birb-scheduler-teller}

Ezt a szolgáltatás kizárólag az intelligens madárhang elemző alkalmazás használja. 

Ennek a szolgáltatásnak a feladata, hogy számontartsa az egyes eszközök jelenlétét illetve kiszolgálja számukra, hogy pillanatnyilag melyik adatközponthoz vannak rendelve. Az eszközök futásuk során ettől a szolgáltatástól tudják lekérni az ütemezési információikat. 

Ha a szolgáltatástól egy eddig ismeretlen eszköz kéri le az ütemezését, akkor azt egy dinamikusan megválasztott \enquote{alapértelmezett} adatközponthoz rendeli. Ezután ezt az ütemezési döntést elmenti, és innentől kezdve ugyanúgy van kezelve az új eszköz is, mint az összes többi.

A kiszolgált adatokat egy kulcs-érték adatbázisban tárolja. Ehhez \textit{Redis} adatbázist használtam, ennek oka az, hogy a \textit{Redis} támogatja az értékekhez lejárati idő rendelését. A lejárai idő leteltével az értékeket automatikusan törli. Ennek a segítségével számos funkcionalitást könnyebb volt implementálni. A \textit{Redis} támogatja továbbá az osztott memóriaként való funkcionalitást, amelyet kihasználva \aref{sec:birb-scheduler}.\ alfejezetben ismertetett szolgáltatással való kommunikációt megoldottam.

\subsubsection{Dinamikus újra-ütemező komponens}
\label{sec:birb-scheduler}

\Aref{sec:birb-scheduler-teller}.\ alfejezetben ismertetett szolgáltatás csak egy statikus hozzárendelést valósít meg az új eszközök és az adatközpontok között. Viszont ezek után nem változtatja meg a döntését. Ezeknek a döntéseknek a felülvizsgálatára és az \enquote{alapértelmezett} adatközpont dinamikus megváltoztatására szolgál ez a szolgáltatás.

Ez a szolgáltatás valósítja meg \aref{sec:scheduling-algo}.\ alfejezetben vázolt periodikusan futó ütemező algoritmust. 

Futása során a kiértékelt metrikákat lekérdezi a \textit{Mérési adat kezelő} szolgáltatásból. Majd ezek alapján és az osztott \textit{Redis} adatbázisban tárolt információk alapján meghozza az ütemezési döntést. Szükség esetén \textit{Kubernetes} \acrshort{api} hívásokkal elindítja a \textit{KubeFed} által kezelt szolgáltatást a megfelelő adatközpontban majd ezek után az ütemezési döntést rögzíti a az adatbázisban. Így legközelebb, amikor az eszköz frissíti a konfigurációját, már az újonnan indított szolgáltatáshoz küldi az információkat, ezzel megvalósítva a dinamikus átütemezést.

A szolgáltatás azt is ellenőrzi, hogy a kijelölt \enquote{alapértelmezett} adatközpont stabilnak számít-e. Ha nem, akkor ezt a beállítást is frissíti, így az új eszközök már másik adatközpontba kezdik el küldeni az adatokat.

Értelemszerűen ezt a szolgáltatást is csak az intelligens madárhang elemző alkalmazás használja.

\subsection{Link késleltetés mérése}

A robotkarokat vezérlő alkalmazás számára szükség van arra az információra, hogy az egyes adatközpontokkal milyen minőségű a link összeköttetése. 

Ennek a megvalósítására egy egyszerű szkriptet készítettem, amely leméri az összes adatközponttal szembeni késleltetést, majd ezeket elküldi \aref{sec:birb-latency-collector}.\ alfejezetben ismertetett szolgáltatás számára, amely így képes arról kiértékelést készíteni.

A késleltetés mérésére kézenfekvő megoldás lehet a hagyományos \acrfull{icmp} által biztosított \textit{Ping} kérésekkel mérni a körülfordulási időt. De ez nagyon limitált eredményt ad egy konkrét végponthoz. 

Szerettem volna egy olyan megoldást készíteni, amely nem csak az adatközpont határán lévő, publikus címmel rendelkező végponthoz tudja mérni a késleltetést, hanem közvetlenül az ott futó szolgáltatások és a végpont közti kapcsolatot tudja mérni. Ennek köszönhetően a mért késleltetés nem csak a publikus hálózat állapotáról, hanem az egyes adatközpontok belső hálózatáról is képet tud adni. Ezzel átfogóbb és pontosabb információt kapunk arról, hogy melyik adatközpontot érdemes használnunk.

Ezt úgy oldottam meg, hogy felkonfiguráltam egy egyszerű webszerver konténert, amely minden kérésre  egy üres válasszal válaszol. Ezt a konténert \textit{KubeFed} segítségével úgy futtattam, mint bármelyik másik szolgáltatást minden adatközpontban. Ezt a szolgáltatást kiajánlottam minden adatközpont publikus címére. A szkriptem pedig a \acrshort{http} kérés körülfordulási idejét méri.

Az így mért értékeket az ütemező fel tudja használni arra, hogy eldöntse, hogy melyik adatközpontra ütemezze be a robotkarok vezérléséhez szükséges szolgáltatást.

\subsection{Robotkarok vezérlésének átalakítása}

A robotkarok vezérlését megvalósító komponens a \textit{Kubernetes} \acrshort{api} interfészét használva indítja el \textit{KubeFed} segítségével az egyes \textit{programok} végrehajtását végző szolgáltatásokat. Ahhoz, hogy ezeket a szolgáltatásokat dinamikusan a legideálisabb környezetben indítsa el, arra van szükség, hogy szolgáltatás indítása előtt lekérje a \textit{Mérési adat kezelő} szolgáltatásból az egyes adatközpontok felé a cél telephely késleltetését, ezután pedig kiválassza azt, ahol legkisebb a késleltetés. 

A viselkedés implementálása egy \acrshort{http} \acrshort{api} hívást igényelt csak, közvetlenül az ütemezés kezdete előtt. Ezzel lekérte a szolgáltatásból a linkek késleltetésének középértékét az elmúlt két percre vetítve. Ezután minimum függvénnyel meghatározható volt, hogy melyik adatközpontban kerüljön ütemezésre a szolgáltatás.