One-cloud - OS na úrovni dátového centra v Odnoklassniki

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Aloha, ľudia! Volám sa Oleg Anastasyev, pracujem v Odnoklassniki v tíme Platform. A okrem mňa v Odnoklassniki pracuje veľa hardvéru. Máme štyri dátové centrá s približne 500 rackmi s viac ako 8 tisíc servermi. V určitom momente sme si uvedomili, že zavedenie nového systému riadenia nám umožní efektívnejšie zaťažovať zariadenia, zjednodušiť správu prístupov, automatizovať (pre)distribúciu výpočtových zdrojov, urýchliť spustenie nových služieb a zrýchliť reakcie. k rozsiahlym nehodám.

čo z toho vzniklo?

Okrem mňa a kopy hardvéru sú tu aj ľudia, ktorí s týmto hardvérom pracujú: inžinieri, ktorí sa nachádzajú priamo v dátových centrách; sieťoví pracovníci, ktorí nastavujú sieťový softvér; správcovia alebo SRE, ktorí poskytujú odolnosť infraštruktúry; a vývojové tímy, pričom každý z nich je zodpovedný za časť funkcií portálu. Softvér, ktorý vytvárajú, funguje asi takto:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Požiadavky používateľov sú prijímané na oboch frontoch hlavného portálu www.ok.rua na iných, napríklad na frontoch music API. Na spracovanie obchodnej logiky volajú aplikačný server, ktorý pri spracovaní požiadavky zavolá potrebné špecializované mikroslužby - jeden graf (graf sociálnych väzieb), user-cache (vyrovnávacia pamäť používateľských profilov) atď.

Každá z týchto služieb je nasadená na mnohých strojoch a každý z nich má zodpovedných vývojárov zodpovedných za fungovanie modulov, ich prevádzku a technologický rozvoj. Všetky tieto služby bežia na hardvérových serveroch a donedávna sme spúšťali presne jednu úlohu na server, čiže bol špecializovaný na konkrétnu úlohu.

prečo je to tak? Tento prístup mal niekoľko výhod:

  • Uľavilo hromadné riadenie. Povedzme, že úloha vyžaduje nejaké knižnice, nejaké nastavenia. A potom je server priradený presne jednej konkrétnej skupine, je popísaná politika cfengine pre túto skupinu (alebo už bola popísaná) a táto konfigurácia je centrálne a automaticky zavedená na všetky servery v tejto skupine.
  • Zjednodušené diagnostika. Povedzme, že sa pozriete na zvýšené zaťaženie centrálneho procesora a uvedomíte si, že toto zaťaženie môže byť generované iba úlohou, ktorá beží na tomto hardvérovom procesore. Hľadanie vinníka sa veľmi rýchlo končí.
  • Zjednodušené monitorovanie. Ak so serverom niečo nie je v poriadku, monitor to nahlási a vy presne viete, kto je na vine.

Službe pozostávajúcej z niekoľkých replík je pridelených niekoľko serverov – jeden pre každý. Potom sa výpočtový zdroj pre službu pridelí veľmi jednoducho: počet serverov, ktoré služba má, maximálne množstvo zdrojov, ktoré môže spotrebovať. „Jednoduché“ tu neznamená, že sa ľahko používa, ale v tom zmysle, že prideľovanie zdrojov sa vykonáva manuálne.

Tento prístup nám to tiež umožnil špecializované konfigurácie železa pre úlohu spustenú na tomto serveri. Ak úloha ukladá veľké množstvo dát, potom použijeme 4U server so šasi s 38 diskami. Ak je úloha čisto výpočtová, môžeme si kúpiť lacnejší 1U server. Toto je výpočtovo efektívne. Tento prístup nám okrem iného umožňuje využívať štyrikrát menej strojov so záťažou porovnateľnou s jednou priateľskou sociálnou sieťou.

Takáto efektívnosť využívania výpočtových zdrojov by mala zabezpečiť aj ekonomickú efektívnosť, ak vychádzame z premisy, že najdrahšie sú servery. Po dlhú dobu bol hardvér najdrahší a vynaložili sme veľa úsilia na zníženie ceny hardvéru, pričom sme prišli s algoritmami odolnosti voči chybám na zníženie požiadaviek na spoľahlivosť hardvéru. A dnes sme sa dostali do štádia, kedy cena servera prestala byť rozhodujúca. Ak neberiete do úvahy najnovšie exotiky, na konkrétnej konfigurácii serverov v racku nezáleží. Teraz máme ďalší problém - cenu priestoru, ktorý zaberá server v dátovom centre, teda priestoru v racku.

Uvedomili sme si, že je to tak, rozhodli sme sa vypočítať, ako efektívne sme stojany využívali.
Vybrali sme cenu najvýkonnejšieho servera z ekonomicky opodstatnených, vypočítali, koľko takýchto serverov môžeme umiestniť do rackov, koľko úloh na nich spustíme podľa starého modelu „jeden server = jedna úloha“ a koľko napr. úlohy mohli využívať vybavenie. Počítali a ronili slzy. Ukázalo sa, že naša efektivita pri používaní stojanov je približne 11 %. Záver je zrejmý: musíme zvýšiť efektivitu využívania dátových centier. Zdá sa, že riešenie je zrejmé: musíte spustiť niekoľko úloh na jednom serveri naraz. Ale tu začínajú ťažkosti.

Hromadná konfigurácia sa dramaticky skomplikuje – teraz nie je možné priradiť žiadnu jednu skupinu k serveru. Koniec koncov, teraz je možné na jednom serveri spustiť niekoľko úloh rôznych príkazov. Okrem toho môže byť konfigurácia pre rôzne aplikácie konfliktná. Diagnostika sa tiež skomplikuje: ak na serveri vidíte zvýšenú spotrebu CPU alebo disku, neviete, ktorá úloha spôsobuje problémy.

