Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Ho, homoj! Mi nomiĝas Oleg Anastasyev, mi laboras ĉe Odnoklassniki en la Platform-teamo. Kaj krom mi, en Odnoklassniki funkcias multe da aparataro. Ni havas kvar datumcentrojn kun ĉirkaŭ 500 rakoj kun pli ol 8 mil serviloj. Je certa punkto, ni rimarkis, ke la enkonduko de nova mastruma sistemo permesus al ni pli efike ŝargi ekipaĵojn, faciligi aliradministradon, aŭtomatigi la (re)distribuon de komputikaj rimedoj, akceli la lanĉon de novaj servoj kaj akceli respondojn. al grandskalaj akcidentoj.

Kio venis el ĝi?

Krom mi kaj amaso da aparataro, estas ankaŭ homoj, kiuj laboras kun ĉi tiu aparataro: inĝenieroj, kiuj situas rekte en datumcentroj; retumantoj, kiuj starigas retan programaron; administrantoj, aŭ SREoj, kiuj disponigas infrastrukturan rezistecon; kaj evoluigaj teamoj, ĉiu el ili respondecas pri parto de la funkcioj de la portalo. La programaro, kiun ili kreas, funkcias kiel ĉi tio:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Uzantpetoj estas ricevitaj ambaŭ sur la frontoj de la ĉefa portalo www.ok.ru, kaj sur aliaj, ekzemple sur la muzikaj API-frontoj. Por prilabori la komercan logikon, ili nomas la aplikaĵoservilon, kiu, kiam oni prilaboras la peton, nomas la necesajn specialigitajn mikroservojn - unu-grafeon (grafeo de sociaj ligoj), uzantkaŝmemoro (kaŝmemoro de uzantprofiloj), ktp.

Ĉiu el ĉi tiuj servoj estas deplojita sur multaj maŝinoj, kaj ĉiu el ili havas respondecajn programistojn respondecajn pri la funkciado de la moduloj, ilia funkciado kaj teknologia disvolviĝo. Ĉiuj ĉi tiuj servoj funkcias per aparataj serviloj, kaj ĝis antaŭ nelonge ni lanĉis ĝuste unu taskon per servilo, t.e. ĝi estis specialigita por specifa tasko.

Kial estas tio? Ĉi tiu aliro havis plurajn avantaĝojn:

  • Malpezigita amasa administrado. Ni diru, ke tasko postulas kelkajn bibliotekojn, kelkajn agordojn. Kaj tiam la servilo estas asignita al ekzakte unu specifa grupo, la cfengine-politiko por ĉi tiu grupo estas priskribita (aŭ ĝi jam estis priskribita), kaj ĉi tiu agordo estas centre kaj aŭtomate eligita al ĉiuj serviloj en ĉi tiu grupo.
  • Simpligita diagnozoj. Ni diru, ke vi rigardas la pliigitan ŝarĝon sur la centra procesoro kaj rimarkas, ke ĉi tiu ŝarĝo povus esti generita nur de la tasko, kiu funkcias sur ĉi tiu aparataro. La serĉado de iu kulpulo finiĝas tre rapide.
  • Simpligita monitorado. Se io misas kun la servilo, la monitoro raportas ĝin, kaj vi scias ĝuste kiu kulpas.

Servo konsistanta el pluraj kopioj estas asignita plurajn servilojn - unu por ĉiu. Tiam la komputika rimedo por la servo estas asignita tre simple: la nombro da serviloj kiujn la servo havas, la maksimuma kvanto de rimedoj kiujn ĝi povas konsumi. "Facila" ĉi tie ne signifas, ke ĝi estas facile uzebla, sed en la senco, ke resursa asignado estas farita permane.

Ĉi tiu aliro ankaŭ permesis al ni fari specialigitaj feraj agordoj por tasko funkcianta sur ĉi tiu servilo. Se la tasko stokas grandajn kvantojn da datumoj, tiam ni uzas servilon 4U kun ĉasio kun 38 diskoj. Se la tasko estas pure komputa, tiam ni povas aĉeti pli malmultekostan 1U-servilon. Ĉi tio estas komputile efika. Interalie, ĉi tiu aliro permesas al ni uzi kvaroble malpli da maŝinoj kun ŝarĝo komparebla al unu amika socia reto.

Tia efikeco en la uzo de komputikaj rimedoj ankaŭ devus certigi ekonomian efikecon, se ni eliras de la premiso, ke la plej multekosta afero estas serviloj. Dum longa tempo, aparataro estis la plej multekosta, kaj ni multe klopodis redukti la prezon de aparataro, elpensante algoritmojn pri mistoleremo por redukti aparatajn fidindecpostulojn. Kaj hodiaŭ ni atingis la stadion, ĉe kiu la prezo de la servilo ĉesis esti decida. Se vi ne konsideras la plej novajn ekzotikojn, tiam la specifa agordo de la serviloj en la rako ne gravas. Nun ni havas alian problemon - la prezon de la spaco okupata de la servilo en la datumcentro, tio estas, la spaco en la rako.

Rimarkinte, ke tio estas la kazo, ni decidis kalkuli kiom efike ni uzas la rakojn.
Ni prenis la prezon de la plej potenca servilo el la ekonomie pravigeblaj, kalkulis kiom da tiaj serviloj ni povus meti en rakojn, kiom da taskoj ni rulus sur ili surbaze de la malnova modelo "unu servilo = unu tasko" kaj kiom tiaj. taskoj povus uzi la ekipaĵon. Ili kalkulis kaj verŝis larmojn. Montriĝis, ke nia efikeco en uzado de rakoj estas ĉirkaŭ 11%. La konkludo estas evidenta: ni devas pliigi la efikecon de uzado de datumcentroj. Ŝajnus, ke la solvo estas evidenta: vi devas ruli plurajn taskojn en unu servilo samtempe. Sed ĉi tie komenciĝas la malfacilaĵoj.

