Jedan oblak - OS na nivou data centra u Odnoklassniki

Jedan oblak - OS na nivou data centra u Odnoklassniki

Aloha, ljudi! Moje ime je Oleg Anastasjev, radim u Odnoklassniki u timu Platforme. A osim mene, u Odnoklassniki radi mnogo hardvera. Imamo četiri data centra sa oko 500 rekova sa više od 8 hiljada servera. U određenom trenutku smo shvatili da će nam uvođenje novog sistema upravljanja omogućiti efikasnije učitavanje opreme, olakšati upravljanje pristupom, automatizovati (pre)distribuciju računarskih resursa, ubrzati pokretanje novih usluga i ubrzati odgovore. do nesreća velikih razmjera.

Šta je iz toga proizašlo?

Pored mene i gomile hardvera, tu su i ljudi koji rade sa ovim hardverom: inženjeri koji se nalaze direktno u data centrima; mrežari koji postavljaju mrežni softver; administratori, ili SRE, koji pružaju otpornost infrastrukture; i razvojni timovi, svaki od njih je odgovoran za dio funkcija portala. Softver koji kreiraju radi otprilike ovako:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Zahtjevi korisnika primaju se i na frontovima glavnog portala www.ok.ru, i na drugim, na primjer na frontovima muzičkog API-ja. Za obradu poslovne logike pozivaju aplikacijski server, koji prilikom obrade zahtjeva poziva potrebne specijalizirane mikroservise - one-graph (graf društvenih veza), user-cache (cache korisničkih profila) itd.

Svaki od ovih servisa je raspoređen na mnogo mašina, a svaki od njih ima odgovorne programere odgovorne za funkcionisanje modula, njihov rad i tehnološki razvoj. Svi ovi servisi rade na hardverskim serverima, a donedavno smo pokretali tačno jedan zadatak po serveru, odnosno bio je specijaliziran za određeni zadatak.

Žašto je to? Ovaj pristup je imao nekoliko prednosti:

  • Laknulo masovno upravljanje. Recimo da zadatak zahtijeva neke biblioteke, neke postavke. Zatim se server dodjeljuje tačno jednoj specifičnoj grupi, opisuje se politika cfengine za ovu grupu (ili je već opisana), a ova konfiguracija se centralno i automatski uvodi na sve servere u ovoj grupi.
  • Pojednostavljeno dijagnostika. Recimo da pogledate povećano opterećenje centralnog procesora i shvatite da ovo opterećenje može generirati samo zadatak koji se izvodi na ovom hardverskom procesoru. Potraga za okrivljenim završava se vrlo brzo.
  • Pojednostavljeno praćenje. Ako nešto nije u redu sa serverom, monitor to prijavljuje, a vi tačno znate ko je kriv.

Servisu koji se sastoji od nekoliko replika dodijeljeno je nekoliko servera - po jedan za svaki. Tada se računski resurs za uslugu dodjeljuje vrlo jednostavno: broj servera koje usluga ima, maksimalna količina resursa koju može potrošiti. “Lako” ovdje ne znači da je jednostavan za korištenje, već u smislu da se raspodjela resursa vrši ručno.

Ovaj pristup nam je također omogućio specijalizirane željezne konfiguracije za zadatak koji se izvodi na ovom serveru. Ako zadatak pohranjuje velike količine podataka, tada koristimo 4U server sa šasijom sa 38 diskova. Ako je zadatak isključivo računski, onda možemo kupiti jeftiniji 1U server. Ovo je računski efikasno. Između ostalog, ovaj pristup nam omogućava da koristimo četiri puta manje mašina sa opterećenjem uporedivim sa jednom prijateljskom društvenom mrežom.

Ovakva efikasnost u korišćenju računarskih resursa trebalo bi da obezbedi i ekonomsku efikasnost, ako polazimo od pretpostavke da su najskuplji serveri. Dugo vremena je hardver bio najskuplji, a mi smo uložili mnogo truda da smanjimo cijenu hardvera, osmišljavajući algoritme tolerancije grešaka kako bismo smanjili zahtjeve za pouzdanost hardvera. I danas smo došli do faze u kojoj je cijena servera prestala da bude odlučujuća. Ako ne uzimate u obzir najnoviju egzotiku, onda specifična konfiguracija servera u stalku nije bitna. Sada imamo još jedan problem - cijenu prostora koji server zauzima u data centru, odnosno prostora u racku.

Shvativši da je to slučaj, odlučili smo da izračunamo koliko efikasno koristimo police.
Uzeli smo cijenu najmoćnijeg servera od ekonomski opravdanih, izračunali koliko takvih servera možemo smjestiti u rekove, koliko zadataka ćemo na njima izvoditi po starom modelu “jedan server = jedan zadatak” i koliko takvih servera zadaci mogu koristiti opremu. Brojali su i lili suze. Pokazalo se da je naša efikasnost u korištenju regala oko 11%. Zaključak je očigledan: moramo povećati efikasnost korišćenja data centara. Čini se da je rješenje očigledno: potrebno je pokrenuti nekoliko zadataka na jednom serveru odjednom. Ali tu počinju poteškoće.

Masovna konfiguracija postaje dramatično složenija - sada je nemoguće dodijeliti bilo koju grupu serveru. Uostalom, sada se na jednom serveru može pokrenuti nekoliko zadataka različitih naredbi. Osim toga, konfiguracija može biti u sukobu za različite aplikacije. Dijagnoza također postaje složenija: ako vidite povećanu potrošnju procesora ili diska na serveru, ne znate koji zadatak uzrokuje probleme.