Ale hlavná vec je, že neexistuje žiadna izolácia medzi úlohami bežiacimi na rovnakom počítači. Tu je napríklad graf priemernej doby odozvy úlohy servera pred a po spustení inej výpočtovej aplikácie na tom istom serveri, ktorý nijako nesúvisí s prvou – doba odozvy hlavnej úlohy sa výrazne zvýšila.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Je zrejmé, že musíte spúšťať úlohy buď v kontajneroch alebo vo virtuálnych strojoch. Keďže takmer všetky naše úlohy bežia pod jedným OS (Linux) alebo sú preň prispôsobené, nepotrebujeme podporovať veľa rôznych operačných systémov. Virtualizácia teda nie je potrebná; kvôli dodatočnej réžii bude menej efektívna ako kontajnerizácia.

Ako implementácia kontajnerov na spúšťanie úloh priamo na serveroch je Docker dobrým kandidátom: obrazy súborového systému dobre riešia problémy s konfliktnými konfiguráciami. Skutočnosť, že obrázky môžu byť zložené z niekoľkých vrstiev, nám umožňuje výrazne znížiť množstvo údajov potrebných na ich nasadenie v infraštruktúre, pričom spoločné časti oddeľujeme do samostatných základných vrstiev. Potom sa základné (a najobjemnejšie) vrstvy uložia do vyrovnávacej pamäte pomerne rýchlo v celej infraštruktúre a na poskytovanie mnohých rôznych typov aplikácií a verzií bude potrebné preniesť len malé vrstvy.

Navyše, pripravený register a označovanie obrázkov v Dockeri nám poskytuje hotové primitívy na vytváranie verzií a dodávanie kódu do produkcie.

Docker, ako každá iná podobná technológia, nám poskytuje určitú úroveň izolácie kontajnerov hneď po vybalení. Napríklad izolácia pamäte – každý kontajner má daný limit na využitie pamäte stroja, po prekročení ktorého nebude spotrebovávať. Kontajnery môžete izolovať aj na základe využitia procesora. Nám však štandardné zateplenie nestačilo. Ale o tom viac nižšie.

Priame spustenie kontajnerov na serveroch je len časťou problému. Druhá časť sa týka hosťovania kontajnerov na serveroch. Musíte pochopiť, ktorý kontajner je možné umiestniť na ktorý server. Nie je to taká jednoduchá úloha, pretože kontajnery je potrebné umiestniť na servery čo najhustejšie bez zníženia ich rýchlosti. Takéto umiestnenie môže byť náročné aj z hľadiska odolnosti voči chybám. Často chceme umiestniť repliky tej istej služby do rôznych stojanov alebo dokonca do rôznych miestností dátového centra, aby sme v prípade zlyhania stojana alebo miestnosti neprišli okamžite o všetky repliky služieb.

Ručná distribúcia kontajnerov nie je možná, keď máte 8 tisíc serverov a 8-16 tisíc kontajnerov.

Okrem toho sme chceli vývojárom poskytnúť väčšiu nezávislosť pri prideľovaní zdrojov, aby mohli svoje služby hostiť v produkcii sami, bez pomoci správcu. Zároveň sme si chceli zachovať kontrolu, aby nejaká menšia služba nespotrebovala všetky zdroje našich dátových centier.

Je zrejmé, že potrebujeme kontrolnú vrstvu, ktorá by to urobila automaticky.

Dospeli sme teda k jednoduchému a zrozumiteľnému obrázku, ktorý zbožňujú všetci architekti: tri štvorce.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

one-cloud masters je klaster prepnutia pri zlyhaní zodpovedný za cloudovú orchestráciu. Vývojár odošle manifest hlavnému serveru, ktorý obsahuje všetky informácie potrebné na hosťovanie služby. Na jej základe master dáva príkazy vybraným minionom (strojom určeným na spúšťanie kontajnerov). Prisluhovači majú nášho agenta, ktorý prijíma príkaz, vydáva príkazy Dockeru a Docker nakonfiguruje linuxové jadro na spustenie príslušného kontajnera. Okrem vykonávania príkazov agent neustále hlási masterovi zmeny v stave stroja minion a kontajnerov, ktoré na ňom bežia.

Rozdelenie zdrojov

Teraz sa pozrime na problém zložitejšej alokácie zdrojov pre mnohých prisluhovačov.

Výpočtový zdroj v jednom cloude je:

  • Množstvo výkonu procesora spotrebovaného konkrétnou úlohou.
  • Množstvo pamäte dostupnej pre úlohu.
  • Sieťová prevádzka. Každý z prisluhovačov má špecifické sieťové rozhranie s obmedzenou šírkou pásma, takže nie je možné distribuovať úlohy bez zohľadnenia množstva dát, ktoré prenášajú cez sieť.
  • Disky. Okrem toho, samozrejme, k priestoru pre tieto úlohy prideľujeme aj typ disku: HDD alebo SSD. Disky môžu obsluhovať konečný počet požiadaviek za sekundu – IOPS. Preto pri úlohách, ktoré generujú viac IOPS, ako dokáže zvládnuť jeden disk, prideľujeme aj „vretená“ – teda diskové zariadenia, ktoré musia byť výhradne vyhradené pre danú úlohu.

Potom pre nejakú službu, napríklad pre user-cache, môžeme zaznamenať spotrebované zdroje týmto spôsobom: 400 procesorových jadier, 2,5 TB pamäte, 50 Gbit/s prevádzka v oboch smeroch, 6 TB miesta na HDD umiestnenom na 100 vretenách . Alebo v známejšej forme, ako je táto:

alloc:
    cpu: 400
    mem: 2500
    lan_in: 50g
    lan_out: 50g
    hdd:100x6T