Amasa agordo fariĝas draste pli komplika - nun estas neeble asigni iun grupon al servilo. Post ĉio, nun pluraj taskoj de malsamaj komandoj povas esti lanĉitaj sur unu servilo. Aldone, la agordo povas esti konflikta por malsamaj aplikoj. Diagnozo ankaŭ fariĝas pli komplika: se vi vidas pliigitan CPU aŭ disko-konsumon sur servilo, vi ne scias, kiu tasko kaŭzas problemojn.

Sed la ĉefa afero estas, ke ne ekzistas izolado inter taskoj kurantaj sur la sama maŝino. Jen, ekzemple, grafikaĵo de la meza respondtempo de servila tasko antaŭ kaj post kiam alia komputila aplikaĵo estis lanĉita sur la sama servilo, neniel rilata al la unua - la respondtempo de la ĉefa tasko signife pliiĝis.

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Evidente, vi devas ruli taskojn aŭ en ujoj aŭ en virtualaj maŝinoj. Ĉar preskaŭ ĉiuj niaj taskoj funkcias sub unu OS (Linukso) aŭ estas adaptitaj por ĝi, ni ne bezonas subteni multajn malsamajn operaciumojn. Sekve, virtualigo ne estas necesa; pro la kroma ŝarĝo, ĝi estos malpli efika ol kontenerigo.

Kiel efektivigo de ujoj por ruli taskojn rekte sur serviloj, Docker estas bona kandidato: dosiersistemaj bildoj bone solvas problemojn kun konfliktantaj agordoj. La fakto ke bildoj povas esti kunmetitaj de pluraj tavoloj permesas al ni signife redukti la kvanton de datumoj necesaj por deploji ilin sur la infrastrukturo, apartigante komunajn partojn en apartajn bazajn tavolojn. Tiam la bazaj (kaj plej grandaj) tavoloj estos konservitaj sufiĉe rapide tra la tuta infrastrukturo, kaj por liveri multajn malsamajn specojn de aplikoj kaj versioj, nur malgrandaj tavoloj devos esti translokigitaj.

Krome, preta registro kaj bilda etikedado en Docker donas al ni pretajn primitivulojn por versio kaj liverado de kodo al produktado.

Docker, kiel iu ajn alia simila teknologio, provizas al ni iom da nivelo de izolado de ujo el la skatolo. Ekzemple, memorizolado - ĉiu ujo ricevas limon pri la uzo de maŝina memoro, preter kiu ĝi ne konsumos. Vi ankaŭ povas izoli ujojn laŭ CPU-uzado. Por ni tamen ne sufiĉis norma izolado. Sed pli pri tio ĉi sube.

Rekte ruli ujojn sur serviloj estas nur parto de la problemo. La alia parto rilatas al gastigado de ujoj sur serviloj. Vi devas kompreni, kiu ujo povas esti metita sur kiu servilo. Ĉi tio ne estas tiel facila tasko, ĉar ujoj devas esti metitaj sur servilojn kiel eble plej dense sen redukti sian rapidecon. Tia lokigo ankaŭ povas esti malfacila de faŭltoleremo vidpunkto. Ofte ni volas meti kopiojn de la sama servo en malsamaj rakoj aŭ eĉ en malsamaj ĉambroj de la datumcentro, tiel ke se rako aŭ ĉambro malsukcesas, ni ne tuj perdu ĉiujn servajn kopiojn.

Distribui ujojn permane ne estas eblo kiam vi havas 8 mil servilojn kaj 8-16 mil ujojn.

Krome, ni volis doni al programistoj pli da sendependeco en resursa asignado, por ke ili mem povu gastigi siajn servojn en produktado, sen la helpo de administranto. Samtempe, ni volis konservi kontrolon por ke iu negrava servo ne konsumu ĉiujn rimedojn de niaj datumcentroj.

Evidente, ni bezonas kontroltavolon, kiu farus tion aŭtomate.

Do ni venis al simpla kaj komprenebla bildo, kiun ĉiuj arkitektoj adoras: tri kvadratoj.

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

unu-nubaj majstroj estas malsukcesa areto respondeca por nuba orkestrado. La programisto sendas manifeston al la majstro, kiu enhavas ĉiujn informojn necesajn por gastigi la servon. Surbaze de ĝi, la majstro donas komandojn al elektitaj sbiroj (maŝinoj destinitaj por ruli ujojn). La sbiroj havas nian agenton, kiu ricevas la komandon, eldonas siajn komandojn al Docker, kaj Docker agordas la linuksan kernon por lanĉi la respondan ujon. Krom ekzekuti komandojn, la agento senĉese raportas al la majstro pri ŝanĝoj en la stato kaj de la maŝino kaj la ujoj kurantaj sur ĝi.

Asigno de Rimedoj

Nun ni rigardu la problemon de pli kompleksa asigno de rimedoj por multaj sbiroj.

Komputila rimedo en unu-nubo estas:

  • La kvanto de procesora potenco konsumita de specifa tasko.
  • La kvanto de memoro disponebla por la tasko.
  • Reta trafiko. Ĉiu el la sbiroj havas specifan retan interfacon kun limigita bendolarĝo, do estas neeble distribui taskojn sen konsideri la kvanton da datumoj, kiujn ili transdonas tra la reto.
  • Diskoj. Krome, evidente, al la spaco por ĉi tiuj taskoj, ni ankaŭ atribuas la tipon de disko: HDD aŭ SSD. Diskoj povas servi finian nombron da petoj je sekundo - IOPS. Tial, por taskoj kiuj generas pli da IOPS ol ununura disko povas trakti, ni ankaŭ asignas "spindelojn" - tio estas, disko-aparatoj kiuj devas esti ekskluzive rezervitaj por la tasko.

Tiam por iu servo, ekzemple por uzantkaŝmemoro, ni povas registri la konsumitajn rimedojn tiamaniere: 400 procesoraj kernoj, 2,5 TB da memoro, 50 Gbit/s trafiko ambaŭdirekte, 6 TB da HDD-spaco situanta sur 100 spindeloj. Aŭ en pli konata formo kiel ĉi tio:

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

Uzantkaŝmemoraj servaj rimedoj konsumas nur parton de ĉiuj disponeblaj resursoj en la produkta infrastrukturo. Tial mi volas certigi, ke subite, pro eraro de operacianto aŭ ne, la uzantkaŝmemoro ne konsumas pli da rimedoj ol estas asignitaj al ĝi. Tio estas, ni devas limigi rimedojn. Sed al kio ni povus ligi la kvoton?

