Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Dobrý deň, čitatelia Habr. Týmto článkom otvárame sériu, ktorá bude hovoriť o hyperkonvergovanom systéme AERODISK vAIR, ktorý sme vyvinuli. Pôvodne sme chceli všetko o všetkom povedať v prvom článku, no systém je dosť zložitý, takže slona budeme jesť po častiach.

Začnime príbeh históriou vzniku systému, ponoríme sa do súborového systému ARDFS, ktorý je základom vAIR, a tiež si povieme niečo o umiestnení tohto riešenia na ruskom trhu.

V budúcich článkoch si povieme podrobnejšie o rôznych architektonických komponentoch (klaster, hypervízor, load balancer, monitorovací systém atď.), o procese konfigurácie, nastolíme licenčné problémy, samostatne ukážeme crash testy a samozrejme budeme písať o záťažovom testovaní a dimenzovanie. Samostatný článok budeme venovať aj komunitnej verzii vAIR.

Je Aerodisk príbehom o úložných systémoch? Alebo prečo sme vôbec začali robiť hyperkonvergenciu?

Pôvodne k nám myšlienka vytvoriť vlastnú hyperkonvergenciu prišla niekedy okolo roku 2010. V tom čase ešte nebol na trhu Aerodisk ani podobné riešenia (komerčné krabicové hyperkonvergované systémy). Naša úloha bola nasledovná: zo sady serverov s lokálnymi diskami, spojených prepojením cez ethernetový protokol, bolo potrebné vytvoriť rozšírené úložisko a spustiť tam virtuálne stroje a softvérovú sieť. Toto všetko sa muselo realizovať bez úložných systémov (pretože na úložné systémy a ich hardvér jednoducho neboli peniaze a ešte sme nevymysleli vlastné úložné systémy).

Vyskúšali sme veľa open source riešení a nakoniec sme tento problém vyriešili, ale riešenie bolo veľmi zložité a ťažko sa opakovalo. Okrem toho bolo toto riešenie v kategórii „Funguje to? Nedotýkajte sa! Po vyriešení tohto problému sme ďalej nerozvíjali myšlienku transformácie výsledku našej práce na plnohodnotný produkt.

Po tom incidente sme sa od tejto myšlienky vzdialili, no stále sme mali pocit, že tento problém je úplne riešiteľný a výhody takéhoto riešenia boli viac než zrejmé. Následne vydané HCI produkty zahraničných firiem tento pocit len ​​potvrdili.

Preto sme sa v polovici roka 2016 k tejto úlohe vrátili v rámci tvorby plnohodnotného produktu. V tom čase sme ešte nemali žiadne vzťahy s investormi, a tak sme si developerský stánok museli kúpiť za vlastné nie veľmi veľké peniaze. Po zhromaždení použitých serverov a prepínačov na Avito sme sa pustili do práce.

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Hlavnou prvotnou úlohou bolo vytvorenie vlastného, ​​síce jednoduchého, ale vlastného súborového systému, ktorý dokáže automaticky a rovnomerne distribuovať dáta vo forme virtuálnych blokov na n-tom počte uzlov klastra, ktoré sú prepojené prepojením cez Ethernet. Zároveň by mal FS dobre a jednoducho škálovať a byť nezávislý od susedných systémov, t.j. byť odcudzený od vAIR vo forme „len skladovacieho zariadenia“.

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Prvý koncept vAIR

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Zámerne sme upustili od používania hotových open source riešení na organizovanie stretched storage (ceph, gluster, luster a podobne) v prospech vlastného vývoja, keďže sme s nimi už mali veľa projektových skúseností. Samozrejme, tieto riešenia sú samé o sebe výborné a pred prácou na Aerodisku sme s nimi realizovali nejeden integračný projekt. Jedna vec je však zrealizovať konkrétnu úlohu pre jedného zákazníka, zaškoliť personál a možno aj kúpiť si podporu veľkého predajcu a druhá vec je vytvoriť ľahko replikovateľný produkt, ktorý bude slúžiť na rôzne úlohy, ktoré my ako predajca, možno o sebe ani vedieť nebudeme. Pre druhý účel nám nevyhovovali existujúce open source produkty, preto sme sa rozhodli vytvoriť distribuovaný súborový systém sami.
O dva roky neskôr dosiahlo niekoľko vývojárov (ktorí spojili prácu na vAIR s prácou na klasickom úložnom systéme Engine) istý výsledok.