Prostriedky služieb používateľskej vyrovnávacej pamäte spotrebúvajú iba časť všetkých dostupných zdrojov v produkčnej infraštruktúre. Preto sa chcem uistiť, že náhle, kvôli chybe operátora alebo nie, používateľská vyrovnávacia pamäť nespotrebováva viac zdrojov, ako je pridelené. To znamená, že musíme obmedziť zdroje. Ale s čím by sme mohli kvótu viazať?

Vráťme sa k nášmu výrazne zjednodušenému diagramu interakcie komponentov a prekreslite ho s ďalšími podrobnosťami - takto:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Čo vám padne do oka:

  • Webové rozhranie a hudba používajú izolované klastre rovnakého aplikačného servera.
  • Môžeme rozlíšiť logické vrstvy, do ktorých tieto klastre patria: fronty, cache, dátové úložisko a vrstva správy.
  • Frontend je heterogénny, pozostáva z rôznych funkčných subsystémov.
  • Vyrovnávacie pamäte môžu byť tiež roztrúsené po podsystéme, ktorého údaje ukladajú do vyrovnávacej pamäte.

Prekreslíme obrázok znova:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Bach! Áno, vidíme hierarchiu! To znamená, že môžete distribuovať zdroje vo väčších častiach: priraďte zodpovedného vývojára k uzlu tejto hierarchie zodpovedajúcemu funkčnému subsystému (ako „hudba“ na obrázku) a priraďte kvótu na rovnakú úroveň hierarchie. Táto hierarchia nám tiež umožňuje flexibilnejšie organizovať služby pre uľahčenie správy. Napríklad celý web, keďže ide o veľmi veľké zoskupenie serverov, rozdeľujeme na niekoľko menších skupín, ktoré sú na obrázku znázornené ako skupina1, skupina2.

Odstránením nadbytočných riadkov môžeme napísať každý uzol nášho obrázka v plochejšom tvare: group1.web.front, api.music.front, user-cache.cache.

Takto sa dostávame k pojmu „hierarchický front“. Má názov ako „group1.web.front“. Je mu priradená kvóta pre zdroje a používateľské práva. Dáme tomu človeku z DevOps práva na odoslanie služby do frontu a takýto zamestnanec môže spustiť niečo vo fronte a ten človek z OpsDev bude mať administrátorské práva a teraz môže front spravovať, prideľovať tam ľudí, dať týmto ľuďom práva atď. Služby spustené v tomto fronte budú bežať v rámci kvóty frontu. Ak výpočtová kvóta frontu nestačí na spustenie všetkých služieb naraz, potom sa budú vykonávať postupne, čím sa vytvorí samotný front.

Pozrime sa bližšie na služby. Služba má plne kvalifikovaný názov, ktorý vždy obsahuje názov frontu. Potom bude mať predná webová služba názov ok-web.group1.web.front. A zavolá sa služba aplikačného servera, ku ktorej pristupuje ok-app.group1.web.front. Každá služba má manifest, ktorý špecifikuje všetky potrebné informácie pre umiestnenie na konkrétnych strojoch: koľko zdrojov táto úloha spotrebúva, aká konfigurácia je pre ňu potrebná, koľko replík by malo byť, vlastnosti na riešenie zlyhaní tejto služby. A po umiestnení služby priamo na stroje sa objavia jej inštancie. Sú tiež pomenované jednoznačne - ako číslo inštancie a názov služby: 1.ok-web.group1.web.front, 2.ok-web.group1.web.front, …

To je veľmi výhodné: pohľadom iba na názov bežiaceho kontajnera môžeme okamžite zistiť veľa.

Teraz sa pozrime bližšie na to, čo tieto inštancie skutočne vykonávajú: úlohy.

Triedy izolácie úloh

Všetky úlohy v OK (a pravdepodobne všade) možno rozdeliť do skupín:

  • Short Latency Tasks - prod. Pri takýchto úlohách a službách je veľmi dôležité oneskorenie odozvy (latencia), ako rýchlo bude každá z požiadaviek systémom spracovaná. Príklady úloh: webové fronty, vyrovnávacie pamäte, aplikačné servery, úložisko OLTP atď.
  • Problémy s výpočtom - dávka. Rýchlosť spracovania každej konkrétnej požiadavky tu nie je dôležitá. Pre nich je dôležité, koľko výpočtov táto úloha urobí za určitý (dlhý) časový úsek (priepustnosť). Pôjde o ľubovoľné úlohy MapReduce, Hadoop, strojové učenie, štatistiky.
  • Úlohy na pozadí - nečinné. Pre takéto úlohy nie je veľmi dôležitá ani latencia, ani priepustnosť. To zahŕňa rôzne testy, migrácie, prepočty a konverziu údajov z jedného formátu do druhého. Na jednej strane sú podobné vypočítaným, na druhej strane je pre nás úplne jedno, ako rýchlo sú dokončené.

Pozrime sa, ako takéto úlohy spotrebúvajú zdroje, napríklad centrálny procesor.

Úlohy s krátkym oneskorením. Takáto úloha bude mať vzor spotreby CPU podobný tomuto:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Prijme sa požiadavka od užívateľa na spracovanie, úloha začne využívať všetky dostupné jadrá CPU, spracuje ju, vráti odpoveď, čaká na ďalšiu požiadavku a zastaví sa. Prišla ďalšia požiadavka - opäť sme vybrali všetko, čo tam bolo, vypočítali a čakáme na ďalšiu.

Aby sme zaručili minimálnu latenciu takejto úlohy, musíme zobrať maximum zdrojov, ktoré spotrebúva, a rezervovať požadovaný počet jadier na minione (stroji, ktorý úlohu vykoná). Potom bude vzorec rezervácie pre náš problém vyzerať takto:

alloc: cpu = 4 (max)