Ni revenu al nia tre simpligita diagramo de la interago de komponantoj kaj redesegnu ĝin kun pli da detaloj - jene:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Kio kaptas vian atenton:

  • La interreta fasado kaj muziko uzas izolitajn aretojn de la sama aplikaĵoservilo.
  • Ni povas distingi la logikajn tavolojn al kiuj ĉi tiuj aretoj apartenas: frontoj, kaŝmemoroj, datumstokado kaj administrada tavolo.
  • La fasado estas heterogena; ĝi konsistas el malsamaj funkciaj subsistemoj.
  • Deponejoj ankaŭ povas esti disigitaj trans la subsistemo kies datumojn ili konservas.

Ni denove desegnu la bildon:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Bah! Jes, ni vidas hierarkion! Ĉi tio signifas, ke vi povas distribui rimedojn en pli grandaj partoj: asignu respondecan programiston al nodo de ĉi tiu hierarkio responda al la funkcia subsistemo (kiel "muziko" en la bildo), kaj aligu kvoton al la sama nivelo de la hierarkio. Ĉi tiu hierarkio ankaŭ permesas al ni organizi servojn pli flekseble por facileco de administrado. Ekzemple, ni dividas la tutan retejon, ĉar ĉi tio estas tre granda grupo de serviloj, en plurajn pli malgrandajn grupojn, montritajn en la bildo kiel grupo1, grupo2.

Forigante la ekstrajn liniojn, ni povas skribi ĉiun nodon de nia bildo en pli plata formo: grupo1.rete.fronto, api.music.front, user-cache.cache.

Jen kiel ni venas al la koncepto de "hierarkia vosto". Ĝi havas nomon kiel "group1.web.front". Kvoto por rimedoj kaj uzantrajtoj estas asignita al ĝi. Ni donos al la persono de DevOps la rajtojn sendi servon al la atendovico, kaj tia dungito povas lanĉi ion en la atendovico, kaj la persono de OpsDev havos administrajn rajtojn, kaj nun li povas administri la atendovicon, asigni homojn tie, donu al ĉi tiuj homoj rajtojn, ktp. Servoj kurantaj sur ĉi tiu vosto funkcios en la kvoto de la vosto. Se la komputikkvoto de la atendovico ne sufiĉas por ekzekuti ĉiujn servojn samtempe, tiam ili estos ekzekutitaj sinsekve, tiel formante la atendovicon mem.

Ni rigardu pli detale la servojn. Servo havas plene kvalifikitan nomon, kiu ĉiam inkluzivas la nomon de la atendovico. Tiam la antaŭa retservo havos la nomon ok-web.group1.web.front. Kaj la servo de aplika servilo, kiun ĝi aliras, estos nomita ok-app.group1.web.front. Ĉiu servo havas manifeston, kiu specifas ĉiujn necesajn informojn por lokigo sur specifaj maŝinoj: kiom da rimedoj ĉi tiu tasko konsumas, kia agordo necesas por ĝi, kiom da kopioj devus esti, ecoj por pritrakti malsukcesojn de ĉi tiu servo. Kaj post kiam la servo estas metita rekte sur la maŝinojn, aperas ĝiaj kazoj. Ili ankaŭ estas nomitaj malambigue - kiel la instanca numero kaj servonomo: 1.ok-web.group1.web.front, 2.ok-web.group1.web.front, …

Ĉi tio estas tre oportuna: rigardante nur la nomon de la kuranta ujo, ni povas tuj ekscii multon.

Nun ni rigardu pli detale kion ĉi tiuj okazoj efektive plenumas: taskoj.

Taskaj Izolitaj Klasoj

Ĉiuj taskoj en OK (kaj, verŝajne, ĉie) povas esti dividitaj en grupojn:

  • Mallongaj Latencaj Taskoj - prod. Por tiaj taskoj kaj servoj, la responda prokrasto (latenteco) estas tre grava, kiom rapide ĉiu el la petoj estos procesita de la sistemo. Ekzemploj de taskoj: TTT-frontoj, kaŝmemoroj, aplikaĵserviloj, OLTP-stokado, ktp.
  • Kalkulaj problemoj - aro. Ĉi tie, la prilabora rapideco de ĉiu specifa peto ne gravas. Por ili gravas kiom da kalkuloj ĉi tiu tasko faros en certa (longa) tempoperiodo (trafluo). Ĉi tiuj estos ajnaj taskoj de MapReduce, Hadoop, maŝinlernado, statistiko.
  • Fonaj taskoj - neaktiva. Por tiaj taskoj, nek latencia nek trairo estas tre gravaj. Ĉi tio inkluzivas diversajn testojn, migradojn, rekalkulojn kaj konvertiĝon de datumoj de unu formato al alia. Unuflanke, ili similas al kalkulitaj, aliflanke, ne vere gravas al ni kiom rapide ili estas kompletigitaj.

Ni vidu kiel tiaj taskoj konsumas rimedojn, ekzemple la centra procesoro.

Mallongaj prokrasttaskoj. Tia tasko havos CPU-konsuman ŝablonon similan al ĉi tio:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Peto de la uzanto ricevas por prilaborado, la tasko komencas uzi ĉiujn disponeblajn CPU-kernojn, prilaboras ĝin, resendas respondon, atendas la sekvan peton kaj ĉesas. La sekva peto alvenis - denove ni elektis ĉion, kio estis tie, kalkulis ĝin, kaj atendas la sekvan.

Por garantii la minimuman latentecon por tia tasko, ni devas preni la maksimumajn rimedojn, kiujn ĝi konsumas, kaj rezervi la postulatan nombron da kernoj sur la sbiulo (la maŝino, kiu plenumos la taskon). Tiam la rezerva formulo por nia problemo estos jena:

alloc: cpu = 4 (max)

kaj se ni havas minion-maŝinon kun 16 kernoj, tiam precize kvar tiaj taskoj povas esti metitaj sur ĝin. Ni precipe rimarkas, ke la meza procesora konsumo de tiaj taskoj ofte estas tre malalta - kio estas evidenta, ĉar signifa parto de la tempo la tasko atendas peton kaj faras nenion.