Do roku 2018 sme napísali jednoduchý súborový systém a doplnili ho o potrebný hardvér. Systém spojil fyzické (lokálne) disky z rôznych serverov do jedného plochého fondu cez interné prepojenie a „rozrezal“ ich do virtuálnych blokov, z virtuálnych blokov sa potom vytvorili blokové zariadenia s rôznym stupňom odolnosti voči chybám, na ktorých sa vytvorili virtuálne. a vykonávané pomocou KVM hypervisor cars.

S názvom súborového systému sme sa príliš neobťažovali a stručne sme ho nazvali ARDFS (hádajte, čo znamená))

Tento prototyp vyzeral dobre (samozrejme nie vizuálne, ešte neexistoval žiadny vizuálny dizajn) a vykazoval dobré výsledky z hľadiska výkonu a škálovania. Po prvom skutočnom výsledku sme dali tento projekt do pohybu, zorganizovali sme plnohodnotné vývojové prostredie a samostatný tím, ktorý sa zaoberal iba vAIR.

Práve v tom čase dozrela všeobecná architektúra riešenia, ktorá zatiaľ neprešla veľkými zmenami.

Ponorenie do systému súborov ARDFS

ARDFS je základom vAIR, ktorý poskytuje distribuované ukladanie údajov odolné voči chybám v celom klastri. Jednou z (ale nie jedinou) charakteristickou črtou ARDFS je, že na metadáta a správu nepoužíva žiadne ďalšie dedikované servery. Pôvodne to bolo koncipované pre zjednodušenie konfigurácie riešenia a pre jeho spoľahlivosť.

Skladovacia štruktúra

Vo všetkých uzloch klastra ARDFS organizuje logickú oblasť zo všetkého dostupného miesta na disku. Je dôležité pochopiť, že fond ešte nie sú dáta alebo formátovaný priestor, ale jednoducho značkovanie, t.j. Všetky uzly s nainštalovaným vAIR, keď sú pridané do klastra, sa automaticky pridajú do zdieľanej oblasti ARDFS a diskové prostriedky sa automaticky zdieľajú v celom klastri (a sú k dispozícii na budúce ukladanie údajov). Tento prístup vám umožňuje pridávať a odstraňovať uzly za chodu bez akéhokoľvek vážneho dopadu na už spustený systém. Tie. systém sa dá veľmi ľahko škálovať „v tehlách“ a v prípade potreby pridať alebo odstrániť uzly v klastri.

Virtuálne disky (úložné objekty pre virtuálne stroje) sú pridané na vrch fondu ARDFS, ktoré sú zostavené z virtuálnych blokov s veľkosťou 4 megabajty. Virtuálne disky priamo ukladajú dáta. Schéma odolnosti voči chybám je nastavená aj na úrovni virtuálneho disku.

Ako ste už možno uhádli, pre odolnosť diskového subsystému voči chybám nepoužívame koncept RAID (Redundantné pole nezávislých diskov), ale RAIN (Redundantné pole nezávislých uzlov). Tie. Odolnosť voči chybám sa meria, automatizuje a riadi na základe uzlov, nie diskov. Disky sú samozrejme tiež úložným objektom, sú ako všetko ostatné monitorované, môžete s nimi vykonávať všetky štandardné operácie vrátane zostavenia lokálneho hardvérového RAID, ale klaster funguje špeciálne na uzloch.

V situácii, keď naozaj chcete RAID (napríklad scenár, ktorý podporuje viacero zlyhaní na malých klastroch), nič vám nebráni použiť lokálne radiče RAID a vybudovať natiahnuté úložisko a architektúru RAIN. Tento scenár je celkom živý a je nami podporovaný, preto si o ňom povieme v článku o typických scenároch používania vAIR.

Schémy tolerancie chýb úložiska

Pre virtuálne disky vo vAIR môžu existovať dve schémy odolnosti voči chybám:

1) Faktor replikácie alebo jednoducho replikácia – táto metóda odolnosti voči chybám je jednoduchá ako palica a lano. Synchrónna replikácia sa vykonáva medzi uzlami s faktorom 2 (2 kópie na klaster) alebo 3 (3 kópie). RF-2 umožňuje virtuálnemu disku odolať zlyhaniu jedného uzla v klastri, ale „zožerie“ polovicu užitočného objemu a RF-3 odolá zlyhaniu 2 uzlov v klastri, no rezervuje si 2/3 užitočný objem pre jeho potreby. Táto schéma je veľmi podobná RAID-1, to znamená, že virtuálny disk nakonfigurovaný v RF-2 je odolný voči zlyhaniu ktoréhokoľvek uzla v klastri. V tomto prípade bude s dátami všetko v poriadku a ani I/O sa nezastaví. Keď sa spadnutý uzol vráti do prevádzky, spustí sa automatická obnova/synchronizácia dát.

Nižšie sú uvedené príklady distribúcie dát RF-2 a RF-3 v normálnom režime a pri poruche.

Máme virtuálny stroj s kapacitou 8 MB jedinečných (užitočných) dát, ktorý beží na 4 uzloch vAIR. Je jasné, že v skutočnosti je nepravdepodobné, že bude taký malý objem, ale pre schému, ktorá odráža logiku fungovania ARDFS, je tento príklad najzrozumiteľnejší. AB sú 4 MB virtuálne bloky obsahujúce jedinečné dáta virtuálneho stroja. RF-2 vytvorí dve kópie týchto blokov A1+A2 a B1+B2. Tieto bloky sú „rozložené“ medzi uzlami, čím sa vyhýbajú priesečníku rovnakých údajov v rovnakom uzle, to znamená, že kópia A1 nebude umiestnená na rovnakom uzle ako kópia A2. To isté s B1 a B2.

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Ak jeden z uzlov zlyhá (napríklad uzol č. 3, ktorý obsahuje kópiu B1), táto kópia sa automaticky aktivuje na uzle, kde neexistuje žiadna kópia jeho kópie (t. j. kópia B2).

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Virtuálny disk (a teda VM) môže ľahko prežiť zlyhanie jedného uzla v schéme RF-2.

Replikačná schéma, hoci je jednoduchá a spoľahlivá, trpí rovnakým problémom ako RAID1 – nedostatok využiteľného priestoru.

2) Na vyriešenie vyššie uvedeného problému existuje kódovanie vymazania alebo kódovanie vymazania (tiež známe ako „redundantné kódovanie“, „kódovanie vymazania“ alebo „redundantný kód“). EC je schéma redundancie, ktorá poskytuje vysokú dostupnosť údajov s nižšou réžiou miesta na disku v porovnaní s replikáciou. Princíp fungovania tohto mechanizmu je podobný RAID 5, 6, 6P.

Pri kódovaní proces EC rozdelí virtuálny blok (štandardne 4 MB) na niekoľko menších „dátových častí“ v závislosti od schémy EC (napríklad schéma 2+1 rozdelí každý 4 MB blok na 2 2 MB časti). Ďalej tento proces generuje „paritné časti“ pre „údajové časti“, ktoré nie sú väčšie ako jedna z predtým rozdelených častí. Pri dekódovaní EC generuje chýbajúce kúsky čítaním „prežívajúcich“ dát v celom klastri.

Napríklad virtuálny disk so schémou 2 + 1 EC, implementovaný na 4 klastrových uzloch, bez problémov odolá zlyhaniu jedného uzla v klastri rovnako ako RF-2. V tomto prípade budú režijné náklady nižšie, najmä koeficient užitočnej kapacity pre RF-2 je 2 a pre EC 2+1 bude 1,5.

Aby sme to popísali jednoduchšie, podstatou je, že virtuálny blok je rozdelený na 2-8 (prečo od 2 do 8, pozri nižšie) „kusov“ a pre tieto kusy sa vypočítajú „kusy“ parity podobného objemu.