a ak máme minion stroj so 16 jadrami, tak sa naň dajú umiestniť presne štyri takéto úlohy. Zvlášť si všimneme, že priemerná spotreba procesora takýchto úloh je často veľmi nízka - čo je zrejmé, pretože značnú časť času úloha čaká na požiadavku a nerobí nič.

Výpočtové úlohy. Ich vzor sa bude mierne líšiť:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Priemerná spotreba zdrojov CPU pri takýchto úlohách je pomerne vysoká. Často chceme, aby sa výpočtová úloha dokončila za určitý čas, takže musíme vyhradiť minimálny počet procesorov, ktoré potrebuje, aby bol celý výpočet dokončený v prijateľnom čase. Jeho rezervačný vzorec bude vyzerať takto:

alloc: cpu = [1,*)

"Prosím, umiestnite to na miniona, kde je aspoň jedno voľné jadro, a potom, koľko ich bude, zožerie všetko."

Tu je efektivita použitia už oveľa lepšia ako pri úlohách s krátkym oneskorením. Ale zisk bude oveľa väčší, ak skombinujete oba typy úloh na jednom stroji miniona a budete distribuovať jeho zdroje na cestách. Keď úloha s krátkym oneskorením vyžaduje procesor, dostane ho okamžite a keď už zdroje nie sú potrebné, prenesú sa do výpočtovej úlohy, t.j.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Ale ako na to?

Najprv sa pozrime na prod a jeho alloc: cpu = 4. Musíme si rezervovať štyri jadrá. Pri spustení Docker to možno vykonať dvoma spôsobmi:

  • Pomocou voľby --cpuset=1-4t.j. prideliť štyri špecifické jadrá na stroji pre úlohu.
  • použitie --cpuquota=400_000 --cpuperiod=100_000, priraďte kvótu pre čas procesora, t. j. uveďte, že každých 100 ms reálneho času úloha nespotrebuje viac ako 400 ms času procesora. Získajú sa rovnaké štyri jadrá.

Ktorá z týchto metód je však vhodná?

cpuset vyzerá celkom atraktívne. Úloha má štyri vyhradené jadrá, čo znamená, že vyrovnávacie pamäte procesora budú fungovať čo najefektívnejšie. To má aj nevýhodu: museli by sme prevziať úlohu distribúcie výpočtov medzi nezaťažené jadrá stroja namiesto OS, a to je dosť netriviálna úloha, najmä ak sa snažíme umiestniť dávkové úlohy na takéto stroj. Testy ukázali, že možnosť s kvótou je tu vhodnejšia: takto má operačný systém väčšiu voľnosť pri výbere jadra na vykonanie úlohy v aktuálnom momente a čas procesora je distribuovaný efektívnejšie.

Poďme zistiť, ako urobiť rezervácie v Docker na základe minimálneho počtu jadier. Kvóta pre dávkové úlohy už neplatí, pretože nie je potrebné obmedzovať maximum, stačí len garantovať minimum. A tu sa táto možnosť dobre hodí docker run --cpushares.

Dohodli sme sa, že ak si šarža vyžaduje záruku aspoň na jedno jadro, tak uvádzame --cpushares=1024, a ak existujú aspoň dve jadrá, potom uvedieme --cpushares=2048. Zdieľania CPU nijako nezasahujú do rozloženia procesorového času, pokiaľ je ho dostatok. Ak teda prod momentálne nepoužíva všetky svoje štyri jadrá, nie je nič obmedzujúce dávkové úlohy a môžu využívať dodatočný čas procesora. Ale v situácii, keď je nedostatok procesorov, ak produkt spotreboval všetky štyri svoje jadrá a dosiahol svoju kvótu, zostávajúci čas procesora sa rozdelí úmerne medzi procesory, t. j. v situácii troch voľných jadier bude jedno pridelené úlohe s 1024 cpushares a zvyšné dva budú pridelené úlohe s 2048 cpushares.

Používanie kvót a podielov však nestačí. Musíme sa uistiť, že úloha s krátkym oneskorením má pri prideľovaní času procesora prednosť pred dávkovou úlohou. Bez takéhoto uprednostňovania zaberie dávková úloha celý čas procesora v momente, keď ju produkt potrebuje. Pri spustení Dockera nie sú k dispozícii žiadne možnosti uprednostňovania kontajnerov, ale politiky plánovača procesora Linux sa hodia. Môžete si o nich prečítať podrobne tua v rámci tohto článku si ich stručne prejdeme:

  • SCHED_OTHER
    V predvolenom nastavení prijímajú všetky bežné používateľské procesy na počítači so systémom Linux.
  • SCHED_BATCH
    Navrhnuté pre procesy náročné na zdroje. Pri umiestnení úlohy na procesor sa zavedie takzvaná aktivačná penalizácia: pri takejto úlohe je menej pravdepodobné, že prijme prostriedky procesora, ak ju práve používa úloha s SCHED_OTHER
  • SCHED_IDLE
    Proces na pozadí s veľmi nízkou prioritou, dokonca nižšou ako pekných -19. Používame našu open source knižnicu jedno-nio, aby ste nastavili potrebnú politiku pri spúšťaní kontajnera volaním

one.nio.os.Proc.sched_setscheduler( pid, Proc.SCHED_IDLE )

Ale aj keď neprogramujete v Jave, to isté sa dá urobiť pomocou príkazu chrt:

chrt -i 0 $pid

Pre prehľadnosť zhrňme všetky naše úrovne izolácie do jednej tabuľky:

Trieda izolácie
Príklad Alloc
Možnosti spustenia Docker
sched_setscheduler chrt*

Podnecovať
CPU = 4
--cpuquota=400000 --cpuperiod=100000
SCHED_OTHER

Dávka
CPU = [1, *)
--cpushares=1024
SCHED_BATCH

Lenivý
CPU = [2, *)
--cpushares=2048
SCHED_IDLE