Ali glavna stvar je da ne postoji izolacija između zadataka koji se izvršavaju na istoj mašini. Evo, na primjer, grafikona prosječnog vremena odgovora serverskog zadatka prije i nakon pokretanja druge računske aplikacije na istom serveru, ni na koji način u vezi s prvom – vrijeme odgovora glavnog zadatka je značajno povećano.

Jedan oblak - OS na nivou data centra u Odnoklassniki

Očigledno je potrebno da izvršavate zadatke ili u kontejnerima ili na virtuelnim mašinama. Budući da se gotovo svi naši zadaci pokreću pod jednim OS (Linux) ili su prilagođeni za njega, ne moramo podržavati mnogo različitih operativnih sistema. Shodno tome, virtuelizacija nije potrebna zbog dodatnih troškova, biće manje efikasna od kontejnerizacije.

Kao implementacija kontejnera za pokretanje zadataka direktno na serverima, Docker je dobar kandidat: slike sistema datoteka dobro rješavaju probleme s konfliktnim konfiguracijama. Činjenica da slike mogu biti sastavljene od nekoliko slojeva omogućava nam da značajno smanjimo količinu podataka potrebnih za njihovo postavljanje na infrastrukturu, odvajajući zajedničke dijelove u zasebne osnovne slojeve. Tada će se osnovni (i najobimniji) slojevi prilično brzo keširati kroz cijelu infrastrukturu, a da bi se isporučilo mnogo različitih tipova aplikacija i verzija, bit će potrebno prenijeti samo male slojeve.

Osim toga, gotovi registar i označavanje slika u Dockeru daju nam gotove primitive za verzioniranje i isporuku koda u produkciju.

Docker, kao i svaka druga slična tehnologija, pruža nam određeni nivo izolacije kontejnera iz kutije. Na primjer, izolacija memorije - svakom kontejneru je dato ograničenje upotrebe memorije stroja, preko kojeg se neće trošiti. Također možete izolirati kontejnere na osnovu korištenja CPU-a. Nama, međutim, standardna izolacija nije bila dovoljna. Ali više o tome u nastavku.

Direktno pokretanje kontejnera na serverima samo je dio problema. Drugi dio se odnosi na hostovanje kontejnera na serverima. Morate razumjeti koji kontejner se može postaviti na koji server. Ovo nije tako lak zadatak, jer kontejnere treba postaviti na servere što je gušće moguće bez smanjenja njihove brzine. Takvo postavljanje takođe može biti teško sa stanovišta tolerancije grešaka. Često želimo da postavimo replike iste usluge u različite police ili čak u različite prostorije data centra, tako da ako stalak ili soba pokvare, ne bismo odmah izgubili sve replike servisa.

Ručna distribucija kontejnera nije opcija kada imate 8 hiljada servera i 8-16 hiljada kontejnera.

Osim toga, željeli smo dati programerima veću nezavisnost u raspodjeli resursa kako bi sami mogli hostirati svoje usluge u produkciji, bez pomoći administratora. Istovremeno, željeli smo zadržati kontrolu kako neki manji servis ne bi potrošio sve resurse naših podatkovnih centara.

Očigledno, potreban nam je kontrolni sloj koji bi to radio automatski.

Tako smo došli do jednostavne i razumljive slike koju obožavaju svi arhitekti: tri kvadrata.

Jedan oblak - OS na nivou data centra u Odnoklassniki

one-cloud masters je klaster za nadilaženje greške odgovoran za orkestraciju oblaka. Programer šalje manifest masteru, koji sadrži sve informacije potrebne za hostovanje usluge. Na osnovu toga, gospodar daje komande odabranim minionima (mašinama dizajniranim za pokretanje kontejnera). Poslužnici imaju našeg agenta, koji prima komandu, izdaje njene komande Dockeru, a Docker konfiguriše jezgro Linuxa da pokrene odgovarajući kontejner. Pored izvršavanja naredbi, agent kontinuirano izvještava mastera o promjenama u stanju kako minion mašine tako i kontejnera koji se na njoj pokreću.

Alokacija resursa

Pogledajmo sada problem složenije distribucije resursa za mnoge sluge.

Računski resurs u jednom oblaku je:

  • Količina snage procesora koju troši određeni zadatak.
  • Količina memorije dostupne zadatku.
  • Mrežni promet. Svaki od miniona ima specifično mrežno sučelje s ograničenim propusnim opsegom, tako da je nemoguće distribuirati zadatke bez uzimanja u obzir količine podataka koje prenose preko mreže.
  • Diskovi. Osim toga, očito, prostoru za ove zadatke dodjeljujemo i tip diska: HDD ili SSD. Diskovi mogu poslužiti konačan broj zahtjeva u sekundi - IOPS. Stoga, za zadatke koji generiraju više IOPS-a nego što jedan disk može podnijeti, također dodjeljujemo “vretena” - to jest, disk uređaje koji moraju biti isključivo rezervirani za zadatak.

Zatim za neki servis, na primjer za korisnički keš, možemo snimiti potrošene resurse na ovaj način: 400 procesorskih jezgri, 2,5 TB memorije, 50 Gbit/s saobraćaja u oba smjera, 6 TB HDD prostora smještenog na 100 vretena. Ili u poznatijem obliku kao što je ovaj:

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

Resursi usluge predmemorije korisnika troše samo dio svih dostupnih resursa u proizvodnoj infrastrukturi. Stoga, želim biti siguran da odjednom, zbog greške operatera ili ne, korisnički keš memorija ne troši više resursa nego što mu je dodijeljeno. Odnosno, moramo ograničiti resurse. Ali za šta bismo mogli vezati kvotu?