Výsledkom je, že údaje a parita sú rovnomerne rozdelené medzi všetky uzly klastra. Súčasne, rovnako ako pri replikácii, ARDFS automaticky distribuuje údaje medzi uzly tak, aby sa zabránilo ukladaniu identických údajov (kópií údajov a ich parity) na rovnakom uzle, aby sa eliminovala možnosť straty údajov v dôsledku k tomu, že dáta a ich parita zrazu skončia na jednom storage node, ktorý zlyhá.

Nižšie je uvedený príklad s rovnakým 8 MB virtuálnym strojom a 4 uzlami, ale so schémou EC 2+1.

Bloky A a B sú rozdelené na dva kusy po 2 MB (dva, pretože 2+1), teda A1+A2 a B1+B2. Na rozdiel od repliky, A1 nie je kópiou A2, je to virtuálny blok A, rozdelený na dve časti, to isté s blokom B. Celkovo tak získame dve sady po 4 MB, z ktorých každá obsahuje dve dvojMB časti. Ďalej sa pre každú z týchto množín vypočíta parita s objemom nie väčším ako jeden kus (t.j. 2 MB), získame ďalšie + 2 kusy parity (AP a BP). Celkovo máme 4×2 dáta + 2×2 paritu.

Potom sa kúsky „rozložia“ medzi uzly tak, aby sa dáta nepretínali s ich paritou. Tie. A1 a A2 nebudú na rovnakom uzle ako AP.

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

V prípade výpadku jedného uzla (napr. aj tretieho) sa spadnutý blok B1 automaticky obnoví z parity BP, ktorá je uložená na uzle č.2 a aktivuje sa na uzle, kde je žiadna B-parita, t.j. kus BP. V tomto príklade ide o uzol č. 1

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Som si istý, že čitateľ má otázku:

"Všetko, čo ste opísali, už dávno implementovali konkurenti aj v riešeniach s otvoreným zdrojom, aký je rozdiel medzi vašou implementáciou EC v ARDFS?"

A potom tu budú zaujímavé funkcie ARDFS.

Vymazanie kódovania so zameraním na flexibilitu

Spočiatku sme poskytli pomerne flexibilnú schému EC X+Y, kde X sa rovná číslu od 2 do 8 a Y sa rovná číslu od 1 do 8, ale vždy je menšie alebo rovné X. Táto schéma je poskytnutá pre flexibilitu. Zvýšenie počtu dátových kusov (X), na ktoré je virtuálny blok rozdelený, umožňuje znížiť režijné náklady, teda zvýšiť využiteľný priestor.
Zvýšenie počtu paritných častí (Y) zvyšuje spoľahlivosť virtuálneho disku. Čím väčšia je hodnota Y, tým viac uzlov v klastri môže zlyhať. Samozrejme, zvýšenie objemu parity znižuje množstvo využiteľnej kapacity, ale je to cena, ktorú treba zaplatiť za spoľahlivosť.

Závislosť výkonu na obvodoch EC je takmer priama: čím viac „kúskov“, tým nižší výkon, tu je samozrejme potrebný vyvážený pohľad.

Tento prístup umožňuje správcom konfigurovať natiahnuté úložisko s maximálnou flexibilitou. V rámci fondu ARDFS môžete použiť ľubovoľné schémy odolnosti voči chybám a ich kombinácie, čo je podľa nášho názoru tiež veľmi užitočné.

Nižšie je uvedená tabuľka porovnávajúca niekoľko (nie všetky možné) schémy RF a EC.

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Tabuľka ukazuje, že aj „najviac „froté“ kombinácia EC 8+7, ktorá umožňuje stratu až 7 uzlov v klastri súčasne, „zaberá“ menej využiteľného priestoru (1,875 oproti 2) ako štandardná replikácia a chráni 7-krát lepšie. , čo robí tento ochranný mechanizmus, hoci je zložitejší, oveľa atraktívnejší v situáciách, kedy je potrebné zabezpečiť maximálnu spoľahlivosť v podmienkach obmedzeného miesta na disku. Zároveň musíte pochopiť, že každé „plus“ k X alebo Y bude predstavovať dodatočnú výkonovú réžiu, takže v trojuholníku medzi spoľahlivosťou, úsporou a výkonom musíte vyberať veľmi opatrne. Z tohto dôvodu budeme venovať vymazaniu veľkosti kódovania samostatný článok.