*Ak robíte chrt zvnútra kontajnera, možno budete potrebovať schopnosť sys_nice, pretože v predvolenom nastavení Docker túto možnosť pri spustení kontajnera odstráni.

Úlohy však spotrebúvajú nielen procesor, ale aj prevádzku, čo ovplyvňuje latenciu sieťovej úlohy ešte viac ako nesprávne prideľovanie zdrojov procesora. Preto prirodzene chceme získať presne rovnaký obraz o premávke. To znamená, že keď prod úloha posiela nejaké pakety do siete, obmedzíme maximálnu rýchlosť (vzorec alloc: lan=[*,500 Mb/s) ), s ktorým to prod dokáže. A pre dávku garantujeme len minimálnu priepustnosť, ale neobmedzujeme maximálnu (vzorec alloc: lan=[10Mbps,*) ) V tomto prípade by prevádzka produktov mala dostať prednosť pred dávkovými úlohami.
Tu Docker nemá žiadne primitívy, ktoré by sme mohli použiť. Ale prichádza nám na pomoc Kontrola premávky v systéme Linux. Pomocou disciplíny sme dokázali dosiahnuť želaný výsledok Hierarchická krivka spravodlivých služieb. S jeho pomocou rozlišujeme dve triedy prevádzky: prod s vysokou prioritou a dávka/nečinnosť s nízkou prioritou. V dôsledku toho je konfigurácia pre odchádzajúce prenosy takáto:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

tu je 1:0 „koreňový disk qdisc“ disciplíny hsfc; 1:1 - podriadená trieda hsfc s celkovým limitom šírky pásma 8 Gbit/s, pod ktorou sú umiestnené podradené triedy všetkých kontajnerov; 1:2 - podriadená trieda hsfc je spoločná pre všetky dávkové a nečinné úlohy s „dynamickým“ limitom, ktorý je popísaný nižšie. Zostávajúce podradené triedy hsfc sú vyhradené triedy pre aktuálne spustené kontajnery produktov s limitmi zodpovedajúcimi ich manifestom – 450 a 400 Mbit/s. Každá trieda hsfc má priradený qdisc queue fq alebo fq_codel, v závislosti od verzie jadra Linuxu, aby sa predišlo strate paketov počas zhlukov prevádzky.

Disciplíny tc zvyčajne slúžia na uprednostnenie iba odchádzajúcej prevádzky. Chceme však uprednostniť aj prichádzajúcu premávku - koniec koncov, niektorá dávková úloha môže ľahko vybrať celý prichádzajúci kanál, pričom napríklad dostane veľkú dávku vstupných údajov pre map&reduce. Na tento účel používame modul ifb, ktorý vytvára virtuálne rozhranie ifbX pre každé sieťové rozhranie a presmeruje prichádzajúcu prevádzku z rozhrania na odchádzajúce na ifbX. Ďalej, pre ifbX fungujú všetky rovnaké disciplíny na riadenie odchádzajúcej prevádzky, pre ktorú bude konfigurácia hsfc veľmi podobná:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Počas experimentov sme zistili, že hsfc vykazuje najlepšie výsledky, keď je trieda 1:2 neprioritnej dávkovej/nečinnej prevádzky obmedzená na strojoch minion na nie viac ako určitý voľný pruh. V opačnom prípade má neprioritná prevádzka príliš veľký vplyv na latenciu prod úloh. miniond určuje aktuálne množstvo voľnej šírky pásma každú sekundu, pričom meria priemernú spotrebu prevádzky všetkých prod úloh daného miniona One-cloud - OS na úrovni dátového centra v Odnoklassniki a odpočítaním od šírky pásma sieťového rozhrania One-cloud - OS na úrovni dátového centra v Odnoklassniki s malou rezervou, t.j.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Pásma sú definované nezávisle pre prichádzajúcu a odchádzajúcu prevádzku. A podľa nových hodnôt miniond prekonfiguruje limit neprioritnej triedy 1:2.

Takto sme implementovali všetky tri triedy izolácie: prod, batch a idle. Tieto triedy výrazne ovplyvňujú výkonové charakteristiky úloh. Preto sme sa rozhodli umiestniť tento atribút na vrchol hierarchie, aby pri pohľade na názov hierarchického frontu bolo hneď jasné, s čím máme do činenia:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Všetci naši priatelia web и hudba fronty sú potom umiestnené v hierarchii pod prod. Napríklad pod dávku umiestnime službu hudobný katalóg, ktorá pravidelne zostavuje katalóg skladieb zo súboru mp3 súborov nahraných do Odnoklassniki. Príkladom služby v nečinnosti by bolo hudobný transformátor, ktorý normalizuje úroveň hlasitosti hudby.

Po opätovnom odstránení nadbytočných riadkov môžeme písať názvy našich služieb plochejšie pridaním triedy izolácie úloh na koniec úplného názvu služby: web.front.prod, katalóg.hudba.dávka, transformátor.hudba.nečinný.

A teraz, keď sa pozrieme na názov služby, chápeme nielen to, akú funkciu vykonáva, ale aj triedu izolácie, čo znamená jej kritickosť atď.

Všetko je skvelé, no je tu jedna trpká pravda. Úlohy bežiace na jednom počítači nie je možné úplne izolovať.

Čo sa nám podarilo dosiahnuť: ak dávka intenzívne spotrebuje iba CPU zdroje, potom vstavaný plánovač CPU Linuxu robí svoju prácu veľmi dobre a prakticky nemá žiadny vplyv na úlohu produktu. Ale ak táto dávková úloha začne aktívne pracovať s pamäťou, potom sa už objaví vzájomný vplyv. Stáva sa to preto, že produkčná úloha je „vymývaná“ z vyrovnávacej pamäte procesora – v dôsledku toho sa zmeškania vyrovnávacej pamäte zvyšujú a procesor spracováva produkčnú úlohu pomalšie. Takáto dávková úloha môže zvýšiť latenciu nášho typického kontajnera na produkty o 10 %.