Vratimo se našem uvelike pojednostavljenom dijagramu interakcije komponenti i precrtamo ga s više detalja - ovako:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Šta vam upada u oči:

  • Web frontend i muzika koriste izolovane klastere istog servera aplikacija.
  • Možemo razlikovati logičke slojeve kojima ovi klasteri pripadaju: frontovi, keš memorije, skladište podataka i sloj upravljanja.
  • Frontend je heterogen, sastoji se od različitih funkcionalnih podsistema.
  • Kešovi također mogu biti rasuti po podsistemu čije podatke keširaju.

Ponovo iscrtajmo sliku:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Bah! Da, vidimo hijerarhiju! To znači da možete distribuirati resurse u većim dijelovima: dodijeliti odgovornog programera čvoru ove hijerarhije koji odgovara funkcionalnom podsistemu (kao „muzika” na slici) i priložiti kvotu istom nivou hijerarhije. Ova hijerarhija nam takođe omogućava da fleksibilnije organizujemo usluge radi lakšeg upravljanja. Na primjer, cijeli web, pošto se radi o vrlo velikoj grupi servera, dijelimo na nekoliko manjih grupa, prikazanih na slici kao grupa1, grupa2.

Uklanjanjem dodatnih linija, možemo napisati svaki čvor naše slike u ravnijem obliku: group1.web.front, api.music.front, user-cache.cache.

Tako dolazimo do koncepta "hijerarhijskog reda". Ima ime poput "group1.web.front". Njemu je dodijeljena kvota za resurse i korisnička prava. Daćemo osobi iz DevOps-a prava da pošalje uslugu u red čekanja, i takav zaposlenik može pokrenuti nešto u redu, a osoba iz OpsDev-a će imati administratorska prava, a sada može upravljati redom, dodijeliti ljude tamo, dajte ovim ljudima prava, itd. Usluge koje se pokreću na ovom redu će se izvoditi unutar kvote reda. Ako računska kvota reda nije dovoljna za izvršavanje svih usluga odjednom, onda će se one izvršavati uzastopno, formirajući sam red.

Pogledajmo bliže usluge. Usluga ima potpuno kvalificirano ime, koje uvijek uključuje ime reda. Tada će prednji web servis imati ime ok-web.group1.web.front. I servis aplikacijskog servera kojem pristupa će biti pozvan ok-app.group1.web.front. Svaki servis ima manifest, koji specificira sve potrebne informacije za postavljanje na određene mašine: koliko resursa ovaj zadatak troši, koja mu je konfiguracija potrebna, koliko replika treba da ima, svojstva za rukovanje kvarovima ove usluge. A nakon što se servis postavi direktno na mašine, pojavljuju se njegove instance. Oni su također imenovani nedvosmisleno - kao broj instance i naziv usluge: 1.ok-web.group1.web.front, 2.ok-web.group1.web.front, …

Ovo je vrlo zgodno: gledajući samo naziv tekućeg kontejnera, odmah možemo saznati mnogo.

Pogledajmo sada pobliže šta ove instance zapravo izvode: zadatke.

Klase izolacije zadataka

Svi zadaci u OK (i, vjerovatno, svugdje) mogu se podijeliti u grupe:

  • Zadaci kratkog kašnjenja - prod. Za ovakve zadatke i usluge je veoma važno kašnjenje odgovora (latencija), koliko brzo će svaki od zahteva biti obrađen od strane sistema. Primjeri zadataka: web frontovi, keš memorije, aplikacijski serveri, OLTP skladište, itd.
  • Računski problemi - serija. Ovdje brzina obrade svakog konkretnog zahtjeva nije bitna. Za njih je važno koliko će proračuna obaviti ovaj zadatak u određenom (dugom) vremenskom periodu (propusnost). To će biti bilo koji zadaci MapReduce-a, Hadoop-a, mašinskog učenja, statistike.
  • Pozadinski zadaci - neaktivni. Za takve zadatke ni kašnjenje ni propusnost nisu od velike važnosti. To uključuje razne testove, migracije, ponovna izračunavanja i konverziju podataka iz jednog formata u drugi. S jedne strane, oni su slični proračunatima, s druge strane, nije nam bitno koliko brzo se završavaju.

Pogledajmo kako takvi zadaci troše resurse, na primjer, centralni procesor.

Zadaci sa kratkim kašnjenjem. Takav zadatak će imati obrazac potrošnje CPU-a sličan ovom:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Prima se zahtjev od korisnika na obradu, zadatak počinje koristiti sve raspoložive CPU jezgre, obrađuje ga, vraća odgovor, čeka sljedeći zahtjev i zaustavlja se. Stigao je sljedeći zahtjev - opet smo odabrali sve što je bilo, izračunali i čekamo sljedeći.

Da bismo garantovali minimalno kašnjenje za takav zadatak, moramo uzeti maksimalne resurse koje troši i rezervisati potreban broj jezgara na minionu (mašini koja će izvršiti zadatak). Tada će formula rezervacije za naš problem biti sljedeća:

alloc: cpu = 4 (max)

a ako imamo minion mašinu sa 16 jezgri, onda se na nju mogu postaviti tačno četiri takva zadatka. Posebno napominjemo da je prosječna potrošnja procesora ovakvih zadataka često vrlo niska – što je očigledno, budući da značajan dio vremena zadatak čeka na zahtjev i ne radi ništa.

