some todo done

This commit is contained in:
Torma Kristóf 2019-12-05 22:48:41 +01:00
parent f5f3d85150
commit b15d6130d6
Signed by: tormakris
GPG Key ID: DC83C4F2C41B1047
6 changed files with 134 additions and 162 deletions

View File

@ -2,7 +2,7 @@
kile_livePreviewEnabled=true kile_livePreviewEnabled=true
kile_livePreviewStatusUserSpecified=true kile_livePreviewStatusUserSpecified=true
kile_livePreviewTool=LivePreview-XeLaTeX kile_livePreviewTool=LivePreview-XeLaTeX
lastDocument=content/preparation.tex lastDocument=content/theory.tex
[document-settings,item:../../thesis-template-latex/src/thesis.tex] [document-settings,item:../../thesis-template-latex/src/thesis.tex]
Bookmarks= Bookmarks=
@ -213,7 +213,7 @@ CursorLine=20
Dynamic Word Wrap=false Dynamic Word Wrap=false
JumpList= JumpList=
TextFolding=[] TextFolding=[]
ViMarks=.,22,0,[,22,0,],22,0 ViMarks=.,20,0,[,20,0,],20,0
[view-settings,view=0,item:content/results.tex] [view-settings,view=0,item:content/results.tex]
CursorColumn=28 CursorColumn=28
@ -224,12 +224,12 @@ TextFolding=[]
ViMarks=.,4,28,[,4,28,],4,28 ViMarks=.,4,28,[,4,28,],4,28
[view-settings,view=0,item:content/theory.tex] [view-settings,view=0,item:content/theory.tex]
CursorColumn=20 CursorColumn=13
CursorLine=170 CursorLine=33
Dynamic Word Wrap=false Dynamic Word Wrap=false
JumpList= JumpList=
TextFolding=[] TextFolding=[]
ViMarks=.,168,203,[,168,203,],168,213 ViMarks=.,115,78,[,116,0,],116,26
[view-settings,view=0,item:thesis.tex] [view-settings,view=0,item:thesis.tex]
CursorColumn=29 CursorColumn=29

View File