Izolácia prevádzky je ešte zložitejšia, pretože moderné sieťové karty majú internú frontu paketov. Ak sa tam dostane paket z dávkovej úlohy ako prvý, potom bude prvý, ktorý sa prenesie cez kábel, a nedá sa s tým nič robiť.

Okrem toho sa nám zatiaľ podarilo vyriešiť len problém uprednostňovania TCP prevádzky: hsfc prístup nefunguje pre UDP. A dokonca aj v prípade prevádzky TCP, ak dávková úloha generuje veľa prevádzky, tiež to vedie k približne 10% zvýšeniu oneskorenia prod úlohy.

odolnosť proti chybám

Jedným z cieľov pri vývoji jedného cloudu bolo zlepšiť odolnosť Odnoklassniki voči chybám. Preto by som v ďalšom rád podrobnejšie zvážil možné scenáre porúch a nehôd. Začnime jednoduchým scenárom – poruchou kontajnera.

Samotný kontajner môže zlyhať niekoľkými spôsobmi. Môže to byť nejaký druh experimentu, chyba alebo chyba v manifeste, kvôli ktorej začne prod úloha spotrebúvať viac zdrojov, ako je uvedené v manifeste. Mali sme prípad: vývojár implementoval jeden zložitý algoritmus, mnohokrát ho prerábal, premýšľal a bol taký zmätený, že sa problém nakoniec dostal do veľmi netriviálnej slučky. A keďže prod úloha má vyššiu prioritu ako všetky ostatné na rovnakých prisluhovačoch, začala spotrebúvať všetky dostupné procesorové zdroje. V tejto situácii zachránila deň izolácia alebo skôr kvóta času CPU. Ak je úlohe pridelená kvóta, úloha nespotrebuje viac. Preto dávkové a iné prod úlohy, ktoré bežali na rovnakom stroji, si nič nevšimli.

Druhým možným problémom je pád nádoby. A tu nás zachraňujú politiky reštartu, každý ich pozná, samotný Docker odvádza skvelú prácu. Takmer všetky úlohy produktu majú politiku vždy reštartu. Niekedy používame on_failure pre dávkové úlohy alebo pre ladenie prod kontajnerov.

Čo môžete urobiť, ak celý minion nie je dostupný?

Samozrejme, spustite kontajner na inom stroji. Zaujímavou časťou je, čo sa stane s IP adresou (adresami) pridelenou kontajneru.

Kontajnerom môžeme priradiť rovnaké IP adresy ako minionovým strojom, na ktorých tieto kontajnery bežia. Potom, keď sa kontajner spustí na inom počítači, jeho IP adresa sa zmení a všetci klienti musia pochopiť, že kontajner sa presunul, a teraz musia prejsť na inú adresu, čo si vyžaduje samostatnú službu Service Discovery.

Zisťovanie služby je pohodlné. Na trhu existuje mnoho riešení s rôznym stupňom odolnosti voči chybám na organizáciu registra služieb. Takéto riešenia často implementujú logiku vyrovnávania záťaže, ukladajú dodatočnú konfiguráciu vo forme úložiska KV atď.
Chceli by sme sa však vyhnúť potrebe implementácie samostatného registra, pretože by to znamenalo zavedenie kritického systému, ktorý využívajú všetky služby vo výrobe. To znamená, že toto je potenciálny bod zlyhania a musíte si vybrať alebo vyvinúť riešenie veľmi odolné voči chybám, čo je samozrejme veľmi ťažké, časovo náročné a drahé.

A ešte jeden veľký nedostatok: aby naša stará infraštruktúra fungovala s novou, museli by sme prepísať úplne všetky úlohy, aby sme používali nejaký systém Service Discovery. Je tu veľa práce a na niektorých miestach je to takmer nemožné, pokiaľ ide o nízkoúrovňové zariadenia, ktoré pracujú na úrovni jadra operačného systému alebo priamo s hardvérom. Implementácia tejto funkcionality pomocou zavedených vzorov riešení, ako napr postranný vozík by na niektorých miestach znamenalo dodatočné zaťaženie, na iných - komplikáciu prevádzky a ďalšie scenáre porúch. Nechceli sme veci skomplikovať, a tak sme sa rozhodli, že používanie funkcie Service Discovery bude voliteľné.

V jednom cloude IP nasleduje kontajner, t.j. každá inštancia úlohy má svoju vlastnú IP adresu. Táto adresa je „statická“: je priradená každej inštancii pri prvom odoslaní služby do cloudu. Ak mala služba počas svojej životnosti iný počet inštancií, potom jej bude nakoniec pridelených toľko IP adries, koľko bolo maximálnych inštancií.

Následne sa tieto adresy nemenia: sú pridelené raz a naďalej existujú počas životnosti služby vo výrobe. IP adresy sledujú kontajnery v celej sieti. Ak je kontajner prenesený na iného miniona, adresa bude nasledovať za ním.

Mapovanie názvu služby na jeho zoznam IP adries sa teda mení veľmi zriedka. Ak sa znova pozriete na názvy inštancií služieb, ktoré sme spomenuli na začiatku článku (1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, …), všimneme si, že sa podobajú na FQDN používané v DNS. Správne, na mapovanie názvov inštancií služieb na ich adresy IP používame protokol DNS. Okrem toho tento DNS vracia všetky rezervované IP adresy všetkých kontajnerov – spustených aj zastavených (povedzme, že sú použité tri repliky a máme tam rezervovaných päť adries – vráti sa všetkých päť). Klienti, ktorí dostanú tieto informácie, sa pokúsia nadviazať spojenie so všetkými piatimi replikami – a tak určiť tie, ktoré fungujú. Táto možnosť určovania dostupnosti je oveľa spoľahlivejšia, nezahŕňa DNS ani zisťovanie služby, čo znamená, že neexistujú žiadne zložité problémy na vyriešenie pri zabezpečovaní relevantnosti informácií a odolnosti týchto systémov voči chybám. Navyše v kritických službách, od ktorých závisí chod celého portálu, nemôžeme vôbec používať DNS, ale jednoducho zadať IP adresy do konfigurácie.