Računski zadaci. Njihov će uzorak biti malo drugačiji:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Prosječna potrošnja CPU resursa za takve zadatke je prilično visoka. Često želimo da se računski zadatak završi u određenom vremenskom roku, tako da moramo rezervisati minimalni broj procesora koji mu je potreban kako bi se cijeli proračun završio u prihvatljivom vremenu. Njegova formula za rezervaciju će izgledati ovako:

alloc: cpu = [1,*)

“Molim vas, stavite ga na miniona gdje ima barem jedno slobodno jezgro, a onda će onoliko koliko ih ima, proždreti sve.”

Ovdje je efikasnost korištenja već mnogo bolja nego na zadacima s kratkim kašnjenjem. Ali dobitak će biti mnogo veći ako kombinirate obje vrste zadataka na jednoj minion mašini i distribuirate njene resurse u pokretu. Kada zadatak s kratkim kašnjenjem zahtijeva procesor, on ga odmah prima, a kada resursi više nisu potrebni, oni se prenose u računski zadatak, tj. otprilike ovako:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Ali kako to učiniti?

Prvo, pogledajmo prod i njegovu dodjelu: cpu = 4. Moramo rezervisati četiri jezgre. U Docker pokretanju to se može uraditi na dva načina:

  • Koristeći opciju --cpuset=1-4, tj. dodijeliti četiri specifična jezgra na mašini zadatku.
  • Upotreba --cpuquota=400_000 --cpuperiod=100_000, dodijelite kvotu za procesorsko vrijeme, tj. naznačite da svakih 100 ms realnog vremena zadatak ne troši više od 400 ms procesorskog vremena. Dobivaju se ista četiri jezgra.

Ali koja je od ovih metoda prikladna?

cpuset izgleda prilično atraktivno. Zadatak ima četiri namjenska jezgra, što znači da će kešovi procesora raditi što je moguće efikasnije. Ovo ima i lošu stranu: morali bismo preuzeti zadatak distribucije proračuna po neopterećenim jezgrama mašine umjesto OS-a, a to je prilično netrivijalan zadatak, pogotovo ako pokušamo postaviti batch zadatke na takav mašina. Testovi su pokazali da je opcija sa kvotom ovdje bolja: na taj način operativni sistem ima više slobode u odabiru jezgre za obavljanje zadatka u trenutnom trenutku, a vrijeme procesora se efikasnije raspoređuje.

Hajde da shvatimo kako napraviti rezervacije u Dockeru na osnovu minimalnog broja jezgara. Kvota za paketne zadatke više nije primjenjiva, jer nema potrebe za ograničavanjem maksimuma, dovoljno je samo garantirati minimum. I ovdje se opcija dobro uklapa docker run --cpushares.

Složili smo se da ako serija zahtijeva garanciju za barem jedno jezgro, onda naznačimo --cpushares=1024, a ako postoje najmanje dvije jezgre, onda označavamo --cpushares=2048. Dijelovi procesora ni na koji način ne ometaju raspodjelu procesorskog vremena sve dok ga ima dovoljno. Dakle, ako prod trenutno ne koristi sve svoje četiri jezgre, ništa ne ograničava batch zadatke i oni mogu koristiti dodatno procesorsko vrijeme. Ali u situaciji kada postoji manjak procesora, ako je prod potrošio sva četiri svoja jezgra i dostigao svoju kvotu, preostalo procesorsko vrijeme će se podijeliti proporcionalno cpushares-u, tj. u situaciji od tri slobodna jezgra, jedno će biti dato zadatku sa 1024 cpushares-a, a preostala dva će biti data zadatku sa 2048 cpushares-a.

Ali korištenje kvota i dionica nije dovoljno. Moramo se pobrinuti da zadatak s kratkim kašnjenjem dobije prioritet u odnosu na paketni zadatak kada dodjeljuje vrijeme procesora. Bez takvog određivanja prioriteta, paketni zadatak će zauzeti svo vrijeme procesora u trenutku kada je potreban proizvodu. Ne postoje opcije prioritizacije kontejnera u Docker pokretanju, ali politike rasporeda Linux CPU-a dobro dolaze. O njima možete pročitati detaljno ovdje, a u okviru ovog članka ćemo ih ukratko proći:

  • SCHED_OTHER
    Podrazumevano, svi normalni korisnički procesi na Linux mašini primaju.
  • SCHED_BATCH
    Dizajniran za procese koji zahtijevaju velike resurse. Prilikom postavljanja zadatka na procesor, uvodi se takozvana kazna aktivacije: manja je vjerovatnoća da će takav zadatak dobiti resurse procesora ako ga trenutno koristi zadatak sa SCHED_OTHER
  • SCHED_IDLE
    Pozadinski proces sa veoma niskim prioritetom, čak nižim od lepog -19. Koristimo našu biblioteku otvorenog koda one-nio, kako biste postavili potrebnu politiku pri pokretanju kontejnera pozivom

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

Ali čak i ako ne programirate u Javi, ista stvar se može uraditi pomoću naredbe chrt:

chrt -i 0 $pid

Hajde da sumiramo sve naše nivoe izolacije u jednu tabelu radi jasnoće:

Klasa izolacije
Alloc primjer
Opcije pokretanja Dockera
sched_setscheduler chrt*

štap
procesor = 4
--cpuquota=400000 --cpuperiod=100000
SCHED_OTHER

Serija
Cpu = [1, *)
--cpushares=1024
SCHED_BATCH

Idle
Cpu= [2, *)
--cpushares=2048
SCHED_IDLE

*Ako radite chrt iz kontejnera, možda će vam trebati mogućnost sys_nice, jer Docker po defaultu uklanja ovu mogućnost prilikom pokretanja kontejnera.

