1. A szökőkútkódok és alkalmazásuk a végpontok közötti megbízható adatkommunikációban
1.1. Áttekintő
Napjainkban egyre többen és többen fogyasztanak hétköznapjaik során valamilyen online tartalmat, akik kiszolgálása érdekében a világ több pontján elhelyezett szerverek (szerverközpontok) felelnek. Ilyen nagyobb tartalom szolgáltató például a Youtube, a Vimeo, vagy épp a Facebook is. Élő streameket, televízió adásokat, vagy videófelvételeket nézhetünk bárhol, bármikor. Az otthoni személyi és a hordozható számítógépek fejlődésével, ezzel járó nagyobb teljesítményével, a szolgáltatott anyagok egyre jobb és jobb minőségűek lehetnek, melyek arányosan egyre nagyobb sávszélességet igényelnek a tökéletes felhasználói és fogyasztói élményhez. A fogyasztói piac átalakulásával pedig, egyre nagyobb arányban használnak ezen célokra különféle vezetékes/nélküli eszközöket. Az internetes adatkommunikációt az 1990-es évek elejétől, a HTTP (Hypertext Transfer Protocol) végzi a TCP (Transmission Control Protocol) protokoll segítségével, melyek együtt egy szabványos közeget biztosítanak bármilyen adat megbízható, veszteségmentes és sorrendtartó átvitelére. A TCP szabványosítása már 1981-ben (melyet azóta bővítettek a nagysebességű átvitelekhez igazodóan), a http szabványosítása pedig a 90-es évek elején megtörtént. Ezek a szabványok még az akkori alapvetően vezetékes és néhány kilobájtnyi kommunikációhoz nyújtottak megoldást, mely a mai fentebb említett egyre különfélébb eszközök és közegek számára nem mindig a legoptimálisabb. Például a vezeték nélküli eszközök esetében az átviteli közeg, mely nem csak hogy helyben, de folyamatosan időben is jóval drasztikusabban változik mint a vezetékes esetben. A csatornát használó hasonló készülékeink, az elektromágneses zajokat keltő berendezéseink, valamint a természetben keletkező további a közegre ható zajok összesége folyamatosan változtatja az átvitel megbízhatóságát, és így az átvihető adat mennyiségét is [1]. A zajok hatására olyan csomaghibák is jelentkezhetnek, melyet a jelenleg használt fizikai rétegben lévő hibajavító funkció nem tud megfelelően korrigálni/észlelni, mint például egy nagyon zajos városi helyszínen. Csomaghibák esetén pedig, a hibás adatot a sikeres kézbesítésig újra és újra le kell kérdezni a forrástól. Az újraküldés [1] egy szabványos eljárása az egyedi tartalom továbbításnak, amelyben a fogadó fél, értesíti a küldőt, hogy mely darabjai hiányoznak a küldött anyagnak negatív, vagy pozitív nyugtázások által. Az újraküldés megkövetel egy vissza irányba kialakított csatornát, így csak olyan esetekben használható ahol ez megoldható, valamint kis számú csomagveszteségek, és kis számú kliens esetén. Azonban például egy TV adás közvetítése során több relatív nagy veszteségű kapcsolat a sok újraküldéssel könnyen túlterhelheti a szervert. Túlterhelést okozhat több nagy késleltetésű kapcsolat is, az időben hosszúra nyúló nyugtázások miatt, a küldőnek több ideig kell a memóriában tartani a küldött anyagot, így kevesebb tartalom szolgáltatására leszünk képesek. Tehát az újraküldés több szempontból is többletterhelést okoz a szervernek, ezen kérések feldolgozása során.1.2. A TCP működési elve
A TCP fő komponense a torlódásszabályozás, mely a torlódás észlelésén alapszik. [2] A kezdetekben ezért egy időzítő felelt, melynek letelte a csomag nyugtázásának hiányában a hálózat torlódását jelezte, habár több esetben is a visszajelzés hiányát nem a torlódás, hanem a zavarok jelentették. Manapság az optikai kábeleken ezen zavarok elhanyagolhatóak, azonban a vezeték nélküli átvitelben igen jelentősek tudnak lenni. Tehát míg az eredeti elgondolás az optikai hálózaton optimálisnak is tekinthető, más közegben jelentős teljesítménycsökkenést okoz. A különböző TCP verziók különböző időzítőket, limiteket, és ezek értékeinek meghatározására különböző algoritmusokat használnak. A legjelentősebb a retransmission időzítő, mely minden egyes csomag elküldésekor elindul. Ha nem érkezik visszajelzés, és a időzítő lejárt, az adatot újra küldjük, ha megérkezett az időzítőt megállítjuk, és elküldjük a következő csomagot. Tehát a megfelelő idő megválasztása kiemelten fontos. Ha túl kicsit választunk, túl sokszor küldünk újra csomagokat, ha túl nagyot választunk, nem használjuk ki teljes mértékben a hálózat kapacitását, az elvesztett csomagok visszajelzésére várakozással. A másik ilyen fontosabb limit a torlódási ablak, mely az elküldött, még nem nyugtázott csomagok számát határozza meg. Alapvetően a sikeres nyugtázások időben megérkezése esetén növelik a limit értékét, így növelve a sávszélességet, ellenkező esetben pedig csökkentik annak értékét, így csökkentve a sávszélességet.1.3. Digital Fountain based Communication Protocol
Az elmúlt években a Távközlési és Médiainformatikai Tanszéken fejlesztett DFCP az előző fejezetekben részletezett problémákra, tehát a manapság használt TCP protokollra szeretne nyújtani egy új univerzális, számos közegben hatékonyabb alternatívát [2]. A koncepció legradikálisabb ötlete, hogy a TCP által használt torlódáskezelést egyszerűen elhagynák a kommunikációból, így minden kommunikáló eszköz a lehető legnagyobb sebességével küldhetne adatot a világhálón. Az elvesztett adatok egy hatékony szökőkút (RaptorQ) algoritmussal lehetnének visszaállíthatók. Ezzel a megoldással kiaknázhatnánk a jelenlegi hálózatunk teljes kapacitását, valamint olcsóbbá tehetné jövőbeli eszközeink előállítását is a kevesebb átmeneti tároló alkalmazásával. A torlódáskezelés teljes elhagyásából és a maximum sebességgel való adatküldésből, óhatatlanul következik az átvitel során létrejövő nagyszámú csomagvesztés, a hálózati eszközök folyamatos terhelése miatt. Így nem minden csomag kerül továbbításra. Ezen csomagvesztések azonban egy megfelelő szökőkútkódoláson alapuló algoritmussal kiküszöbölhetőek lennének.1.4. Szökőkútkódok
A szökőkút kódok úttörő algoritmusok az internet számára, ahol az adatok továbbítása több kis részlet csomag továbbításán alapszik, melyek akár hibát tartalmazhatnak, vagy akár el is veszhetnek. [3] Az egyszerű fájl átviteli protokollok egyszerűen K darabra vágják a küldendő adatot, majd egész addig küldözgetik az egyes darabokat, míg a fogadó meg nem erősíti annak hibátlan célba érését. Ezzel szemben a szökőkút kódok véletlenszerűen generálnak a forrásból egységnyi csomagokat, melyeknek bármely K < N darab halmazából nagy eséllyel visszaállítható az eredeti küldött adat. Használatának előnye, hogy olyan közegekben is lehetőség nyílik megbízhatóbb átvitelre, ahol csak egy irányú kommunikáció lehetséges. (Pl. Digitális műholdas televíziózás). A szökőkútkódok használatával egy tetszőleges hosszú adatból végtelen mennyiségű csomagot generálhatunk. A fogadó képes visszaállítani az eredeti adatot bármely halmazából a fogadott csomagoknak, mely alig nagyobb elemszámú mint az eredeti adat. Tehát, alapvetően a közegbéli veszteségek nem befolyásolják annyira az adatküldést. Az első ilyen szökőkút algoritmus a Luby Transform kód (lásd később), azonban ez még nem tudott alacsony komplexitású megoldást biztosítani. A Raptor kódok melyek jelentős elméleti továbbfejlesztései az LT kódnak, az első olyan kódok, amelyek lineáris idejű kódolást és dekódolást nyújtanak. A kódoló algoritmus végtelen hosszú folyamot tud generálni a forrásból, melyet a fogadó nagy eséllyel vissza tud állítani. Már néhány, a forrás méretén felül érkező csomag fogadása esetén a dekódolás sikeressége majdnem 100%. A +2 szimbólum vétele esetén a sikertelenség már kisebb mint egy a millióhoz. Ráadásul, ha a dekódolás sikertelen, csak várni kell egy újabb csomag megérkezéséig, és egy újabb próbát tehetünk az adat visszanyerésére.1.4.1. Luby Transform kód
A Luby Transform kód egy szökőkút algoritmus, melyeknek futási ideje akár lineáris is lehet a üzenet méretének függvényében (pl. raptor). [4] Eljárás egy csomag előállítására röviden (encoding):- A forrást (adatot) K darabra tördeljük (csak az első körben)
- Véletlenszerűen választunk egy 0 < n < K számot (fokszám)
- Majd szintén véletlenszerűen választunk n darab töredéket, a K darabból
- Ezeket a töredékeket XOR-oljuk egymással, majd ezen adatok mellé eltároljuk mely csomagokat XOR-oltuk össze
- Végül CRC kóddal kiegészítve elküldjük a csomagot.
- Ha a pillanatnyilag fogadott csomag hibás, vagy már kaptunk egy ilyet, a csomagot eldobjuk.
- Ha a kapott csomag hibátlan, és még nem kaptunk ilyet, valamint a csomagban egynél több forrásdarab modulo-ja van kódolva, a csomagot XOR-oljuk az összes eddig kapott teljesen dekódolt forrásdarabbal.
- Ha az így kapott n-1 fokszámú csomag még n!=1 fokszámú, egy átmeneti tárolóba (buffer) helyezzük azt.
- Ha egy n=1 fokszámú csomagot kapunk, ami egy forrástöredék is egyben, az összes átmeneti tárolóban lévő, ezen forrástöredéket tartalmazó csomaggal XOR-oljuk (így minden csomag fokszáma csökken egyel).
- Mikor egy csomag fokszáma n=1-re csökken, a csomag adata a fogadott üzenet tárolójába kerül.
1.4.2. Raptor kódok
A Raptor kódok az első olyan ismert szökőkút algoritmusok, melyek lineáris kódolási és dekódolási tulajdonságokkal bírnak. [5]T kódolás, dekódolás = O(1)
Az első Raptor kódot Amin Shokrollahi iráni matematikus 2004-ben publikálta. A raptor kód egy jelentősen feljavított változata az LT kódolási eljárásnak, és már például a DVB-H szabvány része is, ugyanis már egy kisebb hibajavító adattöbblet elküldésével jelentős szolgáltatás minőségbéli javulást érhetnek el.2. RaptorQ (RFC6330) kódolás működése
2.1. Áttekintő
A kódolás menete A legfejlettebb Raptor kód a RaptorQ. [6]- Első lépésben, mielőtt a RaptorQ algoritmust lefuttatnánk a forrásadaton, a forrást Z >= 1 blokkra daraboljuk, amit forrásblokknak nevezünk. Majd ezekre a forrás blokkokra (source block) alkalmazzuk a RaptorQ kódoló algoritmusát. Minden blokk kap egy egyedi – Source Block Number (SBN) – sorszámot, nullától kezdődően.
- Második lépésben minden forrásblokkot feldarabolunk K darabra, így a töredékek – melyet forrás szimbólumnak nevezünk. Minden töredéket sorszámozunk az előzőhez hasonlóan, melyet ESI – Encoding Symbol Indentifier – azonosítónak hívunk.
- Harmadik lépésben a forrásszimbólumokat tovább tördelhetjük forrás al-szimbólumokra, az előzőkhez hasonlóan, azonban darabszámuk nem kell hogy megegyezzen K-val.
- Negyedik lépésben köztes szimbólumokat állítunk elő a forrás szimbólumokból.
- Ötödik lépésben elküldjük a forrás szimbólumokat a vevőnek, majd a köztes szimbólumokból javító szimbólumokat hozunk létre.
- A vevő oldalon előszőr a kapott csomagokból visszaállítjuk a köztes szimbólumokat, majd ezekből, és a többi forrásszimbólumból a hiányzó forrásszimbólumokat.
2.2. A forrás előkészítése
A forrás blokk és forrás al-blokkok előállítása 5 paramétertől függ:- F: a forrás hossza bájtban
- Al: szimbólum
- T: szimbólum méret bájtban
- Z: a forrás blokkok száma
- N: a forrás al-blokkok száma, minden egyes forrás blokkban
2.3. Kódolt csomag szerkezete
Minden csomag tartalmazza az alábbiakat:- SBN
- ESI
- Kódolt szimbólumok
2.4. Kódolás
Első lépés: Köztes szimbólumok generálása (előkódolás).
Ebben a lépésben L darab C köztes szimbólumot generálunk a K’ darab C’ forrás szimbólumból, ahol L > K’. [7] Két fázisú algoritmust használunk. Az első fázisban az LDPC kód segítségével állítunk elő redundáns szimbólumokat a forrás szimbólumokból. Az LPDC kód generálja a legtöbb köztes szimbólumot (Low Density Parity Check Code) az előkódolás alatt, melyeknek kódolása / dekódolása lineáris a forrás blokk méretével. A második fázisban a HDPC kóddal generálunk kis mennyiségű HDPC (High Density Parity Check Code) szimbólumot, melyeknek kódolása / dekódolása szintén lineáris.Második lépés: Kódolás
A második lépés során minden X > K’ csomaghoz, javító szimbólumokat generálunk a köztes szimbólumok véletlenszerű felhasználásával. LT kódolás segítségével a köztes szimbólumokból kódolt szimbólumokat állítunk elő, hogy aztán az LT dekódolás során visszaállíthassuk belőlük a köztes szimbólumokat. Az előny az, hogy ahelyett, hogy minden egyes köztes szimbólumot vissza kellene állítanunk, a beépített redundancia miatt csak egy nagyobb részét kell visszaállítanunk a köztes szimbólumoknak, és aztán ezt a redundanciát felhasználva állíthatjuk elő a maradék köztes szimbólumokat.2.5. Dekódolás
A dekódolónak minden esetben tudnia kell a következő adatokat:- T: szimbólum méret
- K: szimbólum szám a forrás blokkban
- K’: szimbólum szám a kiterjesztett forrás blokkban
- A kapott szimbólumokat egy mátrixba helyezzük, majd Gauss eliminálunk, végezetül megfelelően összegezve a kódolt szimbólumokat, visszakapjuk a köztes szimbólumokat.
- A megkapott forrás szimbólumokhoz tartozó sorokból megállapítjuk, hogy mely köztes szimbólumokat kell összegezni a hiányzó forrás szimbólumok visszaállításához, majd visszaállítjuk a forrás szimbólumokat.
3. RaptorQ kódolás teljesítményelemzése különböző tesztesetek segítségével
3.1. Előkészítés
A félév során a végső feladat, a szökőkút RaptorQ algoritmus, és az új protokoll koncepció megismerése után, egy már C++-ban implementált RaptorQ algoritmus teljesítmény elemzése volt, különböző paraméterek függvényében. A forráskód a következő GitLab repoból érhető el jelenleg: https://www.fenrirproject.org/Luker/libRaptorQ A projekt letöltése után, ubuntu Linux alatt a cmake, libevent, libevent-dev, libunbound-dev telepítése után a leírás alapján hiba nélkül lefordult. Lépések:- cd libRaptorQ/
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release ../
- make -j4
- sudo make install
3.2. Tesztkörnyezet
A teszteléshez használt programom forráskódja: https://github.com/majonez/libraptorQ_tester Tesztelői környezet:- Intel Core i5 6400@3.10GHz,
- 16GB DDR4 RAM,
- Gigabyte Z170X-Gaming-3,
- Mac OS X 10.11.5,
- Xcode 7.3.1
3.3. Teszteredmények
Forrásméret: ~220KB (K=K_max), veszteség=50%, szimbólum méret=1024bájt Az 1. ábra mérési eredményeiből látható, hogy az al-szimbólumok számától a futási idő nem függ. Forrásméret: ~220KB (K=K_max), szimbólum méret=1024bájt, al-szimbólum szám=64 A 2. ábrából látható, hogy a hibátlan vétel kivételével, melynél a dekódolásra szánt idő közel 0, a dekódolás futási ideje nem függ az elvesztett csomagok arányától, és a szükséges idő megegyezik a kódolásra szánt idővel. A teszt során az elvesztett csomagok „kiválasztását” egy véletlen generátor végzi. Így két azonos százalékú teszt során is különböző indexű csomagok vesznek el. Forrásméret: ~220KB (K=K_max), veszteség=50%, al-szimbólum szám=64 Ahogy a 3. ábrán láthatjuk, a futási idő nagyban függ attól, hogy egy kódolandó blokkot hány szimbólumra bontunk fel. A még elfogadható teljesítményt jelen esetben 512 és 1024 körül találhatjuk. Az átvitt adat mennyisége K*sizeof(uint_32)=226kB, így például 1024 választása esetén 1000/64*226=3.5MB/s sávszélességet érhetünk el egyetlen processzormag használata esetén. Az 1024 byte szimbólum nagyság viszont nem teljesen optimális az Ethernet számára, ugyanis egy keretben ~1500byte fér el. Az első optimálisnak mondható szimbólum méret a 128byte, ugyanis 1500-128*11=92byte amiből még a szimbólumokhoz tartozó azonosítók is használnak el bájtokat. Így közel 100%-osan kihasználhatjuk a jelenlegi szabvány szerinti keretet. Veszteség=50%, al-szimbólum szám=64, szimbólum méret=128 bájt A 4. ábrán látható, hogy a futási idő a forrásblokk méretétől négyzetesen függ. A mérés a 128 bájtos szimbólumméret megválasztásával készült. Az előzőeket végig gondolva, a kimenő sávszélesség növelhető valamelyest a szimbólumok egy blokkon belüli számának csökkentésével. Veszteség=50%, al-szimbólum szám=64, szimbólum szám=~10 Az ábráról látható, hogy ha biztosítjuk a konstans blokk/szimbólum méret arányt, tehát a szimbólumok számát egy blokkban, a (de)kódolás sebessége valóban lineárisan függ a forrásblokk méretétől. A 6. Ábrán látható, hogy az elérhető maximális sávszélesség 10 szimbólum/blokk esetén, kb. 12.5MB/s ~ 100Mbps4. Értékelés
A teszt során kapott eredmények hasonlóak a nyílt forráskódú, javában írt RaptorQ implementáció sebesség eredményeivel is: https://github.com/openrq-team/OpenRQ Összességében, a RaptorQ és a DFCP ötlete is nagyon jó, és az algoritmus néhány elenyésző kivételt kivéve, az összes esetben sikeresen előállítja az eredeti adatot. Manapság viszont már jóval túlléptük a 100Mbps-es sávszélességet, így ebben a formában, CPU-n futtatva, egy hálózati protokoll részeként nem tudom elképzelni a kódot. Egyszerűen túl sok az elpazarolt CPU idő.5. Tanulmányozott irodalmak jegyzéke
- [1] Digital Fountain Incorporated, a Qualcomm Company – „Benefits of DF Raptor® for Mobile File Broadcast” https://www.qualcomm.com/documents/benefits-raptor-codes-mobile-file-broadcast
- [2] Szilárd Solymos – „Development of an Efficient Transport Protocol based on Digital Fountain” http://tdk.bme.hu/vik/DownloadPaper/Hatekony-digitalis-szokokut-elvu-szallitasi
- [3] D.J.C. MacKay – „Fountain codes” https://docs.switzernet.com/people/emin-gabrielyan/060112-capillary-references/ref/MacKay05.pdf
- [4] Wikipedia – „Luby Transform code” https://en.wikipedia.org/wiki/Luby_transform_code
- [5] Wikipedia – „Raptor code” https://en.wikipedia.org/wiki/Raptor_code
- [6] M. Luby, Qualcomm Incorporated, A. Shokrollahi, EPFL, M. Watson, Netflix Inc., T. Stockhammer, Nomor Research, L. Minder – „RaptorQ Forward Error Correction Scheme for Object Delivery” https://tools.ietf.org/html/rfc6330
- [7] QUALCOMM Incorporated – „RaptorQTM Technical Overview” https://www.qualcomm.com/documents/raptorq-technical-overview