Kalkulaj taskoj. Ilia ŝablono estos iomete malsama:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

La averaĝa CPU-rimeda konsumo por tiaj taskoj estas sufiĉe alta. Ofte ni volas, ke kalkultasko finiĝu en certa tempo, do ni devas rezervi la minimuman nombron da procesoroj, kiujn ĝi bezonas, por ke la tuta kalkulo estu finita en akceptebla tempo. Ĝia rezerva formulo aspektos jene:

alloc: cpu = [1,*)

"Bonvolu meti ĝin sur sbiulon kie estas almenaŭ unu libera kerno, kaj tiam tiom da kiom estas, ĝi formanĝos ĉion."

Ĉi tie la efikeco de uzo jam estas multe pli bona ol ĉe taskoj kun mallonga prokrasto. Sed la gajno estos multe pli granda, se vi kombinas ambaŭ specojn de taskoj sur unu maŝino kaj disdonas ĝiajn rimedojn dum la irado. Kiam tasko kun mallonga prokrasto postulas procesoron, ĝi ricevas ĝin tuj, kaj kiam la rimedoj ne plu estas bezonataj, ili estas transdonitaj al la komputila tasko, t.e. io tia:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Sed kiel fari tion?

Unue, ni rigardu prod kaj ĝia alloko: cpu = 4. Ni devas rezervi kvar kernojn. En Docker-funkciado, tio povas esti farita en du manieroj:

  • Uzante la opcion --cpuset=1-4, t.e. asignu kvar specifajn kernojn sur la maŝino al la tasko.
  • Uzu --cpuquota=400_000 --cpuperiod=100_000, asignu kvoton por procesora tempo, t.e. indikas, ke ĉiujn 100 ms da reala tempo la tasko konsumas ne pli ol 400 ms da procesora tempo. La samaj kvar kernoj estas akiritaj.

Sed kiu el ĉi tiuj metodoj taŭgas?

cpuset aspektas sufiĉe alloga. La tasko havas kvar dediĉitajn kernojn, kio signifas, ke procesoraj kaŝmemoroj funkcios kiel eble plej efike. Ĉi tio ankaŭ havas malavantaĝon: ni devus preni sur sin la taskon distribui kalkulojn tra la malŝarĝitaj kernoj de la maŝino anstataŭ la OS, kaj ĉi tio estas sufiĉe ne-triviala tasko, precipe se ni provas meti grupajn taskojn sur tia. maŝino. Provoj montris, ke la opcio kun kvoto pli taŭgas ĉi tie: tiamaniere la operaciumo havas pli da libereco en elekto de la kerno por plenumi la taskon en la nuna momento kaj procesora tempo estas distribuata pli efike.

Ni eltrovu kiel fari rezervojn en Docker surbaze de la minimuma nombro da kernoj. La kvoto por bataj taskoj ne plu aplikeblas, ĉar ne necesas limigi la maksimumon, sufiĉas nur garantii la minimumon. Kaj ĉi tie la opcio taŭgas bone docker run --cpushares.

Ni konsentis, ke se aro postulas garantion por almenaŭ unu kerno, tiam ni indikas --cpushares=1024, kaj se estas almenaŭ du kernoj, tiam ni indikas --cpushares=2048. CPU-akcioj neniel malhelpas la distribuadon de la tempo de procesoro kondiĉe ke estas sufiĉe da ĝi. Tiel, se prod ne uzas nuntempe ĉiujn siajn kvar kernojn, nenio limigas batajn taskojn, kaj ili povas uzi plian procesoran tempon. Sed en situacio kie mankas procesoroj, se prod konsumis ĉiujn siajn kvar kernojn kaj atingis sian kvoton, la restanta procesora tempo estos dividita proporcie al cpushares, t.e. en situacio de tri liberaj kernoj, oni estos donita al tasko kun 1024 cpusharoj, kaj la ceteraj du estos donitaj al tasko kun 2048 cpushares.

Sed uzi kvoton kaj akciojn ne sufiĉas. Ni devas certigi, ke tasko kun mallonga prokrasto ricevas prioritaton super grupa tasko dum asignado de procesora tempo. Sen tia prioritato, la bata tasko okupos la tutan procesoran tempon en la momento, kiam ĝi bezonas la prod. Ne ekzistas uj-prioritorigaj elektoj en Docker-kuro, sed Linukso CPU-planilo-politikoj utilas. Vi povas legi pri ili detale tie, kaj en la kadro de ĉi tiu artikolo ni trarigardos ilin mallonge:

  • SCHED_OTHER
    Defaŭlte, ĉiuj normalaj uzantprocezoj sur Linuksa maŝino ricevas.
  • SCHED_BATCH
    Desegnita por rimedoj intensivaj procezoj. Kiam oni metas taskon sur procesoron, oni enkondukas tiel nomatan aktivigan punon: tia tasko malpli verŝajne ricevos procesorajn rimedojn se ĝi estas nuntempe uzata de tasko kun SCHED_OTHER.
  • SCHED_IDLE
    Fona procezo kun tre malalta prioritato, eĉ pli malalta ol bela -19. Ni uzas nian liberkodan bibliotekon unu-nio, por agordi la necesan politikon kiam oni ekfunkciigas la ujon per vokado

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

Sed eĉ se vi ne programas en Java, oni povas fari la samon per la komando chrt:

chrt -i 0 $pid

Ni resumu ĉiujn niajn izoligajn nivelojn en unu tabelon por klareco:

Izola klaso
Alloc Ekzemplo
Docker-funkciaj opcioj
sched_setscheduler chrt*

Prod
CPU = 4
--cpuquota=400000 --cpuperiod=100000
SCHED_OTHER

Batch
CPU = [1, *)
--cpushares=1024
SCHED_BATCH

Iru lin
CPU= [2, *)
--cpushares=2048
SCHED_IDLE

*Se vi faras chrt de ene de ujo, vi eble bezonos la kapablon sys_nice, ĉar defaŭlte Docker forigas ĉi tiun kapablon dum lanĉado de la ujo.