Ali zadaci ne troše samo procesor, već i promet, što utječe na kašnjenje mrežnog zadatka čak i više od pogrešne alokacije resursa procesora. Stoga, prirodno želimo da dobijemo potpuno istu sliku o saobraćaju. To jest, kada prod zadatak pošalje neke pakete u mrežu, ograničavamo maksimalnu brzinu (formula alloc: lan=[*,500mbps) ), s kojim prod to može učiniti. A za seriju garantiramo samo minimalnu propusnost, ali ne ograničavamo maksimalnu (formula alloc: lan=[10Mbps,*) ) U ovom slučaju, prod saobraćaj bi trebao dobiti prioritet u odnosu na paketne zadatke.
Ovdje Docker nema primitive koje možemo koristiti. Ali dolazi nam u pomoć Linux kontrola saobraćaja. Uz pomoć discipline uspjeli smo postići željeni rezultat Hijerarhijska krivulja poštenih usluga. Uz njegovu pomoć razlikujemo dvije klase prometa: prod visokog prioriteta i batch/idle niskog prioriteta. Kao rezultat toga, konfiguracija za odlazni promet je ovakva:

Jedan oblak - OS na nivou data centra u Odnoklassniki

ovdje je 1:0 “korijenski qdisc” hsfc discipline; 1:1 - hsfc podređena klasa sa ukupnim ograničenjem propusnog opsega od 8 Gbit/s, ispod koje se stavljaju podređene klase svih kontejnera; 1:2 - hsfc podređena klasa je zajednička za sve batch i neaktivne zadatke sa "dinamičkim" ograničenjem, o čemu se govori u nastavku. Preostale hsfc podređene klase su namenske klase za trenutno pokrenute prod kontejnere sa ograničenjima koja odgovaraju njihovim manifestima - 450 i 400 Mbit/s. Svakoj hsfc klasi je dodijeljen qdisc queue fq ili fq_codel, ovisno o verziji jezgre Linuxa, kako bi se izbjegao gubitak paketa za vrijeme izbijanja prometa.

Tipično, tc discipline služe za davanje prioriteta samo odlaznom saobraćaju. Ali želimo dati prioritet i dolaznom prometu – na kraju krajeva, neki batch zadatak može lako odabrati cijeli dolazni kanal, primajući, na primjer, veliku seriju ulaznih podataka za map&reduce. Za to koristimo modul ifb, koji kreira ifbX virtualno sučelje za svako mrežno sučelje i preusmjerava dolazni promet sa sučelja na odlazni promet na ifbX-u. Nadalje, za ifbX, sve iste discipline rade na kontroli odlaznog prometa, za koji će hsfc konfiguracija biti vrlo slična:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Tokom eksperimenata smo otkrili da hsfc pokazuje najbolje rezultate kada je 1:2 klasa neprioritetnog batch/idle saobraćaja ograničena na minion mašinama na ne više od određene slobodne trake. U suprotnom, neprioritetni saobraćaj ima previše uticaja na kašnjenje prod zadataka. miniond određuje trenutnu količinu slobodne propusnosti svake sekunde, mjereći prosječnu potrošnju saobraćaja za sve prod-zadatke datog miniona Jedan oblak - OS na nivou data centra u Odnoklassniki i oduzimanjem od propusnog opsega mrežnog interfejsa Jedan oblak - OS na nivou data centra u Odnoklassniki sa malom marginom, tj.

Jedan oblak - OS na nivou data centra u Odnoklassniki

Opsezi se definišu nezavisno za dolazni i odlazni saobraćaj. A prema novim vrijednostima, miniond rekonfigurira ograničenje klase neprioriteta 1:2.

Tako smo implementirali sve tri klase izolacije: prod, batch i idle. Ove klase u velikoj meri utiču na karakteristike performansi zadataka. Stoga smo odlučili da ovaj atribut smjestimo na vrh hijerarhije, tako da kada se pogleda naziv hijerarhijskog reda odmah bude jasno o čemu imamo posla:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Svi naši prijatelji veb и muzika frontovi se zatim postavljaju u hijerarhiju pod prod. Na primjer, pod batch, postavimo uslugu muzički katalog, koji povremeno sastavlja katalog numera iz skupa mp3 fajlova postavljenih na Odnoklassniki. Primjer usluge u stanju mirovanja bi bio muzički transformator, koji normalizuje nivo jačine muzike.

Sa ponovno uklonjenim dodatnim redovima, nazive naših usluga možemo pisati ravnije dodavanjem klase izolacije zadataka na kraj punog naziva usluge: web.front.prod, catalog.music.batch, transformer.music.idle.

A sada, gledajući naziv usluge, razumijemo ne samo koju funkciju obavlja, već i njenu klasu izolacije, što znači njenu kritičnost, itd.

Sve je super, ali postoji jedna gorka istina. Nemoguće je potpuno izolovati zadatke koji se izvršavaju na jednoj mašini.

Ono što smo uspjeli postići: ako se serija intenzivno troši samo CPU resursi, zatim ugrađeni Linux CPU planer vrlo dobro radi svoj posao i praktički nema utjecaja na prod zadatak. Ali ako ovaj skupni zadatak počne aktivno raditi s memorijom, tada se već pojavljuje međusobni utjecaj. To se događa zato što se prod zadatak "ispere" iz memorijskih keša procesora - kao rezultat toga, promašaji keša se povećavaju, a procesor sporije obrađuje prod zadatak. Takav skupni zadatak može povećati latenciju našeg tipičnog prod kontejnera za 10%.