Implementácia takéhoto prenosu IP za kontajnermi môže byť netriviálna – a my sa pozrieme na to, ako to funguje na nasledujúcom príklade:

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Povedzme, že majster jedného cloudu dá príkaz minionovi M1, aby sa spustil 1.ok-web.group1.web.front.prod s adresou 1.1.1.1. Pracuje na prisluhovači BIRD, ktorý túto adresu inzeruje na špeciálnych serveroch reflektor trasy. Tie majú reláciu BGP so sieťovým hardvérom, do ktorej je preložená trasa adresy 1.1.1.1 na M1. M1 smeruje pakety do kontajnera pomocou Linuxu. Existujú tri servery odrážajúce trasy, pretože ide o veľmi kritickú časť infraštruktúry jedného cloudu - bez nich nebude sieť v jednom cloude fungovať. Umiestňujeme ich do rôznych stojanov, pokiaľ možno umiestnených v rôznych miestnostiach dátového centra, aby sme znížili pravdepodobnosť zlyhania všetkých troch súčasne.

Predpokladajme teraz, že sa stratí spojenie medzi jedným cloudovým majstrom a M1 minionom. Majster jedného cloudu bude teraz konať za predpokladu, že M1 úplne zlyhal. To znamená, že dá príkaz minionu M2 na spustenie web.group1.web.front.prod s rovnakou adresou 1.1.1.1. Teraz máme dve konfliktné trasy v sieti pre 1.1.1.1: na M1 a na M2. Na vyriešenie takýchto konfliktov používame Multi Exit Discriminator, ktorý je špecifikovaný v oznámení BGP. Toto je číslo, ktoré ukazuje váhu inzerovanej trasy. Spomedzi konfliktných trás sa vyberie trasa s nižšou hodnotou MED. Jeden cloud master podporuje MED ako integrálnu súčasť IP adries kontajnera. Prvýkrát je adresa zapísaná s dostatočne veľkým MED = 1 000 000. V situácii takéhoto núdzového presunu kontajnera kapitán zníži MED a M2 už dostane príkaz na reklamu adresy 1.1.1.1 s MED = 999 999. Inštancia bežiaca na M1 zostane v tomto prípade bez spojenia a jeho ďalší osud nás málo zaujíma, kým sa spojenie s majstrom neobnoví, keď bude zastavený ako starý záber.

Nehody

Všetky systémy riadenia dátových centier vždy riešia menšie zlyhania prijateľne. Pretečenie kontajnerov je štandardom takmer všade.

Pozrime sa, ako riešime núdzovú situáciu, napríklad výpadok prúdu v jednej alebo viacerých miestnostiach dátového centra.

Čo znamená nehoda pre systém riadenia dátového centra? V prvom rade ide o masívne jednorazové zlyhanie mnohých strojov a riadiaci systém potrebuje migrovať veľa kontajnerov súčasne. Ak je však katastrofa veľmi rozsiahla, môže sa stať, že všetky úlohy nebude možné opätovne prideliť iným prisluhovačom, pretože kapacita zdrojov dátového centra klesne pod 100 % záťaže.

Nehody sú často sprevádzané zlyhaním riadiacej vrstvy. Môže sa to stať v dôsledku zlyhania jeho zariadenia, ale častejšie v dôsledku toho, že nehody nie sú testované a samotná riadiaca vrstva klesá v dôsledku zvýšeného zaťaženia.

Čo s tým všetkým môžete urobiť?

Hromadné migrácie znamenajú, že v infraštruktúre prebieha veľké množstvo aktivít, migrácií a nasadení. Každá z migrácií môže nejaký čas trvať, kým sa doručia a rozbalia obrazy kontajnerov prisluhovačom, spustia a inicializujú kontajnery atď. Preto je žiaduce, aby sa dôležitejšie úlohy spustili pred menej dôležitými.

Pozrime sa znova na hierarchiu služieb, ktoré poznáme, a skúsme sa rozhodnúť, ktoré úlohy chceme spustiť ako prvé.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Samozrejme, sú to procesy, ktoré sa priamo podieľajú na vybavovaní požiadaviek používateľov, teda prod. Označujeme to pomocou priorita umiestnenia — číslo, ktoré možno priradiť do frontu. Ak má front vyššiu prioritu, jeho služby sú umiestnené ako prvé.

Na prod priradíme vyššie priority, 0; v dávke - o niečo nižšie, 100; pri nečinnosti - ešte nižšie, 200. Priority sa uplatňujú hierarchicky. Všetky úlohy nižšie v hierarchii budú mať zodpovedajúcu prioritu. Ak chceme, aby sa cache vo vnútri produktu spúšťali pred frontendami, potom priradíme priority cache = 0 a front subqueues = 1. Ak napríklad chceme, aby bol hlavný portál spustený najskôr z frontu a iba front s hudbou potom môžeme tomu druhému priradiť nižšiu prioritu – 10.