Sed taskoj konsumas ne nur la procesoron, sed ankaŭ trafikon, kiu influas la latentecon de reta tasko eĉ pli ol la malĝusta asigno de procesoraj rimedoj. Tial ni nature volas akiri ĝuste la saman bildon por trafiko. Tio estas, kiam prod-tasko sendas kelkajn pakaĵojn al la reto, ni limigas la maksimuman rapidecon (formulo alloc: lan=[*,500mbps) ), per kiu prod povas fari tion. Kaj por batch ni garantias nur la minimuman trairon, sed ne limigas la maksimumon (formulo alloc: lan=[10Mbps,*) ) En ĉi tiu kazo, prod-trafiko devus ricevi prioritaton super grupaj taskoj.
Ĉi tie Docker ne havas iujn ajn primitivaĵojn, kiujn ni povas uzi. Sed ĝi venas al nia helpo Linukso Trafika Kontrolo. Ni povis atingi la deziratan rezulton helpe de disciplino Hierarkia Fair Service Curve. Kun ĝia helpo, ni distingas du klasojn de trafiko: altprioritata prod kaj malaltprioritata batch/idle. Kiel rezulto, la agordo por elira trafiko estas tia:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

ĉi tie 1:0 estas la "radika qdisko" de la hsfc-disciplino; 1:1 - hsfc-infana klaso kun totala bendolarĝa limo de 8 Gbit/s, sub kiu la infanaj klasoj de ĉiuj ujoj estas metitaj; 1:2 - la infana klaso hsfc estas komuna al ĉiuj bataj kaj neaktivaj taskoj kun "dinamika" limo, kiu estas diskutita malsupre. La ceteraj hsfc-infanaj klasoj estas diligentaj klasoj por nuntempe funkciigaj prod-ujoj kun limoj egalrilatantaj al siaj manifestoj - 450 kaj 400 Mbit/s. Ĉiu hsfc-klaso ricevas qdisc queue fq aŭ fq_codel, depende de la Linukso-kernversio, por eviti pakaĵetperdon dum trafikeksplodoj.

Tipe, tc-disciplinoj servas por prioritatigi nur eksiĝintan trafikon. Sed ni ankaŭ volas prioritati envenantan trafikon - finfine iu grupa tasko povas facile elekti la tutan envenantan kanalon, ricevante, ekzemple, grandan aron da enirdatumoj por mapo&redukto. Por tio ni uzas la modulon ifb, kiu kreas virtualan interfacon ifbX por ĉiu reto-interfaco kaj redirektas envenantan trafikon de la interfaco al forira trafiko sur ifbX. Plue, por ifbX, ĉiuj samaj disciplinoj funkcias por kontroli elirantan trafikon, por kiu la hsfc-agordo estos tre simila:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Dum la eksperimentoj, ni eksciis, ke hsfc montras la plej bonajn rezultojn kiam la 1:2 klaso de ne-prioritata batch/neaktiva trafiko estas limigita sur minionaj maŝinoj al ne pli ol certa libera vojo. Alie, ne-prioritata trafiko havas tro da efiko sur la latencia de prod-taskoj. miniond determinas la nunan kvanton de libera bendolarĝo ĉiun sekundon, mezurante la mezan trafikan konsumon de ĉiuj prod-taskoj de antaŭfiksita helpanto. Unu-nuba - datumcentra nivelo OS en Odnoklassniki kaj subtrahante ĝin de la retinterfaco bendolarĝo Unu-nuba - datumcentra nivelo OS en Odnoklassniki kun malgranda marĝeno, t.e.

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Bandoj estas difinitaj sendepende por envenanta kaj eksiĝinta trafiko. Kaj laŭ la novaj valoroj, miniond reagordas la ne-prioritata klaslimo 1:2.

Tiel, ni efektivigis ĉiujn tri izolaj klasoj: prod, batch kaj idle. Ĉi tiuj klasoj multe influas la agadkarakterizaĵojn de taskoj. Sekve, ni decidis meti ĉi tiun atributon ĉe la supro de la hierarkio, tiel ke, kiam oni rigardas la nomon de la hierarkia vico, tuj estu klare, pri kio ni traktas:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Ĉiuj niaj amikoj retejo и muziko la frontoj tiam estas metitaj en la hierarkion sub prod. Ekzemple, sub batch, ni metu la servon muzika katalogo, kiu periode kompilas katalogon de trakoj de aro de mp3-dosieroj alŝutitaj al Odnoklassniki. Ekzemplo de servo sub idle estus muzika transformilo, kiu normaligas la muzikan volumnivelon.

Kun la ekstraj linioj denove forigitaj, ni povas skribi niajn servajn nomojn pli flate aldonante la taskan izolan klason al la fino de la plena serva nomo: retejo.front.prod, katalogo.muziko.baĉo, transformer.music.idle.

Kaj nun, rigardante la nomon de la servo, ni komprenas ne nur kian funkcion ĝi plenumas, sed ankaŭ ĝian izolan klason, kio signifas ĝian kritikecon, ktp.

Ĉio estas bonega, sed estas unu amara vero. Estas neeble tute izoli taskojn kurantajn sur unu maŝino.

Kion ni sukcesis atingi: se batch konsumas intense nur CPU-resursoj, tiam la enkonstruita Linuksa CPU-planilo tre bone faras sian laboron, kaj preskaŭ ne estas efiko al la prod-tasko. Sed se ĉi tiu grupa tasko komencas aktive labori kun memoro, tiam la reciproka influo jam aperas. Ĉi tio okazas ĉar la prod-tasko estas "forlavita" de la memorkaŝmemoroj de la procesoro - kiel rezulto, kaŝmemoro misfunkcias pliiĝas, kaj la procesoro prilaboras la prod-taskon pli malrapide. Tia grupa tasko povas pliigi la latentecon de nia tipa prod-ujo je 10%.

Izola trafiko estas eĉ pli malfacila pro la fakto, ke modernaj retkartoj havas internan atendovicon da pakaĵoj. Se la pakaĵeto de la bata tasko alvenas tie unue, tiam ĝi estos la unua, kiu estos transdonita per la kablo, kaj nenio povas esti farita pri ĝi.