Izolacija saobraćaja je još teža zbog činjenice da moderne mrežne kartice imaju interni red paketa. Ako paket iz paketnog zadatka stigne tamo prvi, onda će on biti prvi koji će se prenijeti preko kabla, i tu se ništa ne može učiniti.

Osim toga, do sada smo uspjeli riješiti samo problem prioritizacije TCP prometa: hsfc pristup ne radi za UDP. Čak iu slučaju TCP saobraćaja, ako paketni zadatak generiše mnogo saobraćaja, to takođe daje oko 10% povećanje kašnjenja prod zadatka.

tolerancije grešaka

Jedan od ciljeva razvoja jednog oblaka bio je poboljšanje tolerancije grešaka Odnoklassniki. Stoga bih u nastavku želio detaljnije razmotriti moguće scenarije kvarova i nesreća. Počnimo s jednostavnim scenarijem - kvar kontejnera.

Sam kontejner može pokvariti na nekoliko načina. Ovo može biti neka vrsta eksperimenta, greške ili greške u manifestu, zbog čega prod zadatak počinje da troši više resursa nego što je naznačeno u manifestu. Imali smo slučaj: programer je implementirao jedan složen algoritam, preradio ga mnogo puta, previše razmišljao i postao toliko zbunjen da se na kraju problem zapetljao na vrlo netrivijalan način. A pošto prod zadatak ima veći prioritet od svih ostalih na istim minionima, počeo je da troši sve raspoložive resurse procesora. U ovoj situaciji, izolacija, odnosno kvota CPU vremena, spasila je dan. Ako je zadatku dodijeljena kvota, zadatak neće trošiti više. Stoga, batch i drugi prod zadaci koji su radili na istoj mašini nisu ništa primijetili.

Drugi mogući problem je pad kontejnera. I ovdje nas spašavaju politike ponovnog pokretanja, svi ih znaju, sam Docker radi odličan posao. Gotovo svi zadaci proizvoda imaju politiku uvijek ponovnog pokretanja. Ponekad koristimo on_failure za paketne zadatke ili za otklanjanje grešaka u prod kontejnerima.

Šta možete učiniti ako cijeli minion nije dostupan?

Očigledno, pokrenite kontejner na drugoj mašini. Zanimljivi dio ovdje je šta se dešava sa IP adresama dodijeljenim kontejneru.

Kontejnerima možemo dodijeliti iste IP adrese kao i minion mašinama na kojima ovi kontejneri rade. Zatim, kada se kontejner pokrene na drugoj mašini, njegova IP adresa se menja i svi klijenti moraju da shvate da se kontejner preselio i sada moraju da odu na drugu adresu, što zahteva posebnu uslugu otkrivanja usluge.

Service Discovery je zgodan. Na tržištu postoji mnogo rješenja različitog stepena tolerancije grešaka za organizaciju servisnog registra. Često takva rješenja implementiraju logiku balansiranja opterećenja, pohranjuju dodatnu konfiguraciju u obliku KV skladišta itd.
Međutim, željeli bismo izbjeći potrebu za implementacijom posebnog registra, jer bi to značilo uvođenje kritičnog sistema koji koriste svi servisi u proizvodnji. To znači da je ovo potencijalna tačka neuspjeha i morate odabrati ili razviti rješenje otporno na greške, koje je očigledno vrlo teško, dugotrajno i skupo.

I još jedan veliki nedostatak: da bi naša stara infrastruktura radila sa novom, morali bismo da prepišemo apsolutno sve zadatke da koristimo neku vrstu Service Discovery sistema. Ima PUNO posla, a na nekim mjestima je gotovo nemoguće kada su u pitanju uređaji niskog nivoa koji rade na nivou kernela OS-a ili direktno sa hardverom. Implementacija ove funkcionalnosti korištenjem utvrđenih obrazaca rješenja, kao npr bočna prikolica bi na nekim mjestima značilo dodatno opterećenje, na drugim - komplikaciju rada i dodatne scenarije kvara. Nismo željeli komplikovati stvari, pa smo odlučili da korištenje usluge Discovery bude opcionalno.

U jednom oblaku, IP prati kontejner, odnosno svaka instanca zadatka ima svoju IP adresu. Ova adresa je “statična”: dodjeljuje se svakoj instanci kada se usluga prvi put pošalje u oblak. Ako je usluga imala različit broj instanci tokom svog života, tada će joj na kraju biti dodijeljen onoliko IP adresa koliko je bilo maksimalno instanci.

Nakon toga, ove adrese se ne mijenjaju: dodjeljuju se jednom i nastavljaju postojati tokom cijelog vijeka trajanja usluge u proizvodnji. IP adrese prate kontejnere širom mreže. Ako se kontejner prenese na drugog miniona, adresa će ga pratiti.

Prema tome, mapiranje naziva usluge u njenu listu IP adresa se vrlo rijetko mijenja. Ako ponovo pogledate nazive servisnih instanci koje smo spomenuli na početku članka (1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, …), primijetit ćemo da liče na FQDN-ove koji se koriste u DNS-u. Tako je, da bismo mapirali imena instanci servisa na njihove IP adrese, koristimo DNS protokol. Štaviše, ovaj DNS vraća sve rezervisane IP adrese svih kontejnera - i pokrenutih i zaustavljenih (recimo da se koriste tri replike, a mi imamo pet adresa rezervisanih tamo - svih pet će biti vraćeno). Klijenti će, nakon što dobiju ovu informaciju, pokušati uspostaviti vezu sa svih pet replika - i tako odrediti one koje rade. Ova opcija za određivanje dostupnosti je mnogo pouzdanija, ne uključuje ni DNS ni otkrivanje usluga, što znači da nema teških problema za rješavanje u osiguravanju relevantnosti informacija i tolerancije grešaka ovih sistema. Štoviše, u kritičnim servisima od kojih ovisi rad cijelog portala, ne možemo uopće koristiti DNS, već jednostavno unositi IP adrese u konfiguraciju.