Hyperkonvergované riešenie AERODISK vAIR. Základom je súborový systém ARDFS

Spoľahlivosť a autonómia súborového systému

ARDFS beží lokálne na všetkých uzloch klastra a synchronizuje ich pomocou vlastných prostriedkov prostredníctvom vyhradených ethernetových rozhraní. Dôležité je, že ARDFS nezávisle synchronizuje nielen dáta, ale aj metadáta súvisiace s úložiskom. Pri práci na ARDFS sme súbežne študovali množstvo existujúcich riešení a zistili sme, že mnohé synchronizujú meta systém súborov pomocou externého distribuovaného DBMS, ktorý tiež používame na synchronizáciu, ale iba konfigurácie, nie metaúdaje FS (o tomto a ďalších súvisiacich podsystémoch v ďalšom článku).

Synchronizácia metadát FS pomocou externej DBMS je samozrejme fungujúcim riešením, ale potom by konzistencia údajov uložených na ARDFS závisela od externej DBMS a jej správania (a úprimne povedané, je to vrtošivá dáma), ktorá v náš názor je zlý. prečo? Ak dôjde k poškodeniu metaúdajov FS, samotným údajom FS sa dá tiež povedať „zbohom“, preto sme sa rozhodli ísť zložitejšou, ale spoľahlivejšou cestou.

Subsystém synchronizácie metadát pre ARDFS sme vytvorili sami a funguje úplne nezávisle od susedných podsystémov. Tie. žiadny iný podsystém nemôže poškodiť údaje ARDFS. Podľa nás je to najspoľahlivejšia a najsprávnejšia cesta, no či je to skutočne tak, ukáže až čas. Tento prístup má navyše ďalšiu výhodu. ARDFS je možné použiť nezávisle od vAIR, rovnako ako natiahnuté úložisko, ktoré určite využijeme v budúcich produktoch.

Výsledkom je, že vývojom ARDFS sme získali flexibilný a spoľahlivý súborový systém, ktorý dáva na výber, kde môžete ušetriť na kapacite alebo sa vzdať výkonu, alebo vytvoriť ultra spoľahlivé úložisko za rozumnú cenu, ale znížiť požiadavky na výkon.

Spolu s jednoduchou licenčnou politikou a flexibilným modelom poskytovania (pri pohľade do budúcnosti je vAIR licencovaný uzlom a dodávaný buď ako softvér alebo ako softvérový balík) vám to umožňuje veľmi presne prispôsobiť riešenie širokej škále požiadaviek zákazníkov a potom ľahko udržať túto rovnováhu.

Kto potrebuje tento zázrak?

Na jednej strane môžeme povedať, že už sú na trhu hráči, ktorí majú seriózne riešenia v oblasti hyperkonvergencie a tam vlastne smerujeme. Zdá sa, že toto tvrdenie je pravdivé, ALE...

Na druhej strane, keď vyrazíme do polí a komunikujeme so zákazníkmi, my aj naši partneri vidíme, že to tak vôbec nie je. Úloh na hyperkonvergenciu je veľa, niekde ľudia jednoducho nevedeli, že takéto riešenia existujú, inde sa im zdali drahé, inde neúspešné testy alternatívnych riešení a inde kvôli sankciám zakazujú nakupovať vôbec. Vo všeobecnosti sa ukázalo, že pole je nezorané, takže sme išli pestovať panenskú pôdu))).

Kedy je úložný systém lepší ako GKS?

Pri práci s trhom sa nás často pýtajú, kedy je lepšie použiť klasickú schému s úložnými systémami a kedy hyperkonvergentnú? Mnohé spoločnosti vyrábajúce GCS (najmä tie, ktoré nemajú vo svojom portfóliu úložné systémy) hovoria: „Úložné systémy sú zastarané, iba hyperkonvergované!“ Toto je odvážne tvrdenie, ktoré však úplne neodráža realitu.

V skutočnosti sa trh s úložiskami skutočne posúva smerom k hyperkonvergencii a podobným riešeniam, ale vždy existuje „ale“.