Krome, ni ĝis nun nur sukcesis solvi la problemon pri prioritato de TCP-trafiko: la hsfc-aliro ne funkcias por UDP. Kaj eĉ en la kazo de TCP-trafiko, se la bata tasko generas multe da trafiko, ĉi tio ankaŭ donas ĉirkaŭ 10% pliiĝon en la prokrasto de la prod-tasko.

kulpo toleremo

Unu el la celoj dum evoluigado de unu-nubo estis plibonigi la faŭltoleremo de Odnoklassniki. Tial, poste mi ŝatus konsideri pli detale eblajn scenarojn de fiaskoj kaj akcidentoj. Ni komencu per simpla scenaro - fiasko de ujo.

La ujo mem povas malsukcesi en pluraj manieroj. Ĉi tio povus esti ia eksperimento, cimo aŭ eraro en la manifesto, pro kiu la prod-tasko komencas konsumi pli da rimedoj ol indikite en la manifesto. Ni havis kazon: programisto efektivigis unu kompleksan algoritmon, relaboris ĝin multfoje, superpensis sin kaj iĝis tiel konfuzita ke finfine la problemo estis cirkulita en tre ne-triviala maniero. Kaj ĉar la prod-tasko havas pli altan prioritaton ol ĉiuj aliaj sur la samaj helpantoj, ĝi komencis konsumi ĉiujn disponeblajn procesorajn rimedojn. En ĉi tiu situacio, izolado, aŭ pli ĝuste la CPU-tempokvoto, savis la tagon. Se tasko estas asignita kvoto, la tasko ne konsumos pli. Sekve, bataj kaj aliaj prod-taskoj, kiuj funkciis per la sama maŝino, nenion rimarkis.

La dua ebla problemo estas la ujo falanta. Kaj ĉi tie rekomencaj politikoj savas nin, ĉiuj konas ilin, Docker mem faras bonegan laboron. Preskaŭ ĉiuj prod-taskoj havas ĉiam rekomencan politikon. Foje ni uzas on_failure por bataj taskoj aŭ por sencimigi prod-ujojn.

Kion vi povas fari se tuta helpanto ne estas disponebla?

Evidente, rulu la ujon sur alia maŝino. La interesa parto ĉi tie estas kio okazas al la IP-adreso(j) asignitaj al la ujo.

Ni povas asigni al ujoj la samajn IP-adresojn kiel la minion-maŝinoj sur kiuj ĉi tiuj ujoj funkcias. Tiam, kiam la ujo estas lanĉita sur alia maŝino, ĝia IP-adreso ŝanĝiĝas, kaj ĉiuj klientoj devas kompreni, ke la ujo moviĝis, kaj nun ili devas iri al malsama adreso, kiu postulas apartan Servo Discovery servo.

Servo Discovery estas oportuna. Estas multaj solvoj sur la merkato de diversaj gradoj de faŭltoleremo por organizi servan registron. Ofte tiaj solvoj efektivigas ŝarĝan ekvilibran logikon, stokas plian agordon en la formo de KV-stokado ktp.
Tamen ni ŝatus eviti la bezonon efektivigi apartan registron, ĉar tio signifus enkonduki kritikan sistemon, kiu estas uzata de ĉiuj servoj en produktado. Ĉi tio signifas, ke ĉi tio estas ebla malsukcesa punkto, kaj vi devas elekti aŭ evoluigi tre toleran solvon, kiu evidente estas tre malfacila, temporaba kaj multekosta.

Kaj plia granda malavantaĝo: por ke nia malnova infrastrukturo funkciu kun la nova, ni devus reverki absolute ĉiujn taskojn por uzi ian Service Discovery-sistemon. Estas MULTA laboro, kaj en iuj lokoj estas preskaŭ neeble kiam temas pri malaltnivelaj aparatoj, kiuj funkcias ĉe la OS-kerno-nivelo aŭ rekte kun la aparataro. Efektivigo de ĉi tiu funkcieco uzante establitajn solvpadronojn, kiel ekzemple flankaŭto signifus kelkloke plian ŝarĝon, en aliaj - komplikaĵo de operacio kaj pliaj malsukcesaj scenaroj. Ni ne volis kompliki aferojn, do ni decidis fari la uzon de Service Discovery laŭvola.

En unu-nubo, la IP sekvas la ujon, t.e. ĉiu taska kazo havas sian propran IP-adreson. Ĉi tiu adreso estas "senmova": ĝi estas asignita al ĉiu okazo kiam la servo unue estas sendita al la nubo. Se servo havis malsaman nombron da okazoj dum sia vivo, tiam finfine ĝi estos asignita tiom da IP-adresoj kiom estis maksimumaj okazoj.

Poste, ĉi tiuj adresoj ne ŝanĝiĝas: ili estas atribuitaj unufoje kaj daŭre ekzistas dum la tuta vivo de la servo en produktado. IP-adresoj sekvas ujojn tra la reto. Se la ujo estas transdonita al alia helpanto, tiam la adreso sekvos ĝin.

Tiel, la mapado de servonomo al ĝia listo de IP-adresoj tre malofte ŝanĝiĝas. Se vi denove rigardas la nomojn de la servokazoj, kiujn ni menciis komence de la artikolo (1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, …), ni rimarkos, ke ili similas la FQDN-ojn uzatajn en DNS. Ĝuste, por mapi la nomojn de servaj instancoj al iliaj IP-adresoj, ni uzas la DNS-protokolon. Plie, ĉi tiu DNS resendas ĉiujn rezervitajn IP-adresojn de ĉiuj ujoj - ambaŭ kurantaj kaj haltigitaj (ni diru, ke tri kopioj estas uzataj, kaj ni havas kvin adresojn rezervitaj tie - ĉiuj kvin estos resenditaj). Klientoj, ricevinte ĉi tiujn informojn, provos establi ligon kun ĉiuj kvin kopioj - kaj tiel determini tiujn, kiuj funkcias. Ĉi tiu opcio por determini haveblecon estas multe pli fidinda; ĝi ne implikas nek DNS nek Service Discovery, kio signifas, ke ne estas malfacilaj problemoj por solvi por certigi la gravecon de informoj kaj misfunkciadon de ĉi tiuj sistemoj. Krome, en kritikaj servoj, de kiuj dependas la funkciado de la tuta portalo, ni tute ne povas uzi DNS, sed simple enigi IP-adresojn en la agordon.