Implementacija takvog IP prijenosa iza kontejnera može biti netrivijalna - a mi ćemo pogledati kako to funkcionira na sljedećem primjeru:

Jedan oblak - OS na nivou data centra u Odnoklassniki

Recimo da gospodar jednog oblaka daje komandu minionu M1 za pokretanje 1.ok-web.group1.web.front.prod sa adresom 1.1.1.1. Radi na minionu PTICA, koji ovu adresu oglašava posebnim serverima reflektor rute. Potonji imaju BGP sesiju sa mrežnim hardverom, u koju je prevedena ruta adrese 1.1.1.1 na M1. M1 usmjerava pakete unutar kontejnera koristeći Linux. Postoje tri servera reflektora ruta, jer je ovo vrlo kritičan dio infrastrukture jednog oblaka - bez njih mreža u jednom oblaku neće raditi. Postavljamo ih u različite police, ako je moguće smještene u različitim prostorijama data centra, kako bismo smanjili vjerovatnoću da sva tri kvara u isto vrijeme.

Pretpostavimo sada da je veza između mastera jednog oblaka i M1 miniona izgubljena. Master jednog oblaka će sada djelovati pod pretpostavkom da je M1 potpuno otkazao. Odnosno, dat će komandu M2 minionu za lansiranje web.group1.web.front.prod sa istom adresom 1.1.1.1. Sada imamo dvije konfliktne rute na mreži za 1.1.1.1: na M1 i na M2. Da bismo riješili takve konflikte, koristimo Multi Exit Discriminator, koji je naveden u BGP najavi. Ovo je broj koji pokazuje težinu oglašene rute. Među konfliktnim rutama, bit će odabrana ruta s nižom MED vrijednošću. Master jednog oblaka podržava MED kao sastavni dio IP adresa kontejnera. Po prvi put, adresa je upisana sa dovoljno velikim MED = 1 U situaciji takvog hitnog prijenosa kontejnera, master smanjuje MED, a M000 će već dobiti naredbu za oglašavanje adrese 000 sa MED =. 2 Instanca koja radi na M1.1.1.1 ostaće u ovom slučaju, nema veze, a njegova dalja sudbina nas malo zanima dok se veza sa masterom ne obnovi, kada će on biti zaustavljen kao stari potez.

Nesreće

Svi sistemi za upravljanje centrom podataka uvijek prihvatljivo rješavaju manje kvarove. Prelijevanje kontejnera je norma gotovo svugdje.

Pogledajmo kako postupamo u hitnim slučajevima, kao što je nestanak struje u jednoj ili više prostorija data centra.

Šta nesreća znači za sistem upravljanja centrom podataka? Prije svega, ovo je masovni jednokratni kvar mnogih mašina, a kontrolni sistem treba da migrira mnogo kontejnera u isto vrijeme. Ali ako je katastrofa vrlo velikih razmjera, onda se može dogoditi da se svi zadaci ne mogu preraspodijeliti na druge minione, jer kapacitet resursa podatkovnog centra pada ispod 100% opterećenja.

Često su nezgode praćene kvarom kontrolnog sloja. To se može dogoditi zbog kvara njegove opreme, ali češće zbog činjenice da se nezgode ne testiraju, a sam kontrolni sloj pada zbog povećanog opterećenja.

Šta možete učiniti povodom svega ovoga?

Masovne migracije znače da postoji veliki broj aktivnosti, migracija i implementacija koje se dešavaju u infrastrukturi. Svaka od migracija može potrajati neko vrijeme potrebno za isporuku i raspakivanje slika kontejnera minionima, pokretanje i inicijalizaciju kontejnera itd. Stoga je poželjno da se važniji zadaci pokreću prije manje važnih.

Pogledajmo ponovo hijerarhiju usluga s kojom smo upoznati i pokušajmo odlučiti koje zadatke želimo prvo pokrenuti.

Jedan oblak - OS na nivou data centra u Odnoklassniki

Naravno, radi se o procesima koji su direktno uključeni u obradu zahtjeva korisnika, odnosno prod. Ovo ukazujemo sa prioritet plasmana — broj koji se može dodijeliti redu. Ako red ima veći prioritet, njegove usluge se stavljaju na prvo mjesto.

Na prod dodjeljujemo više prioritete, 0; na seriju - malo niže, 100; u stanju mirovanja - čak niže, 200. Prioriteti se primjenjuju hijerarhijski. Svi zadaci niže u hijerarhiji će imati odgovarajući prioritet. Ako želimo da se kešovi unutar prod-a pokreću prije frontenda, tada dodjeljujemo prioritete kešu = 0 i prednjim podredovima = 1. Ako, na primjer, želimo da se glavni portal pokrene prvo s fronta, a samo muzički front onda, onda možemo dodijeliti niži prioritet potonjem - 10.

Sljedeći problem je nedostatak resursa. Dakle, otkazala je velika količina opreme, čitave hale data centra, a mi smo ponovo pokrenuli toliko servisa da sada nema dovoljno resursa za sve. Morate odlučiti koje zadatke žrtvovati da biste održali rad glavnih kritičnih usluga.

Jedan oblak - OS na nivou data centra u Odnoklassniki