Po prvé, dátové centrá a IT infraštruktúry vybudované podľa klasickej schémy s úložnými systémami sa nedajú ľahko prebudovať, takže modernizácia a dobudovanie takýchto infraštruktúr je ešte na 5-7 rokov dedičstvom.

Po druhé, infraštruktúra, ktorá sa v súčasnosti z väčšej časti buduje (rozumej Ruská federácia), sa buduje podľa klasickej schémy s využitím úložných systémov a nie preto, že by ľudia o hyperkonvergencii nevedeli, ale preto, že hyperkonvergenčný trh je nový, riešenia a štandardy ešte nie sú zavedené, IT ľudia ešte nie sú vyškolení, majú málo skúseností, ale potrebujú vybudovať dátové centrá tu a teraz. A tento trend bude trvať ďalších 3-5 rokov (a potom ďalšie dedičstvo, pozri bod 1).

Po tretie, existuje čisto technické obmedzenie v dodatočných malých oneskoreniach 2 milisekúnd na zápis (samozrejme s výnimkou lokálnej vyrovnávacej pamäte), čo sú náklady na distribuované úložisko.

No, nezabudnime na použitie veľkých fyzických serverov, ktoré milujú vertikálne škálovanie diskového subsystému.

Existuje veľa potrebných a obľúbených úloh, pri ktorých sa úložné systémy správajú lepšie ako GCS. Tu s nami samozrejme nebudú súhlasiť tí výrobcovia, ktorí nemajú vo svojom produktovom portfóliu úložné systémy, ale sme pripravení rozumne argumentovať. Samozrejme, my ako vývojári oboch produktov určite porovnáme úložné systémy a GCS v niektorej z našich budúcich publikácií, kde jasne ukážeme, čo je za akých podmienok lepšie.

A kde budú hyperkonvergované riešenia fungovať lepšie ako úložné systémy?

Na základe vyššie uvedených bodov možno vyvodiť tri zrejmé závery:

  1. Tam, kde nie sú kritické ďalšie 2 milisekúndy latencie pre záznam, ktoré sa konzistentne vyskytujú v akomkoľvek produkte (teraz nehovoríme o syntetike, nanosekundy sa dajú zobraziť na syntetike), je vhodný hyperkonvergent.
  2. Tam, kde sa dá záťaž z veľkých fyzických serverov premeniť na veľa malých virtuálnych a rozdeliť medzi uzly, tam bude dobre fungovať aj hyperkonvergencia.
  3. Tam, kde má horizontálne škálovanie vyššiu prioritu ako vertikálne škálovanie, GCS bude fungovať dobre aj tam.

Aké sú tieto riešenia?

  1. Všetky štandardné infraštruktúrne služby (adresárová služba, mail, EDMS, súborové servery, malé alebo stredné ERP a BI systémy atď.). Hovoríme tomu „všeobecné počítanie“.
  2. Infraštruktúra cloudových poskytovateľov, kde je potrebné rýchlo a štandardizovať horizontálne rozširovať a jednoducho „osekávať“ veľké množstvo virtuálnych strojov pre klientov.
  3. Infraštruktúra virtuálnych desktopov (VDI), kde beží mnoho malých užívateľských virtuálnych strojov a potichu „pláva“ v jednotnom klastri.
  4. Pobočkové siete, kde každá pobočka potrebuje štandardnú, chybám odolnú, ale lacnú infraštruktúru 15-20 virtuálnych strojov.
  5. Akékoľvek distribuované výpočty (napríklad služby veľkých dát). Kde náklad nejde „do hĺbky“, ale „do šírky“.
  6. Testovacie prostredia, kde sú prijateľné ďalšie malé oneskorenia, ale existujú rozpočtové obmedzenia, pretože ide o testy.

Momentálne práve na tieto úlohy sme urobili AERODISK vAIR a práve na ne sa (zatiaľ úspešne) zameriavame. Možno sa to čoskoro zmení, pretože... svet nestojí.

Takže ...

Tým je prvá časť veľkej série článkov hotová, v ďalšom článku si povieme niečo o architektúre riešenia a použitých komponentoch.

Vítame otázky, návrhy a konštruktívne spory.

Zdroj: hab.com

Pridať komentár