Efektivigi tian IP-translokigon malantaŭ ujoj povas esti ne bagatela - kaj ni rigardos kiel ĝi funkcias per la sekva ekzemplo:

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Ni diru, ke la unu-nuba majstro donas la komandon al servisto M1 por kuri 1.ok-web.group1.web.front.prod kun adreso 1.1.1.1. Laboras sur helpanto BIRDO, kiu reklamas ĉi tiun adreson al specialaj serviloj itinero reflektoro. Ĉi-lastaj havas BGP-sesion kun la reto aparataro, en kiu la itinero de adreso 1.1.1.1 sur M1 estas tradukita. M1 sendas pakaĵojn ene de la ujo uzante Linukso. Estas tri itineraj reflektoserviloj, ĉar ĉi tio estas tre kritika parto de la unu-nuba infrastrukturo - sen ili, la reto en unu-nuba ne funkcios. Ni metas ilin en malsamaj rakoj, se eble situantaj en malsamaj ĉambroj de la datumcentro, por redukti la verŝajnecon de ĉiuj tri malsukcesi samtempe.

Ni nun supozu, ke la ligo inter la unu-nuba majstro kaj la M1-sbiulo estas perdita. La unu-nuba majstro nun agos laŭ la supozo, ke M1 tute malsukcesis. Tio estas, ĝi donos la komandon al la sbiulo M2 por lanĉi web.group1.web.front.prod kun la sama adreso 1.1.1.1. Nun ni havas du konfliktajn itinerojn en la reto por 1.1.1.1: sur M1 kaj sur M2. Por solvi tiajn konfliktojn, ni uzas la Multeligan Diskriminacion, kiu estas specifita en la BGP-anonco. Ĉi tio estas nombro, kiu montras la pezon de la anoncita itinero. Inter la konfliktantaj itineroj, la itinero kun la pli malalta MED-valoro estos elektita. La unu-nuba majstro subtenas MED kiel integra parto de uj IP-adresoj. Por la unua fojo, la adreso estas skribita kun sufiĉe granda MED = 1 000 000. En la situacio de tia kriz-ujo transdono, la majstro reduktas la MED, kaj M2 jam ricevos la komandon reklami la adreson 1.1.1.1 kun MED = 999 999. La instanco kuranta sur M1 restos ĉe ĉi-kaze ne estas rilato, kaj lia plua sorto nin interesas malmulte ĝis la rilato kun la majstro estos restarigita, kiam li estos haltigita kiel malnova preno.

akcidentoj

Ĉiuj datumcentraj administradsistemoj ĉiam pritraktas negravajn misfunkciadojn akcepteble. Uja superfluo estas la normo preskaŭ ĉie.

Ni rigardu kiel ni traktas krizon, kiel elektropaneo en unu aŭ pluraj ĉambroj de datumcentro.

Kion signifas akcidento por datumcentra administra sistemo? Antaŭ ĉio, ĉi tio estas amasa unufoja fiasko de multaj maŝinoj, kaj la kontrolsistemo bezonas migri multajn ujojn samtempe. Sed se la katastrofo estas tre grandskala, tiam povas okazi, ke ĉiuj taskoj ne povas esti re-asignitaj al aliaj helpantoj, ĉar la rimeda kapablo de la datumcentro falas sub 100% de la ŝarĝo.

Ofte akcidentoj estas akompanataj de malsukceso de la kontroltavolo. Ĉi tio povas okazi pro la fiasko de ĝia ekipaĵo, sed pli ofte pro la fakto, ke akcidentoj ne estas provitaj, kaj la kontrola tavolo mem falas pro la pliigita ŝarĝo.

Kion vi povas fari pri ĉio ĉi?

Amasaj migradoj signifas ke ekzistas granda nombro da agadoj, migradoj kaj deplojoj okazantaj en la infrastrukturo. Ĉiu el la migradoj povas preni iom da tempo necesa por liveri kaj malpaki ujajn bildojn al sbiroj, lanĉi kaj pravalorigi ujojn, ktp. Tial, estas dezirinde, ke pli gravaj taskoj estas lanĉitaj antaŭ malpli gravaj.

Ni rigardu denove la hierarkion de servoj, kun kiuj ni konas, kaj provu decidi, kiujn taskojn ni volas fari unue.

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Kompreneble, ĉi tiuj estas la procezoj kiuj estas rekte implikitaj en prilaborado de uzantpetoj, t.e. prod. Ni indikas ĉi tion per lokiga prioritato — nombro, kiu povas esti asignita al la vico. Se vico havas pli altan prioritaton, ĝiaj servoj estas metitaj unue.

Sur prod ni atribuas pli altajn prioritatojn, 0; sur batch - iom pli malalta, 100; on idle - eĉ pli malalta, 200. Prioritatoj estas aplikataj hierarkie. Ĉiuj taskoj pli malaltaj en la hierarkio havos respondan prioritaton. Se ni volas ke kaŝmemoroj en prod estu lanĉita antaŭ fasadoj, tiam ni atribuas prioritatojn al kaŝmemoro = 0 kaj al antaŭaj subvicoj = 1. Se, ekzemple, ni volas, ke la ĉefa portalo estu lanĉita de la frontoj unue, kaj la muzikfronto nur tiam, tiam ni povas atribui pli malaltan prioritaton al ĉi-lasta - 10.