Za razliku od prioriteta postavljanja, ne možemo neselektivno žrtvovati sve skupne zadatke, neki od njih su važni za rad portala. Stoga smo posebno izdvojili prioritet prioriteta zadataka. Kada se postavi, zadatak višeg prioriteta može preduhitriti, tj. zaustaviti zadatak nižeg prioriteta ako više nema slobodnih miniona. U ovom slučaju, zadatak sa niskim prioritetom će vjerovatno ostati nepostavljen, tj. za njega više neće biti odgovarajućeg miniona sa dovoljno slobodnih resursa.

U našoj hijerarhiji, vrlo je jednostavno specificirati prioritet preuzimanja tako da prod i batch zadaci preuzmu ili zaustavljaju neaktivne zadatke, ali ne jedni druge, specificirajući prioritet za mirovanje jednak 200. Baš kao i u slučaju prioriteta postavljanja, mi može koristiti našu hijerarhiju da opiše složenija pravila. Na primjer, naznačimo da žrtvujemo muzičku funkciju ako nemamo dovoljno resursa za glavni web portal, postavljajući niži prioritet za odgovarajuće čvorove: 10.

Cijele DC nesreće

Zašto bi cijeli data centar mogao otkazati? Element. Bio je dobar post uragan je uticao na rad data centra. Elementi se mogu smatrati beskućnicima koji su svojevremeno spalili optiku u kolektoru, a data centar je potpuno izgubio kontakt sa drugim lokacijama. Uzrok kvara može biti i ljudski faktor: operater će izdati takvu komandu da će cijeli podatkovni centar pasti. Ovo se može dogoditi zbog velike greške. Općenito, kolaps centara podataka nije neuobičajen. To nam se dešava jednom u nekoliko mjeseci.

I ovo je ono što radimo da spriječimo bilo koga da tvituje #živ.

Prva strategija je izolacija. Svaka instanca u jednom oblaku je izolovana i može upravljati mašinama u samo jednom data centru. Odnosno, gubitak oblaka zbog grešaka ili pogrešnih komandi operatera je gubitak samo jednog data centra. Spremni smo za to: postoji politika redundantnosti u kojoj se replike aplikacije i podataka nalaze u svim data centrima. Koristimo baze podataka otporne na greške i povremeno testiramo greške.
Pošto danas imamo četiri data centra, to znači četiri odvojena, potpuno izolirana instance jednog oblaka.

Ovaj pristup ne samo da štiti od fizičkog kvara, već može zaštititi i od greške operatera.

Šta se još može učiniti sa ljudskim faktorom? Kada operater da oblaku neku čudnu ili potencijalno opasnu komandu, od njega se iznenada može tražiti da riješi mali problem da vidi koliko je dobro razmišljao. Na primjer, ako je ovo neka vrsta masovnog zaustavljanja mnogih replika ili samo čudna naredba - smanjenje broja replika ili promjena naziva slike, a ne samo broja verzije u novom manifestu.

Jedan oblak - OS na nivou data centra u Odnoklassniki

Ishodi

Prepoznatljive karakteristike jednog oblaka:

  • Hijerarhijska i vizuelna šema imenovanja za usluge i kontejnere, koji vam omogućava da vrlo brzo saznate o čemu se radi, na šta se odnosi i kako radi i ko je za njega odgovoran.
  • Primjenjujemo naše tehnika kombinovanja proizvoda i serijezadaci za sluge za poboljšanje efikasnosti dijeljenja strojeva. Umjesto cpuset-a koristimo CPU kvote, dijeljenja, CPU planer policy i Linux QoS.
  • Nije bilo moguće potpuno izolovati kontejnere koji rade na istoj mašini, ali njihov međusobni uticaj ostaje unutar 20%.
  • Organiziranje usluga u hijerarhiju pomaže pri korištenju automatskog oporavka od katastrofe prioriteti plasmana i prednosti.

FAQ

Zašto nismo uzeli gotovo rješenje?

  • Različite klase izolacije zadataka zahtijevaju drugačiju logiku kada se postavljaju na sluge. Ako se prod zadaci mogu postaviti jednostavnim rezervisanjem resursa, tada se moraju postaviti paketni i neaktivni zadaci, prateći stvarnu upotrebu resursa na minion mašinama.
  • Potreba da se uzmu u obzir resursi koji se troše zadacima, kao što su:
    • propusni opseg mreže;
    • vrste i "vretena" diskova.
  • Potreba da se naznače prioriteti usluga tokom hitnog reagovanja, prava i kvote komandi za resurse, što se rešava korišćenjem hijerarhijskih redova u jednom oblaku.
  • Potreba za ljudskim imenovanjem kontejnera kako bi se smanjilo vrijeme odgovora na nesreće i incidente
  • Nemogućnost jednokratne široke implementacije Service Discovery-a; potreba za dugotrajnim koegzistiranjem sa zadacima koji se nalaze na hardverskim hostovima – nešto što se rješava “statičnim” IP adresama koje prate kontejnere, i, kao posljedica toga, potreba za jedinstvenom integracijom sa velikom mrežnom infrastrukturom.

Sve ove funkcije bi zahtijevale značajne modifikacije postojećih rješenja kako bi nam odgovarale, a procijenivši obim posla, shvatili smo da možemo razviti vlastito rješenje uz približno iste troškove rada. Ali vaše rješenje će biti mnogo lakše za rukovanje i razvoj – ono ne sadrži nepotrebne apstrakcije koje podržavaju funkcionalnost koja nam nije potrebna.

Onima koji su pročitali zadnje redove, hvala na strpljenju i pažnji!

izvor: www.habr.com

Dodajte komentar