Ďalším problémom je nedostatok zdrojov. Zlyhalo teda veľké množstvo zariadení, celé haly dátového centra a znovu sme spustili toľko služieb, že teraz nie je dostatok zdrojov pre každého. Musíte sa rozhodnúť, ktoré úlohy obetujete, aby ste udržali hlavné kritické služby v prevádzke.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Na rozdiel od priority umiestnenia nemôžeme bez rozdielu obetovať všetky dávkové úlohy, niektoré z nich sú dôležité pre chod portálu. Preto sme zvýraznili samostatne predkupné právo úlohy. Po umiestnení môže úloha s vyššou prioritou zabrániť, t.j. zastaviť úlohu s nižšou prioritou, ak už nie sú žiadni voľní prisluhovači. V tomto prípade úloha s nízkou prioritou pravdepodobne zostane neumiestnená, t. j. už pre ňu nebude vhodný prisluhovač s dostatkom voľných zdrojov.

V našej hierarchii je veľmi jednoduché určiť prioritu preempcie tak, že prod a dávkové úlohy predchádzajú alebo zastavujú nečinné úlohy, ale nie navzájom, a to tak, že určíme prioritu pre nečinnosť rovnú 200. Rovnako ako v prípade priority umiestnenia, môže použiť našu hierarchiu na opis zložitejších pravidiel. Povedzme napríklad, že obetujeme funkciu hudby, ak nemáme dostatok zdrojov pre hlavný webový portál, pričom prioritu pre príslušné uzly nastavíme nižšie: 10.

Celé nehody DC

Prečo môže zlyhať celé dátové centrum? Element. Bol to dobrý príspevok hurikán ovplyvnil prácu dátového centra. Za živly možno považovať bezdomovcov, ktorí kedysi spálili optiku v rozdeľovači a dátové centrum úplne stratilo kontakt s inými lokalitami. Príčinou zlyhania môže byť aj ľudský faktor: operátor vydá taký príkaz, že spadne celé dátové centrum. Môže sa to stať v dôsledku veľkej chyby. Vo všeobecnosti nie je kolaps dátových centier nezvyčajný. Toto sa nám stáva raz za pár mesiacov.

A to je to, čo robíme, aby sme zabránili komukoľvek tweetovať #živý.

Prvou stratégiou je izolácia. Každá inštancia jedného cloudu je izolovaná a môže spravovať stroje iba v jednom dátovom centre. To znamená, že strata cloudu v dôsledku chýb alebo nesprávnych príkazov operátora je stratou iba jedného dátového centra. Sme na to pripravení: máme politiku redundancie, v ktorej sú repliky aplikácie a dát umiestnené vo všetkých dátových centrách. Používame databázy odolné voči chybám a pravidelne testujeme chyby.
Od dnešného dňa máme štyri dátové centrá, to znamená štyri samostatné, úplne izolované inštancie jedného cloudu.

Tento prístup chráni nielen pred fyzickým zlyhaním, ale môže chrániť aj pred chybou operátora.

Čo iné sa dá robiť s ľudským faktorom? Keď operátor zadá cloudu nejaký zvláštny alebo potenciálne nebezpečný príkaz, môže byť zrazu požiadaný, aby vyriešil malý problém, aby zistil, ako dobre to myslel. Napríklad, ak ide o nejaké hromadné zastavenie mnohých replík alebo len o zvláštny príkaz - zníženie počtu replík alebo zmena názvu obrázka, a nielen čísla verzie v novom manifeste.

One-cloud - OS na úrovni dátového centra v Odnoklassniki

Výsledky

Charakteristické vlastnosti jedného cloudu:

  • Hierarchická a vizuálna schéma pomenovania služieb a kontajnerov, ktorá umožňuje veľmi rýchlo zistiť, o akú úlohu ide, čoho sa týka a ako funguje a kto je za ňu zodpovedný.
  • Aplikujeme naše technika kombinovania produktov a šaržíúlohy na prisluhovačoch na zlepšenie efektívnosti zdieľania strojov. Namiesto cpuset používame CPU kvóty, zdieľania, zásady plánovača CPU a Linux QoS.
  • Kontajnery bežiace na tom istom stroji nebolo možné úplne izolovať, ale ich vzájomný vplyv zostáva do 20 %.
  • Usporiadanie služieb do hierarchie pomáha pri automatickej obnove po havárii priority umiestňovania a preempcie.

FAQ

Prečo sme nezobrali hotové riešenie?

  • Rôzne triedy izolácie úloh vyžadujú pri umiestnení na prisluhovačov odlišnú logiku. Ak je možné zadať prod úlohy jednoduchou rezerváciou zdrojov, potom sa musia umiestniť dávkové a nečinné úlohy, ktoré sledujú skutočné využitie zdrojov na strojoch minion.
  • Potreba brať do úvahy zdroje spotrebované úlohami, ako sú:
    • šírka pásma siete;
    • typy a „vretená“ diskov.
  • Potreba označovania priorít služieb pri reakcii na núdzové situácie, práva a kvóty príkazov pre zdroje, čo je riešené pomocou hierarchických frontov v jednom cloude.
  • Potreba pomenovať kontajnery ľuďmi, aby sa skrátil čas odozvy na nehody a incidenty
  • Nemožnosť jednorazovej rozsiahlej implementácie Service Discovery; potreba dlho koexistovať s úlohami hostenými na hardvérových hostiteľoch – niečo, čo je riešené „statickými“ IP adresami nasledujúcimi po kontajneroch, a v dôsledku toho potreba jedinečnej integrácie s veľkou sieťovou infraštruktúrou.

Všetky tieto funkcie by si vyžadovali výrazné úpravy existujúcich riešení tak, aby nám vyhovovali, a po zhodnotení množstva práce sme si uvedomili, že dokážeme vyvinúť vlastné riešenie s približne rovnakými mzdovými nákladmi. Vaše riešenie bude ale oveľa jednoduchšie na obsluhu a vývoj – neobsahuje zbytočné abstrakcie, ktoré podporujú funkcionalitu, ktorú nepotrebujeme.

Tým, ktorí čítajú posledné riadky, ďakujem za trpezlivosť a pozornosť!

Zdroj: hab.com

Pridať komentár