La sekva problemo estas manko de rimedoj. Do, granda kvanto da ekipaĵoj, tutaj haloj de la datumcentro, malsukcesis, kaj ni relanĉis tiom da servoj, ke nun ne ekzistas sufiĉe da rimedoj por ĉiuj. Vi devas decidi kiujn taskojn oferi por pluigi la ĉefajn kritikajn servojn funkcii.

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Male al lokiga prioritato, ni ne povas sendistinge oferi ĉiujn grupajn taskojn; kelkaj el ili estas gravaj por la funkciado de la portalo. Tial ni reliefigis aparte antaŭzorga prioritato taskoj. Se metita, pli alta prioritata tasko povas antaŭvidi, t.e. ĉesi, pli malaltan prioritattaskon se ekzistas ne pli da liberaj helpantoj. En ĉi tiu kazo, tasko kun malalta prioritato verŝajne restos senloka, t.e. ne plu estos taŭga sbiulo por ĝi kun sufiĉe da liberaj rimedoj.

En nia hierarkio, estas tre simple specifi antaŭzorgan prioritaton tia ke prod kaj batch taskoj antaŭigas aŭ ĉesigas neaktivajn taskojn, sed ne unu la alian, specifante prioritaton por neaktiva egala al 200. Same kiel en la kazo de lokiga prioritato, ni povas uzi nian hierarkion por priskribi pli kompleksajn regulojn. Ekzemple, ni indiku, ke ni oferas la muzikan funkcion se ni ne havas sufiĉajn rimedojn por la ĉefa retportalo, fiksante la prioritaton por la respondaj nodoj pli malalta: 10.

Tutaj DC-akcidentoj

Kial la tuta datumcentro povus malsukcesi? Elemento. Estis bona afiŝo la uragano influis la laboron de la datumcentro. La elementoj povas esti konsiderataj senhejmaj homoj, kiuj iam bruligis la optikon en la dukto, kaj la datumcentro tute perdis kontakton kun aliaj retejoj. La kaŭzo de fiasko ankaŭ povas esti homa faktoro: la funkciigisto eligos tian komandon, ke la tuta datumcentro falos. Ĉi tio povus okazi pro granda cimo. Ĝenerale, kolapso de datumcentroj ne estas malofta. Ĉi tio okazas al ni unufoje ĉiujn kelkajn monatojn.

Kaj ĉi tion ni faras por malhelpi, ke iu ajn tweetu #alive.

La unua strategio estas izolado. Ĉiu unu-nuba kazo estas izolita kaj povas administri maŝinojn en nur unu datumcentro. Tio estas, la perdo de nubo pro cimoj aŭ malĝustaj operaciistkomandoj estas la perdo de nur unu datumcentro. Ni estas pretaj por ĉi tio: ni havas redundan politikon, en kiu kopioj de la aplikaĵo kaj datumoj troviĝas en ĉiuj datumcentroj. Ni uzas misfunkciajn datumbazojn kaj periode testas pri misfunkciadoj.
Ĉar hodiaŭ ni havas kvar datumcentrojn, tio signifas kvar apartajn, tute izolitajn okazojn de unu-nubo.

Ĉi tiu aliro ne nur protektas kontraŭ fizika fiasko, sed ankaŭ povas protekti kontraŭ operaciista eraro.

Kion alian oni povas fari kun la homa faktoro? Kiam operatoro donas al la nubo ian strangan aŭ eble danĝeran komandon, li subite povas esti petita solvi malgrandan problemon por vidi kiom bone li pensis. Ekzemple, se ĉi tio estas ia amasa halto de multaj kopioj aŭ nur stranga komando - reduktante la nombron da kopioj aŭ ŝanĝante la nomon de la bildo, kaj ne nur la numero de versio en la nova manifesto.

Unu-nuba - datumcentra nivelo OS en Odnoklassniki

Rezultoj

Karakterizaĵoj de unu-nubo:

  • Hierarkia kaj vida nomskemo por servoj kaj ujoj, kiu ebligas al vi tre rapide ekscii, kio estas la tasko, al kio ĝi rilatas kaj kiel ĝi funkcias kaj kiu respondecas pri ĝi.
  • Ni aplikas nian tekniko de kombini prod- kaj batch-taskoj pri sbiroj por plibonigi la efikecon de maŝinkundivido. Anstataŭ cpuset ni uzas CPU-kvotojn, akciojn, CPU-planadpolitikojn kaj Linuksan QoS.
  • Ne eblis tute izoli ujojn kurantajn sur la sama maŝino, sed ilia reciproka influo restas ene de 20%.
  • Organizi servojn en hierarkion helpas kun aŭtomata katastrofa reakiro prioritatoj pri lokigo kaj antaŭzorgo.

Oftaj Demandoj

Kial ni ne prenis pretan solvon?

  • Malsamaj klasoj de taskoizolado postulas malsaman logikon kiam metita sur helpantojn. Se prod-taskoj povas esti metitaj per simple rezervado de resursoj, tiam bataj kaj neaktivaj taskoj devas esti metitaj, spurante la faktan utiligon de resursoj sur servilmaŝinoj.
  • La bezono konsideri rimedojn konsumitajn de taskoj, kiel ekzemple:
    • reto bendolarĝo;
    • tipoj kaj "spindeloj" de diskoj.
  • La bezono indiki la prioritatojn de servoj dum kriz-respondo, la rajtojn kaj kvotojn de komandoj por rimedoj, kiu estas solvita per hierarkiaj vostoj en unu-nubo.
  • La bezono havi homan nomadon de ujoj por redukti respondtempon al akcidentoj kaj okazaĵoj
  • La malebleco de unufoja ĝeneraligita efektivigo de Service Discovery; la bezono kunekzisti dum longa tempo kun taskoj gastigitaj sur aparataj gastigantoj - io, kio estas solvita per "senmovaj" IP-adresoj sekvantaj ujojn, kaj, kiel konsekvenco, la bezono de unika integriĝo kun granda reto-infrastrukturo.

Ĉiuj ĉi tiuj funkcioj postulus signifajn modifojn de ekzistantaj solvoj por konveni al ni, kaj, taksinte la kvanton da laboro, ni rimarkis, ke ni povus evoluigi nian propran solvon kun proksimume la samaj laborkostoj. Sed via solvo estos multe pli facila por funkcii kaj disvolvi - ĝi ne enhavas nenecesajn abstraktaĵojn, kiuj subtenas funkciojn, kiujn ni ne bezonas.

Al tiuj, kiuj legas la lastajn liniojn, dankon pro via pacienco kaj atento!

fonto: www.habr.com

Aldoni komenton