@ -155,25 +155,25 @@
} }
@misc{faas, @misc{faas,
howpublished = {https://www.cloudflare.com/learning/serverless/glossary/function-as-a-service-faas/}, howpublished = {\url{https://www.cloudflare.com/learning/serverless/glossary/function-as-a-service-faas/}},
note = {Megtekintve 2019-12-04}, note = {Megtekintve 2019-12-04},
title = {What Is Function as a Service (FaaS)?} title = {What Is Function as a Service (FaaS)?}
} }
@article{saas, @misc{saas,
howpublished = {https://www.infoworld.com/article/3226386/what-is-saas-software-as-a-service-defined.html}, howpublished = {\url{https://www.infoworld.com/article/3226386/what-is-saas-software-as-a-service-defined.html}},
note = {Megtekintve 2019-12-04}, note = {Megtekintve 2019-12-04},
title = {What is SaaS? Software-as-a-service defined} title = {What is SaaS? Software-as-a-service defined}
} }
@misc{paas, @misc{paas,
howpublished = {https://www.bmc.com/blogs/saas-vs-paas-vs-iaas-whats-the-difference-and-how-to-choose/}, howpublished = {\url{https://www.bmc.com/blogs/saas-vs-paas-vs-iaas-whats-the-difference-and-how-to-choose/}},
note = {Megtekintve 2019-12-04}, note = {Megtekintve 2019-12-04},
title = {SaaS vs PaaS vs IaaS: What{\rq}s The Difference and How To Choose} title = {SaaS vs PaaS vs IaaS: What{\rq}s The Difference and How To Choose}
} }
@misc{iaas, @misc{iaas,
howpublished = {https://www.techradar.com/news/what-is-infrastructure-as-a-service}, howpublished = {\url{https://www.techradar.com/news/what-is-infrastructure-as-a-service}},
note = {Megtekintve 2019-12-04}, note = {Megtekintve 2019-12-04},
title = {What is Infrastructure-as-a-Service? Everything you need to know} title = {What is Infrastructure-as-a-Service? Everything you need to know}
} }
@ -227,7 +227,7 @@
} }
@misc{kubernetes-node-controller, @misc{kubernetes-node-controller,
howpublished = {https://unofficial-kubernetes.readthedocs.io/en/latest/concepts/nodes/node/\#node-controller}, howpublished = {\url{https://unofficial-kubernetes.readthedocs.io/en/latest/concepts/nodes/node/\#node-controller}},
note = {Megtekintve 2019-12-04}, note = {Megtekintve 2019-12-04},
title = {Node - Node Controller} title = {Node - Node Controller}
} }
@ -341,7 +341,7 @@
} }
@misc{knative-autoscaler-component, @misc{knative-autoscaler-component,
howpublished = {https://github.com/knative/serving/blob/master/docs/scaling/DEVELOPMENT.md}, howpublished = {\url{https://github.com/knative/serving/blob/master/docs/scaling/DEVELOPMENT.md}},
note = {Megtekintve 2019-12-04}, note = {Megtekintve 2019-12-04},
title = {Autoscaling} title = {Autoscaling}
} }

View File

@ -103,16 +103,107 @@ class LogAnalyzer(Analyzer):
\end{lstlisting} \end{lstlisting}
%TODO Remove this shit \section{Folyamatos terhel\'est gener\'al\'o m\'er\'est v\'egző szkriptr\'eszlet Bash nyelven}
%---------------------------------------------------------------------------- \begin{lstlisting}[label=code:bash-banchmark-for]
\clearpage\section{Válasz az ,,Élet, a világmindenség, meg minden'' kérdésére} if [[ $* == *"--for"* ]]; then
%---------------------------------------------------------------------------- for num in 1 2 3 4 5 6 7 8 9 10; do
A Pitagorasz-tételből levezetve echo -e "for $num\n"
\begin{align} if $kubeless; then
c^2=a^2+b^2=42. if [[ $* == *"--loadtest"* ]]; then
\end{align} loadtest -k -H "Host: $function.kubeless" --rps $rps -c $connection -t $time -p "$function_firendly".body http://$kuberhost/"$function" >./data/"$function"."$num".txt
A Faraday-indukciós törvényből levezetve else
\begin{align} hey -c "$connection" -q $rps -z "$time" -m POST -o csv -host "$function.kubeless" -D "$function_friendly".body -T "application/json" http://$kuberhost/"$function" >./data/"$function"."$num".csv
\rot E=-\frac{dB}{dt}\hspace{1cm}\longrightarrow \hspace{1cm} fi
U_i=\oint\limits_\mathbf{L}{\mathbf{E}\mathbf{dl}}=-\frac{d}{dt}\int\limits_A{\mathbf{B}\mathbf{da}}=42. else
\end{align} if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.default.example.com" --rps $rps -c $connection -t $time http://$kuberhost/ >./data/"$function"."$num".for.csv
else
hey -c "$connection" -q $rps -z "$time" -m POST -o csv -host "$function.default.example.com" http://$kuberhost/ >./data/"$function"."$num".for.csv
fi
fi
done
fi
\end{lstlisting}
\clearpage
\section{Emelkedő terhel\'est megval\'os\'itő m\'er\'es Bash szkriptnyelven}
\begin{lstlisting}[label=code:bash-banchmark-climb]
if [[ $* == *"--climb"* ]]; then
while [[ $climb -lt $climb_max ]]; do
climb_rps=$((rps * climb))
echo -e "Rps: $climb_rps"
if $kubeless; then
if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.kubeless" --rps $climb_rps -c 1 -t $time -p "$function_firendly".body http://$kuberhost/"$function" >./data/"$function"."$climb_rps".climb.txt
else
hey -c $climb -q $rps -z $time -m POST -o csv -host "$function.kubeless" -D "$function_friendly".body -T "application/json" http://$kuberhost/"$function" >./data/"$function"."$climb_rps".climb.csv
fi
else
if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.default.example.com" --rps $climb_rps -c 1 -t $time http://$kuberhost/ >./data/"$function"."$climb_rps".climb.txt
else
hey -c $climb -q $rps -z $time -m POST -o csv -host "$function.default.example.com" http://$kuberhost/ >./data/"$function"."$climb_rps".climb.csv
fi
fi
climb=$((climb + 1))
done
fi
\end{lstlisting}
\section{Jmeter kimenet\'et feldolgoz\'o k\'odr\'eszlet, Python nyelven}
\begin{lstlisting}[label=code:jmeter-analyze]
class JmeterAnalyzer(CsvAnalyzer):
def __init__(self):
super().__init__()
self.responsepersec = {}
def processfile(
self,
fname,
shouldprint: bool = False):
with open(fname, 'r') as f:
data = csv.reader(f)
fields = next(data)
for row in data:
items = zip(fields, row)
item = {}
for (name, value) in items:
item[name] = value.strip()
sec = datetime.datetime.fromtimestamp(
int(item['timeStamp']) / 1000.0).strftime('%c')
if sec not in self.responsepersec:
self.responsepersec[sec] = []
self.responsepersec[sec].append(float(item['Latency']))
def collectinfo(self, shouldprint: bool = False) -> None:
self.walkresponsepersec(self.responsepersec, shouldprint)
\end{lstlisting}
\clearpage
\section{Hey kimenet\'et feldolgoz\'o k\'odr\'eszlet, Python nyelven}
\begin{lstlisting}[label=code:hey-analyze]
class HeyAnalyzer(CsvAnalyzer):
def __init__(self):
super().__init__()
def processfile(
self,
fname,
shouldprint: bool = False):
with open(fname, 'r') as f:
data = csv.reader(f)
fields = next(data)
responsepersec = {}
for row in data:
items = zip(fields, row)
item = {}
for(name, value) in items:
item[name] = value.strip()
sec = int(item['offset'].split('.')[0])
if sec not in responsepersec:
responsepersec[sec] = []
else:
responsepersec[sec].append(float(item['response-time']))
self.walkresponsepersec(responsepersec, shouldprint)
\end{lstlisting}

View File

@ -1,7 +1,7 @@
\chapter{F\"uggv\'enyek l\'etrehoz\'asa} \chapter{F\"uggv\'enyek l\'etrehoz\'asa}
A rendszerek sajátosságai miatt ugyanazt a kódot nem lehet változtatás nélkül felhasználni a két eltérő rendszerben. Mindkét rendszerre két tesztfüggvényt valósítottam meg. Az egyik célja a lehető legrövidebb válaszidő és a legnagyobb áteresztőképesség. A másik célja a kérésenként nagyobb processzorterhelés generálása. A rendszerek sajátosságai miatt ugyanazt a kódot nem lehet változtatás nélkül felhasználni a két eltérő rendszerben. Mindkét rendszerre két tesztfüggvényt valósítottam meg. Az egyik célja a lehető legrövidebb válaszidő és a legnagyobb áteresztőképesség. A másik célja a kérésenként nagyobb processzorterhelés generálása.
Az első egy Go nyelven megvalósított tesztfüggvény, amely a meghívás után “Hello Go!” szöveggel tér vissza. A Kubeless rendszerhez írt függvény szignatúrája egyezik a korábban bemutatott egyszerű “Hello World!” függvényével. Függőségként importálni kell a Kubeless sztenderd könyvtárát. Az első egy Go nyelven megvalósított tesztfüggvény, amely a meghívás után “Hello Go!” szöveggel tér vissza. A Kubeless rendszerhez írt függvény szignatúrája egyezik a \aref{code:hello-kubeless-go} k\'odr\'eszletben l\'athat\'o függvényével. Függőségként importálni kell a Kubeless sztenderd könyvtárát.
Knative rendszerben szükség van a Go sztenderd könyvtárban megtalálható HTTP szerver implementációra, valamint egy belépési függvényre, amely elindítja a webszervert és beköti a függvényünket úgy, hogy az alapértelmezett URL, ahol elindul a webszerver, az ide érkező kéréseket továbbítsa neki. Mivel a Knative-ba Docker Image-eket lehet telepíteni, ezért azt is létre kell hozni. Annak érdekében, hogy a végső Image a lehető legkisebb méretű legyen, a Go program binárissá fordítását külön végezzük el, a végső Image-be csak bemásoljuk azt. Erre a Docker ad eszközt, az úgynevezett multi-stage buildek segítségével. Ez azt jelenti, hogy egy külön végrehajtási láncot leírva lefordítjuk a kódot, majd a végső Image-be csak bemásoljuk a fordítással végzett konténer Image-éből. Az elkészült Image-et - melyet le\'ir\'o Docker file \aref{code:dockerfile-hello-go} k\'odr\'eszleten l\'athat\'o - a Docker Hubra feltöltöttem, hogy ne kelljen minden frissen telepített Workernek megépítenie az Image-et. Knative rendszerben szükség van a Go sztenderd könyvtárban megtalálható HTTP szerver implementációra, valamint egy belépési függvényre, amely elindítja a webszervert és beköti a függvényünket úgy, hogy az alapértelmezett URL, ahol elindul a webszerver, az ide érkező kéréseket továbbítsa neki. Mivel a Knative-ba Docker Image-eket lehet telepíteni, ezért azt is létre kell hozni. Annak érdekében, hogy a végső Image a lehető legkisebb méretű legyen, a Go program binárissá fordítását külön végezzük el, a végső Image-be csak bemásoljuk azt. Erre a Docker ad eszközt, az úgynevezett multi-stage buildek segítségével. Ez azt jelenti, hogy egy külön végrehajtási láncot leírva lefordítjuk a kódot, majd a végső Image-be csak bemásoljuk a fordítással végzett konténer Image-éből. Az elkészült Image-et - melyet le\'ir\'o Docker file \aref{code:dockerfile-hello-go} k\'odr\'eszleten l\'athat\'o - a Docker Hubra feltöltöttem, hogy ne kelljen minden frissen telepített Workernek megépítenie az Image-et.

View File

@ -97,52 +97,8 @@ A mérendő függvények nevét egy tömbben tároltam, így egymás után több
A folyamatos terhel\'est gener\'al\'o m\'er\'es \aref{code:bash-banchmark-for} k\'odr\'eszleten l\'athat\'o. A hey saj\'at\'oss\'agai miatt alkalmaztam azt a megold\'ast, hogy a k\'iv\'ant hossz\'us\'ag\'u fut\'as el\'er\'ese \'erdek\'eben t\"obbsz\"or elind\'itottam az eszk\"ozt. Látható, hogy a Kubeless-be és a Knative-ba telepített függvények meghívása eltér nem csak az alkalmazott http metódusban és a hosztnév sémájában, de a Content-Type fejléc, melynek értékét a T kapcsolóval lehet megadni, megléte is különbözik. A folyamatos terhel\'est gener\'al\'o m\'er\'es \aref{code:bash-banchmark-for} k\'odr\'eszleten l\'athat\'o. A hey saj\'at\'oss\'agai miatt alkalmaztam azt a megold\'ast, hogy a k\'iv\'ant hossz\'us\'ag\'u fut\'as el\'er\'ese \'erdek\'eben t\"obbsz\"or elind\'itottam az eszk\"ozt. Látható, hogy a Kubeless-be és a Knative-ba telepített függvények meghívása eltér nem csak az alkalmazott http metódusban és a hosztnév sémájában, de a Content-Type fejléc, melynek értékét a T kapcsolóval lehet megadni, megléte is különbözik.
\begin{lstlisting}[float=!ht,caption={Folyamatos terhel\'est gener\'al\'o m\'er\'est v\'egző szkriptr\'eszlet Bash nyelven},label=code:bash-banchmark-for]
if [[ $* == *"--for"* ]]; then
for num in 1 2 3 4 5 6 7 8 9 10; do
echo -e "for $num\n"
if $kubeless; then
if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.kubeless" --rps $rps -c $connection -t $time -p "$function_firendly".body http://$kuberhost/"$function" >./data/"$function"."$num".txt
else
hey -c "$connection" -q $rps -z "$time" -m POST -o csv -host "$function.kubeless" -D "$function_friendly".body -T "application/json" http://$kuberhost/"$function" >./data/"$function"."$num".csv
fi
else
if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.default.example.com" --rps $rps -c $connection -t $time http://$kuberhost/ >./data/"$function"."$num".for.csv
else
hey -c "$connection" -q $rps -z "$time" -m POST -o csv -host "$function.default.example.com" http://$kuberhost/ >./data/"$function"."$num".for.csv
fi
fi
done
fi
\end{lstlisting}
Mint az \aref{code:bash-banchmark-climb} kódrészleten látszik, a növekvő terhelésű mérés implementációja igen hasonló az egyenletes terhelésűhöz. A hey működését kihasználva, a rps kapcsoló segítségével beállított limit nem változik a mérés során, csupán a connection objektumok száma emelkedik. Mint az \aref{code:bash-banchmark-climb} kódrészleten látszik, a növekvő terhelésű mérés implementációja igen hasonló az egyenletes terhelésűhöz. A hey működését kihasználva, a rps kapcsoló segítségével beállított limit nem változik a mérés során, csupán a connection objektumok száma emelkedik.
\begin{lstlisting}[float=!ht,caption={Emelkedő terhel\'est megval\'os\'itő m\'er\'es Bash szkriptnyelven},label=code:bash-banchmark-climb]
if [[ $* == *"--climb"* ]]; then
while [[ $climb -lt $climb_max ]]; do
climb_rps=$((rps * climb))
echo -e "Rps: $climb_rps"
if $kubeless; then
if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.kubeless" --rps $climb_rps -c 1 -t $time -p "$function_firendly".body http://$kuberhost/"$function" >./data/"$function"."$climb_rps".climb.txt
else
hey -c $climb -q $rps -z $time -m POST -o csv -host "$function.kubeless" -D "$function_friendly".body -T "application/json" http://$kuberhost/"$function" >./data/"$function"."$climb_rps".climb.csv
fi
else
if [[ $* == *"--loadtest"* ]]; then
loadtest -k -H "Host: $function.default.example.com" --rps $climb_rps -c 1 -t $time http://$kuberhost/ >./data/"$function"."$climb_rps".climb.txt
else
hey -c $climb -q $rps -z $time -m POST -o csv -host "$function.default.example.com" http://$kuberhost/ >./data/"$function"."$climb_rps".climb.csv
fi
fi
climb=$((climb + 1))
done
fi
\end{lstlisting}
\section{M\'er\'esi eredm\'enyek automatiz\'alt elemz\'ese} \section{M\'er\'esi eredm\'enyek automatiz\'alt elemz\'ese}
Egy mérés eredményeként a mérés típusától függően akár több, nagy méretű csv állomány keletkezik. Ezen fájlok feldolgozása függ attól, hogy azt a Jmeter vagy a hey generálta. A fájlok kézi feldolgozása nyilvánvalóan lehetetlen. Az is előfordulhat, hogy már korábban feldolgozott méréseket egy új szempontból is fel kell dolgozni. Ez elő is fordult, ugyanis a program első verziója még nem volt képes az észlelt késleltetés feldolgozására. Szerencsére a Python programnyelv ilyen feladatok elvégzésére kiváló választás. Egy mérés eredményeként a mérés típusától függően akár több, nagy méretű csv állomány keletkezik. Ezen fájlok feldolgozása függ attól, hogy azt a Jmeter vagy a hey generálta. A fájlok kézi feldolgozása nyilvánvalóan lehetetlen. Az is előfordulhat, hogy már korábban feldolgozott méréseket egy új szempontból is fel kell dolgozni. Ez elő is fordult, ugyanis a program első verziója még nem volt képes az észlelt késleltetés feldolgozására. Szerencsére a Python programnyelv ilyen feladatok elvégzésére kiváló választás.
@ -152,67 +108,12 @@ Mivel egy méréshez több állomány is tartozhat, az egybe tartozó állomány
Ahogy \aref{code:jmeter-analyze} kódrészleten látszik, hogy a Python eléggé megkönnyíti egy csv fájl feldolgozását. A csv.reader függvény egy generátorral tér vissza, melyen végig iterálva lehet soronként feldolgozni az állományt. Egy sort a Python egy tuple objektumként reprezentál. Az első sorban az oszlopok nevét adja meg a Jmeter, így azt külön tuple objektumba mentve a zip hívással egy dictionary-t kapunk. Ebből a kívánt oszlop nevét megadva lehet kinyerni a keresett mezőt. Ahogy \aref{code:jmeter-analyze} kódrészleten látszik, hogy a Python eléggé megkönnyíti egy csv fájl feldolgozását. A csv.reader függvény egy generátorral tér vissza, melyen végig iterálva lehet soronként feldolgozni az állományt. Egy sort a Python egy tuple objektumként reprezentál. Az első sorban az oszlopok nevét adja meg a Jmeter, így azt külön tuple objektumba mentve a zip hívással egy dictionary-t kapunk. Ebből a kívánt oszlop nevét megadva lehet kinyerni a keresett mezőt.
\begin{lstlisting}[float=!ht,caption={Jmeter kimenet\'et feldolgoz\'o k\'odr\'eszlet, Python nyelven},label=code:jmeter-analyze]
class JmeterAnalyzer(CsvAnalyzer):
def __init__(self):
super().__init__()
self.responsepersec = {}
def processfile(
self,
fname,
shouldprint: bool = False):
with open(fname, 'r') as f:
data = csv.reader(f)
fields = next(data)
for row in data:
items = zip(fields, row)
item = {}
for (name, value) in items:
item[name] = value.strip()
sec = datetime.datetime.fromtimestamp(
int(item['timeStamp']) / 1000.0).strftime('%c')
if sec not in self.responsepersec:
self.responsepersec[sec] = []
self.responsepersec[sec].append(float(item['Latency']))
def collectinfo(self, shouldprint: bool = False) -> None:
self.walkresponsepersec(self.responsepersec, shouldprint)
\end{lstlisting}
A JmeterAnalyzer objektum létrejöttekor létrehoz egy dictionary objektumot, melyben a beolvasott fájl timeStamp mezője lesz a kulcs, az érték pedig az adott másodpercben érzékelt válaszok körbefordulási ideje. Mivel a Jmeter egy Java-ban írt szoftver, a timeStamp mező egy java.utils.Date objektum szerializálva. Ahhoz, hogy ebből Python datetime objektumot lehessen készíteni, az adott számot el kell osztani ezerrel. Az így kapott datetime már másodperc pontosan fogja tárolni az időt. Az adott másodpercben visszaérkezett válaszok számát pedig az adott másodpercben tárolt késleltetési értékek száma adja meg. A JmeterAnalyzer objektum létrejöttekor létrehoz egy dictionary objektumot, melyben a beolvasott fájl timeStamp mezője lesz a kulcs, az érték pedig az adott másodpercben érzékelt válaszok körbefordulási ideje. Mivel a Jmeter egy Java-ban írt szoftver, a timeStamp mező egy java.utils.Date objektum szerializálva. Ahhoz, hogy ebből Python datetime objektumot lehessen készíteni, az adott számot el kell osztani ezerrel. Az így kapott datetime már másodperc pontosan fogja tárolni az időt. Az adott másodpercben visszaérkezett válaszok számát pedig az adott másodpercben tárolt késleltetési értékek száma adja meg.
A feldolgozás végeztével egy-egy listába kigyűjti a másodpercenként összegyűjtött adatokat tartalmazó listák hosszát, valamint az értékek átlagát. A feldolgozás végeztével egy-egy listába kigyűjti a másodpercenként összegyűjtött adatokat tartalmazó listák hosszát, valamint az értékek átlagát.
Amint \aref{code:hey-analyze} hey esetében máshogy kell csinálni, ugyanis itt a mérés több fájlra bomlik, amelyekben viszont nem lehet feltételezni, hogy pontosan harminc másodpercnyi, vagy egyéb konstans időtartamnyi mérés adatát tartalmazza egy-egy fájl, ugyanis a munka során ez változott. Emiatt egy fájl feldolgozása után gyűjti ki két listába az összegyűjtött adatokat tartalmazó lista hosszát és a késleltetések átlagát. Amint \aref{code:hey-analyze} hey esetében máshogy kell csinálni, ugyanis itt a mérés több fájlra bomlik, amelyekben viszont nem lehet feltételezni, hogy pontosan harminc másodpercnyi, vagy egyéb konstans időtartamnyi mérés adatát tartalmazza egy-egy fájl, ugyanis a munka során ez változott. Emiatt egy fájl feldolgozása után gyűjti ki két listába az összegyűjtött adatokat tartalmazó lista hosszát és a késleltetések átlagát.
\begin{lstlisting}[float=!ht,caption={Hey kimenet\'et feldolgoz\'o k\'odr\'eszlet, Python nyelven},label=code:hey-analyze]
class HeyAnalyzer(CsvAnalyzer):
def __init__(self):
super().__init__()
def processfile(
self,
fname,
shouldprint: bool = False):
with open(fname, 'r') as f:
data = csv.reader(f)
fields = next(data)
responsepersec = {}
for row in data:
items = zip(fields, row)
item = {}
for(name, value) in items:
item[name] = value.strip()
sec = int(item['offset'].split('.')[0])
if sec not in responsepersec:
responsepersec[sec] = []
else:
responsepersec[sec].append(float(item['response-time']))
self.walkresponsepersec(responsepersec, shouldprint)
\end{lstlisting}
Miután a Knative Autoscaler naplóállománya analizálásának igénye felmerült, a méréseket automatizáló bash szkript módosítva lett úgy, hogy minden mérés kezdetének és végeztének másodpercre pontos dátumát egy külön fájlba menti. Ez által a naplófájl bejegyzéseit lehet szűrni a két dátum köztire. Miután a Knative Autoscaler naplóállománya analizálásának igénye felmerült, a méréseket automatizáló bash szkript módosítva lett úgy, hogy minden mérés kezdetének és végeztének másodpercre pontos dátumát egy külön fájlba menti. Ez által a naplófájl bejegyzéseit lehet szűrni a két dátum köztire.
A Knative Autoscaler a naplóbejegyzéseket json objektumként menti, melyből a Python képes dictionary objektumot készíteni. Amennyiben az adott bejegyzés ts mezője a mérés kezdési és befejezési ideje közé esik, akkor az msg mezőben lévő üzenet feldolgozásra kerül. Az üzenetben kulcs-érték párok vannak szóközzel elválasztva egymástól. A kulcs és az érték között egyenlőségjel van. Ezt egy reguláris kifejezéssel listává lehet konvertálni. Sajnos a Python reguláris kifejezés API-jában nincs arra lehetőség, hogy ilyen esetben dictionary objektumot adjon vissza, így azt kézzel kell konvertálni kihasználva azt, hogy az értékek mindig egy kulcs után következnek. Ezután a Podok száma, valamint a megfigyelt stabil konkurencia érték letárolható. Ennek folyamat\'at \aref{sec:log-analyze} f\"uggel\'ekben l\'atni. A Knative Autoscaler a naplóbejegyzéseket json objektumként menti, melyből a Python képes dictionary objektumot készíteni. Amennyiben az adott bejegyzés ts mezője a mérés kezdési és befejezési ideje közé esik, akkor az msg mezőben lévő üzenet feldolgozásra kerül. Az üzenetben kulcs-érték párok vannak szóközzel elválasztva egymástól. A kulcs és az érték között egyenlőségjel van. Ezt egy reguláris kifejezéssel listává lehet konvertálni. Sajnos a Python reguláris kifejezés API-jában nincs arra lehetőség, hogy ilyen esetben dictionary objektumot adjon vissza, így azt kézzel kell konvertálni kihasználva azt, hogy az értékek mindig egy kulcs után következnek. Ezután a Podok száma, valamint a megfigyelt stabil konkurencia érték letárolható. Ennek folyamat\'at \aref{sec:log-analyze} f\"uggel\'ekben l\'atni.

View File

@ -9,25 +9,11 @@ Mielőtt elkezdtem a Knative és Kubeless rendszerek mérését, annak érdekéb
A két ábrából látszik, hogy a várakozásokkal ellentétben a Jmeter jobban teljesített, mint a hey. Ez azért van, mert a hey-re megszabtam connection objektumomként ötszáz kérés per másodperces korlátot. Erre a számra úgy jutottam, hogy a hey által használt connection objektumok számát egyre állítottam. Ez esetben a generált kérések száma másodpercenként 510 és 530 között ingadozott, viszont stabilan mindig 500 felett volt. A generált forgalom stabilizálása érdekében az 500-nál húztam meg a határt, melynek szükségességét a korábbi tapasztalatok alapján éreztem, ugyanis a hey teljesítménye megfigyeléseim szerint instabil, mikor nagy sebességgel kell generálja a kéréseket. Továbbá, úgy ítéltem, hogy két különbözően viselkedő mérőeszköz többet fed fel a skálázódási mechanizmusokról. A két ábrából látszik, hogy a várakozásokkal ellentétben a Jmeter jobban teljesített, mint a hey. Ez azért van, mert a hey-re megszabtam connection objektumomként ötszáz kérés per másodperces korlátot. Erre a számra úgy jutottam, hogy a hey által használt connection objektumok számát egyre állítottam. Ez esetben a generált kérések száma másodpercenként 510 és 530 között ingadozott, viszont stabilan mindig 500 felett volt. A generált forgalom stabilizálása érdekében az 500-nál húztam meg a határt, melynek szükségességét a korábbi tapasztalatok alapján éreztem, ugyanis a hey teljesítménye megfigyeléseim szerint instabil, mikor nagy sebességgel kell generálja a kéréseket. Továbbá, úgy ítéltem, hogy két különbözően viselkedő mérőeszköz többet fed fel a skálázódási mechanizmusokról.
Az ábrákról szintén látszik, hogy a prím számoló függvény teljesítménye alulmarad a kis számításigényű függvényhez képest. Ez az előzetes várakozások szerint alakult. Mivel a Kubeless egy teljes Function as a Service rendszer, az oda telepített függvényeket önmagukban nem lehet kipróbálni. Az ábrákról szintén látszik, hogy a prím számoló függvény teljesítménye alulmarad a kis számításigényű függvényhez képest. Ez az előzetes várakozások szerint alakult. Mivel a Kubeless egy teljes Function as a Service rendszer, az oda telep\'it\'esre sz\'ant f\"uggv\'enyeket csak a rendszerbe telep\'itve lehet futtatni.
%TODO %TODO Coldstart
<knative-elso-coldstart és latency>
A fent látható ábra az első mérés volt, amit a Knative-ba telepített echo típusú függvényen végeztem. Az eredménye kifejezetten meglepett, ugyanis a két mérés között nem csak szignifikánsan nagy a különbség, de a hey harminc másodperces futásai közül az elsőben kifejezetten nagy a feldolgozott kérések rátája, csak utána csökken le ezer körüli értékre. Később a késleltetési értékeket megtekintve ahogy sejtettem, hogy az első harminc másodpercben a kérések nem értek el a Podig, ugyanis itt a késleltetés kifejezetten alacsony volt. Érdekes jelenség, hogy a Jmeter által mért teljesítmény sokkal stabilabb. Igaz, hogy ez esetben nincs szükség a mérést fél perces szegmensekre bontani. Különösen furcsa a hey viselkedése, ugyanis a hiszterézis akkor nem volt megfigyelhető, ha a függvényt közvetlen Dockerben futtattam. Emiatt használatát nem vetettem el, de az általa mért feldolgozott kérési rátát fenntartással kezeltem.
%TODO
<hatodik-hello-knative-cold részlet>
A korábbi mérést megismételve, hosszabb ideig futtatva a mért teljesítmény ingadozása megmarad, viszont az ezerig történő beesés nem tapasztalható.
%TODO
<jmeter-hatodik-go-cold>
%TODO
<jmeter-hatodik-go-hot>
A fenti két ábrán látható, hogy az nincs kihatással a függvény teljesítményére, hogy létezett-e a mérés indítása előtt. Érdekes jelenség, hogy a Jmeter által mért teljesítmény sokkal stabilabb. Igaz, hogy ez esetben nincs szükség a mérést fél perces szegmensekre bontani. Különösen furcsa a hey viselkedése, ugyanis a hiszterézis akkor nem volt megfigyelhető, ha a függvényt közvetlen Dockerben futtattam. Emiatt használatát nem vetettem el, de az általa mért feldolgozott kérési rátát fenntartással kezeltem.
%TODO %TODO
<jmeter-for-otodik> <jmeter-for-otodik>
@ -70,36 +56,30 @@ Ahogy az az ábrán látszik, a Kubeless skálázódása teljesen máshogy műk
%TODO %TODO
<jmeter-kubeless-hello-go-hatodik-rps> <jmeter-kubeless-hello-go-hatodik-rps>
Sajnos, a Kubeless esetében többször előfordult, hogy csak egy Podot hozott létre az egész mérés során. Ez nem függött attól, hogy mennyi ideig tartott a mérés. Miután véget ért a terhelés, rövid időn belül létre jött a következő Pod. Ennek okát próbáltam kideríteni, egyik hipotézisem az volt, hogy nincs elég cpu ideje a számítógépnek létrehozni a Podot, de ezt kézi megfigyeléseim során elvetettem. Másik probléma a Kubeless esetében, hogy az Nginx Ingress Controller minden beérkező kérésről naplóbejegyzést ír. Ennek következményeképp a Podja Evictelődik, mert túl sok tárterületet használ. Sajnos, a Kubeless esetében többször előfordult, hogy csak egy Podot hozott létre az egész mérés során. Ez nem függött attól, hogy mennyi ideig tartott a mérés. Miután véget ért a terhelés, rövid időn belül létre jött a következő Pod. Ennek okát próbáltam kideríteni, egyik hipotézisem az volt, hogy nincs elég cpu ideje a számítógépnek létrehozni a Podot, de ezt kézi megfigyeléseim során elvetettem. Másik probléma a Kubeless esetében, hogy az Nginx Ingress Controller minden beérkező kérésről naplóbejegyzést ír. Ennek következményeképp a Podja Evictelődik, mert túl sok tárterületet használ.
Erre a problémára több megoldási lehetőség létezik, viszont egyik sem tökéletes. Egy lehetőség a konténerek kézi (vagy akár automatizált) naplójainak rotációja. Ez azért nem jó megoldás, mert nem csak a függvény podok kerülnek evicted állapotba, hanem akár a network plugin által használt Pod, hiszen a monitorozó rendszer minden Pod-tól lekérdezi az adatait, valamint a Kubernetes minden Pod-ot evicted állapotba tesz, ha túl sok ephemeral storage-ot használ. Ennél létezik egyszerűbb megoldás, ami jobb lehetőségnek tűnik. Ez a Docker logrendszerének átkonfigurálása, hogy ne a konténer fájljai között, json formátumban naplózzon, hanem például használja a gazda gép journald rendszer szolgáltatását. Ez meg is oldotta ezt a problémát, viszont felvetett egy másikat. Bár a naplóbejegyzések már nem kerülnek a konténerek mellé, valahol a fájlrendszeren kerülnek tárolásra, ahol egy idő után ugyan tömörítésre kerülnek, de addig jelentős helyet foglalnak a mérésből és a monitorozásból adódó bejegyzések. Ennek eredményeként a Kubernetes worker node-okon DiskPreassure állapot léphet fel, amely azt jelenti, hogy az adott Node fájlrendszerén kevés a fennmaradt szabad hely. Ez a szabály vonatkozik a Node root partíciójára, valamint a Docker konténereket tároló partícióra is. Ekkor a Node-on lévő Pod-ok kerülhetnek evicted állapotba, a Kubernetes megpróbálja azokat újraindítani, viszont ez már új konténer létrehozását jelenti. Erre két megoldási lehetőség létezik. Vagy a problémás Node kubelet konfigurációját átállítjuk, hogy a DiskPreassure állapot később lépjen fel, ezzel viszont csak elnapoltuk a problémát. Másik lehetőség a naplófájlok gyorsabb rotációja, illetve a Docker konténerek külön partíción tárolása, de ez esetben csak lelassítottuk a problémát. Az igazi megoldás a kettő módszer ötvözése. Naplóbejegyzések mindenképpen generálódni fognak, ezt megakadályozni nem tudjuk és nem is érdekünk, hiszen bármi probléma adódik, a naplóbejegyzések jelentős segítséget nyújtanak a diagnózisban, valamint akár a probléma megoldásában is segíthetnek. Erre a problémára több megoldási lehetőség létezik, viszont egyik sem tökéletes. Egy lehetőség a konténerek kézi (vagy akár automatizált) naplójainak rotációja. Ez azért nem jó megoldás, mert nem csak a függvény podok kerülnek evicted állapotba, hanem akár a network plugin által használt Pod, hiszen a monitorozó rendszer minden Podtól lekérdezi az adatait, valamint a Kubernetes minden Podot evicted állapotba tesz, ha túl sok ephemeral storage-ot használ. Ennél létezik egyszerűbb megoldás, ami jobb lehetőségnek tűnik. Ez a Docker logrendszerének átkonfigurálása, hogy ne a konténer fájljai között, json formátumban naplózzon, hanem például használja a gazda gép journald rendszer szolgáltatását. Ez meg is oldotta ezt a problémát, viszont felvetett egy másikat. Bár a naplóbejegyzések már nem kerülnek a konténerek mellé, valahol a fájlrendszeren kerülnek tárolásra, ahol egy idő után ugyan tömörítésre kerülnek, de addig jelentős helyet foglalnak a mérésből és a monitorozásból adódó bejegyzések. Ennek eredményeként a Kubernetes worker node-okon DiskPreassure állapot léphet fel, amely azt jelenti, hogy az adott Node fájlrendszerén kevés a fennmaradt szabad hely. Ez a szabály vonatkozik a Node root partíciójára, valamint a Docker konténereket tároló partícióra is. Ekkor a Node-on lévő Podok kerülhetnek evicted állapotba, a Kubernetes megpróbálja azokat újraindítani, viszont ez már új konténer létrehozását jelenti. Erre két megoldási lehetőség létezik. Vagy a problémás Node kubelet konfigurációját átállítjuk, hogy a DiskPreassure állapot később lépjen fel, ezzel viszont csak elnapoltuk a problémát. Másik lehetőség a naplófájlok gyorsabb rotációja, illetve a Docker konténerek külön partíción tárolása, de ez esetben csak lelassítottuk a problémát. Az igazi megoldás a kettő módszer ötvözése. Naplóbejegyzések mindenképpen generálódni fognak, ezt megakadályozni nem tudjuk és nem is érdekünk, hiszen bármi probléma adódik, a naplóbejegyzések jelentős segítséget nyújtanak a diagnózisban, valamint akár a probléma megoldásában is segíthetnek.
Annak érdekében, hogy a Knative-ba telepített függvények skálázódása az általuk nyújtott teljesítményben is meglátszódjon, szerettem volna limitálni egy-egy Pod teljesítményét. Erre viszont a Knative által létrehozott objektum típusok esetében nincs lehetőség. Emiatt úgy döntöttem, hogy a Knative által létrehozott Kubernetes Deployment objektumot módosítom, ott hozom létre a limiteket. Ez sikerült is, a függvény működött tovább, a megadott korlátozások érvénybe léptek. Viszont az elvárások nem teljesültek, a Podok létrejöttével nem emelkedett meg a függvény teljesítménye. A lenti diagrammon látszik, hogy a függvény végig ezer kérést volt képes kiszolgálni másodpercenként. Annak érdekében, hogy a Knative-ba telepített függvények skálázódása az általuk nyújtott teljesítményben is meglátszódjon, szerettem volna limitálni egy-egy Pod teljesítményét. Erre viszont a Knative által létrehozott objektum típusok esetében nincs lehetőség. Emiatt úgy döntöttem, hogy a Knative által létrehozott Kubernetes Deployment objektumot módosítom, ott hozom létre a limiteket. Ez sikerült is, a függvény működött tovább, a megadott korlátozások érvénybe léptek. Viszont az elvárások nem teljesültek, a Podok létrejöttével nem emelkedett meg a függvény teljesítménye. A lenti diagrammon látszik, hogy a függvény végig ezer kérést volt képes kiszolgálni másodpercenként.
%TODO <jmeter-pillanat-junky>
<jmeter-pillanat-junky>
Korábbi mérések során a prímszámoló függvény egy Python folyamatot használva nyolcszáz kérést szolgált ki másodpercenként. Tehát a mérés során létrejött öt Pod nagyjából négyezer kérést kellene kiszolgálnia másodpercenként az elvárásaink alapján. Ezzel szemben az egész mérés során olyan teljesítményt nyújt a függvény, melyet két Pod is ki tudna szolgálni. Korábbi mérések során a prímszámoló függvény egy Python folyamatot használva nyolcszáz kérést szolgált ki másodpercenként. Tehát a mérés során létrejött öt Pod nagyjából négyezer kérést kellene kiszolgálnia másodpercenként az elvárásaink alapján. Ezzel szemben az egész mérés során olyan teljesítményt nyújt a függvény, melyet két Pod is ki tudna szolgálni.
Kíváncsi voltam, egyes mérések során milyen belső állapotai vannak a Knative egyes alegységeinek. Azért, hogy ezeket megfigyelhessem, telepítettem a Knative Monitoring egységét. Ez után újra elvégeztem bizonyos méréseket. Először a prímszámoló függvény viselkedését vizsgáltam meg. Az első ábrán a Podok CPU használata látható. Érdekes, hogy a Workeren elérhető húsz magból összesen hetet sem használnak. A második ábrán látható, hogy a függvényt kiszolgáló Podok és a Knative rendszer processzorhasználata, hogy alakul egymáshoz képest. Kíváncsi voltam, egyes mérések során milyen belső állapotai vannak a Knative egyes alegységeinek. Azért, hogy ezeket megfigyelhessem, telepítettem a Knative Monitoring egységét. Ez után újra elvégeztem bizonyos méréseket. Először a prímszámoló függvény viselkedését vizsgáltam meg. Az első ábrán a Podok CPU használata látható. Érdekes, hogy a Workeren elérhető húsz magból összesen hetet sem használnak. A második ábrán látható, hogy a függvényt kiszolgáló Podok és a Knative rendszer processzorhasználata hogyan alakul egymáshoz képest.
%TODO <grafana-isprime-cpu>
<grafana-isprime-cpu>
%TODO <grafana-isprime-controllvsdata>
<grafana-isprime-controllvsdata>
Érdekes, hogy együtt is csupán körülbelül tíz processzormagot használnak. A Control Plane az ábrán a Knative Serving egyes komponenseit, az Istio-t, a monitoring eszközöket és a Kubernetes beépített részeit jelenti. A lenti ábrán látható, ezen komponensek között miként oszlik el a processzorhasználat. Érdekes, hogy együtt is csupán körülbelül tíz processzormagot használnak. A Control Plane az ábrán a Knative Serving egyes komponenseit, az Istio-t, a monitoring eszközöket és a Kubernetes beépített részeit jelenti. A lenti ábrán látható ezen komponensek között miként oszlik el a processzorhasználat.
%TODO <grafana-isprime-controlplane-namespaces>
<grafana-isprime-controlplane-namespaces>
Látszik, hogy leginkább a Knative Serving komponense használja leginkább a processzort. A kubectl top parancsot használva azt is sikerült kideríteni, hogy pontosan az activator nevű komponens miatt emelkedik ki a Knative processzorhasználata. A Grafana által generált grafikonok egyikén megfigyelhető, hogy a pánik mód mikor kapcsolt be és meddig tartott. Ez a lenti grafikonon látszik. A pánik mód a specifikáltak szerint viselkedik, az xy ábrán az is látszik, miként alakult a Podok száma a mérés során. Látszik, hogy a Knative Serving komponense használja leginkább a processzort. A kubectl top parancsot használva azt is sikerült kideríteni, hogy pontosan az activator nevű komponens miatt emelkedik ki a Knative processzorhasználata. A Knative activator felel a metrik\'ak autoscaler fel\'e tov\'abb\'it\'as\'a\'ert, valamint inaktiv Revision-\"okh\"oz \'erkező k\'er\'esek bufferel\'es\'e\'ert. A Grafana által generált grafikonok egyikén megfigyelhető, hogy a pánik mód mikor kapcsolt be és meddig tartott. Ez a lenti grafikonon látszik. A pánik mód a specifikáltak szerint viselkedik, az xy ábrán az is látszik, miként alakult a Podok száma a mérés során.
%TODO <grafana-isprime-panik>
<grafana-isprime-panik>
%TODO <grafana-isprime-podszam>
<grafana-isprime-podszam>
Másodikként az echo típusú függvény terhelése alatt vizsgáltam meg a Knative belső működését. Másodikként az echo típusú függvény terhelése alatt vizsgáltam meg a Knative belső működését.