{"id":84114,"date":"2020-06-05T07:42:55","date_gmt":"2020-06-05T05:42:55","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah"},"modified":"2020-06-05T07:42:55","modified_gmt":"2020-06-05T05:42:55","slug":"one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","status":"publish","type":"post","link":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","title":{"rendered":"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/fa983acacec59ff2d4ed098f87223971.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aloha, mensen! Mijn naam is Oleg Anastasyev, ik werk bij Odnoklassniki in het team van het Platform. Naast mij werkt er een heleboel hardware bij Odnoklassniki. We hebben vier datacentra met ongeveer 500 racks en meer dan 8000 servers. Op een bepaald moment realiseerden we ons dat de implementatie van een nieuw beheersysteem ons zou helpen om de hardware effici\u00ebnter te benutten, het beheer van toegangen te vereenvoudigen, de (her)verdeling van rekenmiddelen te automatiseren, de lancering van nieuwe diensten te versnellen en sneller te reageren op grootschalige storingen. <\/p>\n<p><\/p>\n<p>Wat is daaruit voortgekomen? <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Naast mij en de heleboel hardware zijn er ook mensen die met die hardware werken: ingenieurs die zich direct in de datacentra bevinden; netwerkspecialisten die de netwerkinfrastructuur instellen; beheerders, of SRE's, die de betrouwbaarheid van de infrastructuur waarborgen; en teams van ontwikkelaars, elk verantwoordelijk voor een deel van de functies van het portaal. De software die zij ontwikkelen werkt ongeveer zo:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/592fd0acfa7322eb80fbb85601a92918.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Verzoeken van gebruikers komen aan op de fronten van het hoofportaal <noindex><a rel=\"nofollow\" href=\"http:\/\/www.ok.ru\/\">www.ok.ru<\/a><\/noindex>, en ook op andere, bijvoorbeeld op de fronten van de muziek-API. Deze vragen roepen de applicatieserver aan voor de verwerking van de bedrijfslogica, en tijdens de verwerking roept de server de benodigde gespecialiseerde microservices aan \u2014 one-graph (grafiek van sociale connecties), user-cache (cache van gebruikersprofielen) enzovoort.<\/p>\n<p><\/p>\n<p>Elk van deze diensten is op meerdere machines uitgerold, en elk van hen heeft verantwoordelijke ontwikkelaars die verantwoordelijk zijn voor de werking van de modules, hun exploitatie en technologische ontwikkeling. Al deze diensten draaien op fysieke servers, en tot onlangs voerden we precies \u00e9\u00e9n taak per server uit, dat wil zeggen dat de server was gespecialiseerd voor een specifieke taak.<\/p>\n<p><\/p>\n<p>Waarom zo? Deze benadering had verschillende voordelen:<\/p>\n<p><\/p>\n<ul>\n<li>Het vergemakkelijkt <strong>de massale beheer<\/strong>. Stel dat een taak bepaalde bibliotheken of configuraties vereist. Dan wordt de server toegewezen aan precies \u00e9\u00e9n specifieke groep, wordt er een beleid voor cfengine voor deze groep beschreven (of is dit al beschreven), en deze configuratie wordt gecentraliseerd en automatisch uitgerold op alle servers van deze groep.<\/li>\n<li>Het vereenvoudigt <strong>de diagnose<\/strong>. Stel je voor dat je kijkt naar een verhoogde belasting van de CPU en je begrijpt dat alleen de taak die op deze hardware draait, deze belasting kan hebben gegenereerd. Het zoeken naar de schuldige eindigt heel snel.<\/li>\n<li>Het vereenvoudigt <strong>monitoring<\/strong>. Als er iets mis is met de server, meldt het scherm dit, en je weet precies wie de schuldige is.<\/li>\n<\/ul>\n<p><\/p>\n<p>Een dienst die uit meerdere replicaties bestaat, krijgt meerdere servers toegewezen - \u00e9\u00e9n voor elke replicatie. De rekenkracht voor de dienst wordt dan heel eenvoudig toegewezen: zoveel servers als de dienst heeft, zoveel middelen kan hij maximaal gebruiken. \"Eenvoudig\" hier verwijst niet naar gebruiksgemak, maar naar het feit dat de middelen handmatig worden verdeeld.<\/p>\n<p><\/p>\n<p>Deze aanpak stelde ons ook in staat om <strong>gespecialiseerde hardwareconfiguraties<\/strong> te maken voor de taak die op deze server draait. Als de taak grote hoeveelheden gegevens opslaat, gebruiken we een 4U-server met een chassis voor 38 schijven. Als de taak puur rekenkundig is, kunnen we een goedkopere 1U-server kopen. Dit is effici\u00ebnt in termen van rekenkracht. Dit soort aanpak stelt ons ook in staat om vier keer minder machines te gebruiken met een belasting die vergelijkbaar is met die van een sociale netwerksite die ons goed gezind is. <\/p>\n<p><\/p>\n<p>Zulke effici\u00ebntie in het gebruik van rekenkracht zou ook economische effici\u00ebntie moeten opleveren, uitgaande van de premisse dat servers het duurste zijn. Gedurende lange tijd was hardware de duurste factor, en we hebben veel moeite gestoken in het verlagen van de prijs van hardware door algoritmes voor fouttolerantie te bedenken om de eisen voor de betrouwbaarheid van apparatuur te verlagen. Vandaag zijn we op een punt gekomen waarop de prijs van een server niet langer bepalend is. Behalve als we de allernieuwste exotica niet meerekenen, maakt een specifieke configuratie van servers in een rack geen verschil. Nu hebben we een ander probleem \u2014 de prijs van de ruimte die een server in een datacenter in beslag neemt, oftewel de ruimte in het rack.<\/p>\n<p><\/p>\n<p>Zodra we ons hiervan bewust werden, besloten we te berekenen hoe effici\u00ebnt we racks gebruiken.<br \/>\nWe took the price of the most powerful server from a cost-effective perspective, calculated how many such servers we could fit in the racks, how many tasks we would run on them based on the old model of \"one server = one task,\" and to what extent those tasks could utilize the equipment. The calculation left us in tears. It turns out that our rack utilization efficiency is around 11%. The conclusion is clear: we need to improve data center utilization. It seems like the solution is obvious: we should run multiple tasks on a single server. But this is where the complications start. <\/p>\n<p><\/p>\n<p>Mass configuration becomes significantly more complicated \u2014 it's now impossible to assign a specific group to a server. After all, multiple tasks from different teams can run on the same server. Additionally, the configuration may conflict for different applications. Diagnostics also become more challenging: if you notice increased CPU or disk usage on a server, it's unclear which task is causing the trouble.<\/p>\n<p><\/p>\n<p>But the main issue is that there is no isolation between tasks running on the same machine. For example, the graph showing average response time of a server task before and after launching another unrelated calculation application on the same server indicates a significant increase in response time for the primary task.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/c7c07359ae572ca8c84a4c63559e4083.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>It is clear that tasks should be run either in containers or in virtual machines. Since virtually all our tasks run under a single operating system (Linux) or are adapted to it, we don\u2019t need to support multiple different operating systems. Consequently, virtualization is unnecessary; due to the additional overhead costs, it will be less efficient than containerization.<\/p>\n<p><\/p>\n<p>Als implementatie van containers voor het uitvoeren van taken direct op servers is Docker een goede kandidaat: de besturingssysteembeelden lossen het probleem van conflicterende configuraties goed op. Het feit dat beelden uit meerdere lagen kunnen worden opgebouwd, stelt ons in staat om de hoeveelheid gegevens die nodig zijn voor implementatie op de infrastructuur aanzienlijk te verminderen door gemeenschappelijke delen in afzonderlijke basislagen te plaatsen. Hierdoor worden de basislagen (en de meest omvangrijke) vrij snel in de hele infrastructuur gecached, en voor de levering van verschillende soorten applicaties en versies is het voldoende om alleen kleine lagen te verzenden. <\/p>\n<p><\/p>\n<p>Daarnaast bieden de kant-en-klare register en taggen van beelden in Docker ons de nodige primitieve elementen voor versionering en het leveren van code naar productie.<\/p>\n<p><\/p>\n<p>Docker, net als elke andere vergelijkbare technologie, biedt ons een bepaald niveau van isolatie van containers direct uit de doos. Bijvoorbeeld, geheugenisolatie \u2013 elke container krijgt een limiet voor het gebruik van het geheugen van de machine, dat hij niet overschrijdt. Containers kunnen ook ge\u00efsoleerd worden op basis van CPU-gebruik. Voor ons was de standaardisolatie echter niet voldoende. Daarover later meer.<\/p>\n<p><\/p>\n<p>Het directe uitvoeren van containers op servers is slechts een deel van de problemen. Een ander deel hangt samen met de plaatsing van containers op servers. We moeten begrijpen welke container op welke server kan worden geplaatst. Dit is geen eenvoudige taak, omdat containers zo dicht mogelijk op servers moeten worden geplaatst, zonder de snelheid van hun werking te verminderen. Zo'n plaatsing kan ook complex zijn in termen van fouttolerantie. Vaak willen we replica's van dezelfde service in verschillende racks of zelfs in verschillende zalen van het datacenter plaatsen, zodat we bij een storing van een rack of zaal niet onmiddellijk alle replica's van de service verliezen. <\/p>\n<p><\/p>\n<p>Containers handmatig verdelen is geen optie als je 8.000 servers en 8.000 tot 16.000 containers hebt. <\/p>\n<p><\/p>\n<p>Daarnaast wilden we ontwikkelaars meer autonomie geven bij het toewijzen van resources, zodat ze hun services zelfstandig in productie kunnen plaatsen, zonder hulp van de beheerder. Tegelijkertijd wilden we controle behouden, zodat een secundaire service niet alle resources van onze datacenters verbruikt. <\/p>\n<p><\/p>\n<p>Het is duidelijk dat er een beheerslaag nodig is die dit automatisch beheert.<\/p>\n<p><\/p>\n<p>Hier zijn we dan bij een simpele en duidelijke afbeelding die door alle architecten wordt gekoesterd: drie vierkanten. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/079df6e79874ef55b0d967fde3d5feca.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>one-cloud masters \u2014 een hoog beschikbaar cluster dat verantwoordelijk is voor de orkestratie van de cloud. De ontwikkelaar stuurt een manifest naar de master, waarin alle noodzakelijke informatie voor het hosten van de dienst is opgenomen. Op basis daarvan geeft de master opdrachten aan geselecteerde minions (machines die zijn bedoeld voor het draaien van containers). Op de minions hebben we onze agent, die de opdracht ontvangt, zijn eigen opdrachten aan Docker geeft, en Docker configureert de Linux-kernel voor het starten van de betreffende container. Naast het uitvoeren van opdrachten, informeert de agent de master continu over de statusveranderingen van zowel de minion machine als de daarop draaiende containers.<\/p>\n<p><\/p>\n<h2 id=\"raspredelenie-resursov\">Hulpmiddelenverdeling<\/h2>\n<p><\/p>\n<p>Laten we nu de taak van een complexere middelenverdeling voor meerdere minions onder de loep nemen.<\/p>\n<p><\/p>\n<p>Een rekenmiddel in one-cloud is:<\/p>\n<p><\/p>\n<ul>\n<li>De verwerkingskracht van de CPU die door een specifieke taak wordt gebruikt. <\/li>\n<li>Het geheugen dat beschikbaar is voor de taak. <\/li>\n<li>Netwerkverkeer. Elke minion heeft een specifieke netwerkinterface met een beperkte bandbreedte, waardoor taken niet kunnen worden verdeeld zonder rekening te houden met het datavolume dat via het netwerk wordt verzonden. <\/li>\n<li>Schijven. Naast, uiteraard, de benodigde opslagruimte voor de taak, wijzen we ook het type schijf toe: HDD of SSD. Schijven kunnen een eindig aantal verzoeken per seconde verwerken \u2014 IOPS. Daarom, voor taken die meer IOPS genereren dan \u00e9\u00e9n schijf kan verwerken, wijzen we ook 'spindles' toe \u2014 dat zijn opslagapparaten die uitsluitend voor de taak moeten worden gereserveerd.<\/li>\n<\/ul>\n<p><\/p>\n<p>Dus voor een dienst zoals user-cache kunnen we de benodigde middelen als volgt noteren: 400 CPU-kernen, 2,5 TB geheugen, 50 Gbit\/s verkeer in beide richtingen, 6 TB opslag op HDD, verdeeld over 100 spindles. Of in een meer gebruikelijke vorm als volgt:<\/p>\n<p><\/p>\n<pre><code>alloc:\n    cpu: 400\n    mem: 2500\n    lan_in: 50g\n    lan_out: 50g\n    hdd:100x6T<\/code><\/pre>\n<p><\/p>\n<p>De middelen van de user-cache dienst gebruiken slechts een deel van alle beschikbare middelen in de productie-infrastructuur. Daarom willen we ervoor zorgen dat user-cache, plotseling, of dit nu door een operatorfout komt of niet, niet meer middelen verbruikt dan hem zijn toegewezen. Met andere woorden, we moeten de middelen limiteren. Maar waar zouden we de quota aan kunnen koppelen?<\/p>\n<p><\/p>\n<p>Laten we terugkeren naar ons sterk vereenvoudigde schema van de interactie tussen componenten en deze opnieuw tekenen met meer details \u2014 zo: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/27e5bfbffadd3d4b9fdc6bf138d135ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Wat opvalt:<\/p>\n<p><\/p>\n<ul>\n<li>De webfrontend en de muziek gebruiken ge\u00efsoleerde clusters van dezelfde applicatieserver.<\/li>\n<li>We kunnen logische lagen onderscheiden waartoe deze clusters behoren: fronten, caches, opslag- en datamanagementlagen.<\/li>\n<li>De frontend is heterogeen; het zijn verschillende functionele subsysteem. <\/li>\n<li>Caches kunnen ook worden verspreid over het subsysteem waarvan ze de gegevens cachen.<\/li>\n<\/ul>\n<p><\/p>\n<p>Laten we de afbeelding nogmaals opnieuw tekenen:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/905dacc0aca859e65bd33ef751a557cf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>H\u00e9! We zien een hi\u00ebrarchie! Dit betekent dat we hulpbronnen in grotere brokken kunnen toewijzen: wijs een verantwoordelijke ontwikkelaar aan voor een knooppunt van deze hi\u00ebrarchie, dat overeenkomt met het functionele subsysteem (zoals \u2018music\u2019 op de afbeelding), en koppel aan hetzelfde hi\u00ebrarchische niveau een quotum. Zo'n hi\u00ebrarchie stelt ons ook in staat om de diensten flexibeler te organiseren voor eenvoudig beheer. Bijvoorbeeld, aangezien alle web een zeer grote groepering van servers is, splitsen we deze op in verschillende kleinere groepen, zoals weergegeven op de afbeelding als group1, group2.<\/p>\n<p><\/p>\n<p>Door overbodige lijnen te verwijderen, kunnen we elk knooppunt van onze afbeelding in een plattere vorm vastleggen: <strong>group1.web.front<\/strong>, <strong>api.music.front<\/strong>, <strong>user-cache.cache<\/strong>.<\/p>\n<p><\/p>\n<p>Zo komen we tot het begrip \u2018hi\u00ebrarchische wachtrij\u2019. Deze heeft een naam, zoals \u2018group1.web.front\u2019. Hierop wordt een quotum voor hulpbronnen en gebruikersrechten toegewezen. We geven iemand van DevOps rechten om de service naar de wachtrij te verzenden, en zo'n medewerker kan iets in de wachtrij starten, terwijl iemand van OpsDev - beheerdersrechten krijgt, en nu kan deze de wachtrij beheren, mensen eraan toewijzen, deze mensen rechten geven, enzovoort. Diensten die in deze wachtrij worden gestart, worden uitgevoerd binnen het quotum van de wachtrij. Als het rekentroep van de wachtrij niet voldoende is om alle diensten gelijktijdig uit te voeren, worden ze opeenvolgend uitgevoerd, waardoor zo de daadwerkelijke wachtrij ontstaat. <\/p>\n<p><\/p>\n<p>Laten we de diensten eens nader bekijken. Elke dienst heeft een volledige naam die altijd de naam van de wachtrij omvat. De dienst web frontend zal dan de naam hebben van <strong>ok-web.group1.web.front<\/strong>. En de applicatieserver waarnaar hij verwijst, krijgt de naam <strong>ok-app.group1.web.front<\/strong>. Elke service heeft een manifest waarin alle benodigde informatie voor plaatsing op specifieke machines wordt vermeld: hoeveel middelen deze taak verbruikt, welke configuratie nodig is, hoeveel replicas er moeten zijn, en de eigenschappen voor het omgaan met storingen van deze service. Na de plaatsing van de service op de machines verschijnen er ook exemplaren. Deze worden ook eenduidig benoemd \u2014 zoals het exemplaarnummer en de naam van de service: <strong>1.ok-web.group1.web.front, 2.ok-web.group1.web.front, \u2026<\/strong><\/p>\n<p><\/p>\n<p>Dit is zeer handig: alleen al door naar de naam van de actieve container te kijken, kunnen we veel te weten komen.<\/p>\n<p><\/p>\n<p>Laten we nu iets dieper ingaan op wat deze exemplaren eigenlijk uitvoeren: de taken.<\/p>\n<p><\/p>\n<h2 id=\"klassy-izolyacii-zadach\">Klassen van taakisolatie<\/h2>\n<p><\/p>\n<p>Alle taken in OK (en waarschijnlijk overal) kunnen in groepen worden verdeeld:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Taken met korte vertraging \u2014 prod<\/strong>. Voor deze taken en services is de responsetijd (latency) erg belangrijk, hoe snel elk van de verzoeken door het systeem wordt verwerkt. Voorbeelden van taken: web fronten, caches, applicatieservers, OLTP-opslag, enz.<\/li>\n<li><strong>Reken- of batchtaken<\/strong>. Hier is de snelheid van verwerking van elk specifiek verzoek niet belangrijk. Wat telt, is hoeveel berekeningen deze taak in een bepaald (groot) tijdsinterval zal uitvoeren (throughput). Dit zijn taken zoals MapReduce, Hadoop, machine learning, statistiek.<\/li>\n<li><strong>Achtergrondtaken \u2014 idle<\/strong>. Voor deze taken zijn zowel latency als throughput niet erg belangrijk. Dit omvat verschillende tests, migraties, herberekeningen, conversies van gegevens van het ene naar het andere formaat. Enerzijds lijken ze op rekenkracht-taken, maar anderzijds is het voor ons niet zo belangrijk hoe snel ze worden voltooid. <\/li>\n<\/ul>\n<p><\/p>\n<p>Laten we kijken hoe dergelijke taken middelen verbruiken, bijvoorbeeld van de centrale processor.<\/p>\n<p><\/p>\n<p><strong>Taken met korte vertraging.<\/strong> De patroon van CPU-verbruik voor zo'n taak zal er ongeveer als volgt uitzien:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/1ed82c0df76325eb30056ad9af86e86e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Een verzoek van een gebruiker komt binnen, de taak begint alle beschikbare CPU-kernen te gebruiken, verwerkt het verzoek, geeft een antwoord terug, wacht op het volgende verzoek en staat stil. Er komt een nieuw verzoek \u2014 weer wordt alles geselecteerd, het wordt opnieuw berekend, we wachten op het volgende.<\/p>\n<p><\/p>\n<p>Om een minimale vertraging voor zo'n taak te garanderen, moeten we het maximale verbruikte aantal middelen reserveren en het benodigde aantal kernen op de minion (de machine die de taak uitvoert) reserveren. Dan ziet de reservatieformule voor onze taak er als volgt uit:<\/p>\n<p><\/p>\n<pre><code>alloc: cpu = 4 (max)<\/code><\/pre>\n<p><\/p>\n<p>En als we een minionmachine hebben met 16 kernen, kunnen we precies vier van dergelijke taken plaatsen. We moeten opmerken dat het gemiddelde CPU-verbruik van deze taken vaak heel laag is \u2014 dat is vanzelfsprekend, aangezien de taak een aanzienlijk deel van de tijd in afwachting van een verzoek verkeert en niets doet.<\/p>\n<p><\/p>\n<p><strong>Berekeningstaken.<\/strong> Hun patroon zal iets anders zijn:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/35b37fa1d70a137287cafdbfe3bcfc2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Het gemiddelde verbruik van CPU-resources voor dergelijke taken is vrij hoog. Vaak willen we dat de berekeningstaak binnen een bepaalde tijd wordt uitgevoerd, dus moeten we het minimum aantal processors reserveren dat nodig is om de hele berekening in een acceptabele tijd te voltooien. De reserveringsformule zou er als volgt uitzien:<\/p>\n<p><\/p>\n<pre><code>alloc: cpu = [1,*)<\/code><\/pre>\n<p><\/p>\n<p><em>\u201ePlaats het alsjeblieft op de minion waar minstens \u00e9\u00e9n vrije kern beschikbaar is, en verder zoveel als beschikbaar \u2014 alles mag worden gebruikt.\u201d<\/em><\/p>\n<p><\/p>\n<p>Hier is de effici\u00ebntie van het gebruik al veel beter dan bij taken met een korte vertraging. Maar de winst zal aanzienlijk groter zijn als je beide typen taken op \u00e9\u00e9n minionmachine combineert en haar middelen on-the-fly verdeelt. Wanneer de taak met korte vertraging CPU nodig heeft \u2014 krijgt deze die onmiddellijk en wanneer de middelen niet meer nodig zijn \u2014 worden ze doorgegeven aan de berekeningstaak, dat wil zeggen, zoiets:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/875ad8d3f6a01e4fd0a89d0931e986c1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Maar hoe doe je dat?<\/p>\n<p><\/p>\n<p>Laten we beginnen met prod en zijn alloc: cpu = 4. We moeten vier kernen reserveren. In Docker run kan dit op twee manieren worden gedaan: <\/p>\n<p><\/p>\n<ul>\n<li>Met de optie <code>--cpuset=1-4<\/code>, dat wil zeggen, vier specifieke kernen aan de taak toekennen op de machine.<\/li>\n<li>Gebruik <code>--cpuquota=400_000 --cpuperiod=100_000<\/code>, een quota voor CPU-tijd instellen, dat wil zeggen, aangeven dat de taak niet meer dan 400 ms CPU-tijd verbruikt in elke 100 ms echte tijd. Dit resulteert in dezelfde vier kernen. <\/li>\n<\/ul>\n<p><\/p>\n<p>Maar welke van deze methoden is geschikt?<\/p>\n<p><\/p>\n<p>De cpuset ziet er behoorlijk aantrekkelijk uit. De taak heeft vier toegewezen kernen, wat betekent dat de processorkatana's maximaal effectief zullen werken. Dit heeft echter ook een keerzijde: we zouden de taak van het verdelen van berekeningen over de ongebruikte kernen van de machine in plaats van het besturingssysteem op ons moeten nemen, en dat is een vrij complexe taak, vooral als we proberen om batchtaken op zo'n machine te plaatsen. Tests hebben aangetoond dat de optie met quota hier beter geschikt is: zo heeft het besturingssysteem meer vrijheid in het kiezen van de kern voor het uitvoeren van de taak op dat moment en wordt de processingtijd effici\u00ebnter verdeeld.<\/p>\n<p><\/p>\n<p>Laten we bekijken hoe we in Docker minimaal aantal kernen kunnen reserveren. Quota voor batchtaken is niet meer van toepassing, omdat het niet nodig is om een maximum te begrenzen, het is voldoende om alleen een minimum te garanderen. En hiervoor is de optie goed geschikt <code>docker run --cpushares<\/code>.<\/p>\n<p><\/p>\n<p>We zijn overeengekomen dat als de batch een garantie voor minimaal \u00e9\u00e9n kern vereist, we aangeven <code>--cpushares=1024<\/code>, en als het minimum voor twee kernen is, geven we aan <code>--cpushares=2048<\/code>. Cpu shares hebben geen invloed op de verdeling van de processingtijd zolang deze voldoende is. Dat betekent dat als prod op dat moment niet al zijn vier kernen gebruikt \u2014 er niets is dat de batchtaken beperkt, en ze kunnen de extra processingtijd gebruiken. Maar in een situatie van tekort aan processor, als prod al zijn vier kernen heeft gebruikt en tegen het quota aanloopt \u2014 zal de resterende processingtijd proportioneel worden verdeeld volgens de cpushares, dat wil zeggen dat in de situatie van drie beschikbare kernen \u00e9\u00e9n de taak met 1024 cpushares zal krijgen, en de andere twee de taak met 2048 cpushares.<\/p>\n<p><\/p>\n<p>Maar het gebruik van quota en shares is niet voldoende. We moeten ervoor zorgen dat de taak met een korte vertraging prioriteit krijgt boven de batchtaak bij het verdelen van de processingtijd. Zonder deze prioritering zal de batchtaak alle processingtijd in beslag nemen op het moment dat het nodig is voor prod. In Docker run zijn er geen opties voor het prioriteren van containers, maar het CPU-scheduler beleid in Linux komt ons te hulp. Meer hierover kan uitgebreid worden gelezen <noindex><a rel=\"nofollow\" href=\"http:\/\/man7.org\/linux\/man-pages\/man2\/sched_setscheduler.2.html\">here<\/a><\/noindex>, maar in dit artikel zullen we er kort op ingaan:<\/p>\n<p><\/p>\n<ul>\n<li><strong>SCHED_OTHER<\/strong><br \/>\nAlle gewone gebruikersprocessen op een Linux-machine krijgen dit standaard toegewezen.<\/li>\n<li><strong>SCHED_BATCH<\/strong><br \/>\nBestemd voor resource-intensieve processen. Wanneer een taak in de processor wordt geplaatst, wordt er een zogenaamde activatieboete ingevoerd: een taak heeft minder kans om CPU-resources te krijgen wanneer deze op dat moment wordt gebruikt door een taak met SCHED_OTHER.<\/li>\n<li><strong>SCHED_IDLE<\/strong><br \/>\nEen achtergrondproces met een zeer lage prioriteit, zelfs lager dan nice \u201319. We gebruiken onze open-source bibliotheek. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/odnoklassniki\/one-nio\">one-nio<\/a><\/noindex>, om de benodigde scheduler policy in te stellen bij het opstarten van de container aanroept.<\/li>\n<\/ul>\n<p><\/p>\n<pre><code class=\"java\">one.nio.os.Proc.sched_setscheduler( pid, Proc.SCHED_IDLE )<\/code><\/pre>\n<p><\/p>\n<p>Maar zelfs als je niet in Java programmeert, kan hetzelfde worden gedaan met het commando chrt:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">chrt -i 0 $pid<\/code><\/pre>\n<p><\/p>\n<p>Laten we al onze isolatieniveaus samenvatten in \u00e9\u00e9n tabel voor duidelijkheid:<\/p>\n<p><\/p>\n<p>Isolatieklasse<br \/>\nAlloc voorbeeld<br \/>\nDocker run opties<br \/>\nsched_setscheduler chrt*<\/p>\n<p>Prod<br \/>\ncpu = 4<br \/>\n<code>--cpuquota=400000<\/code> <code>--cpuperiod=100000<\/code><br \/>\nSCHED_OTHER<\/p>\n<p>Batch<br \/>\nCpu = [1, * )<br \/>\n<code>--cpushares=1024<\/code><br \/>\nSCHED_BATCH<\/p>\n<p>Idle<br \/>\nCpu= [2, *)<br \/>\n<code>--cpushares=2048<\/code><br \/>\nSCHED_IDLE<\/p>\n<p><\/p>\n<p>*Als je chrt vanuit de container uitvoert, is mogelijk de capability sys_nice vereist, omdat Docker deze capability standaard verwijdert bij het opstarten van de container.<\/p>\n<p><\/p>\n<p>Maar taken verbruiken niet alleen de processor, maar ook verkeer, wat de latency van een netwerktask nog meer be\u00efnvloedt dan een ongepaste toewijzing van CPU-resources. Daarom willen we natuurlijk ook dezelfde afbeelding voor verkeer verkrijgen. Dat betekent dat wanneer de prod-taak bepaalde pakketten naar het netwerk verzendt, we de maximale snelheid quoteren (formule <em>alloc: lan=[*,500mbps)<\/em> ), waarmee prod dit kan doen. En voor batch garanderen we alleen een minimale doorvoersnelheid, maar beperken we de maximale niet (formule <em>alloc: lan=[10Mbps,*)<\/em> ) Hierbij moet het verkeer van prod prioriteit krijgen boven batch-taken.<br \/>\nHier biedt Docker geen primitieve middelen die we kunnen gebruiken. Maar we worden geholpen door <noindex><a rel=\"nofollow\" href=\"http:\/\/lartc.org\/\">Linux Traffic Control<\/a><\/noindex>. We hebben het gewenste resultaat bereikt met de discipline <noindex><a rel=\"nofollow\" href=\"http:\/\/linux-ip.net\/articles\/hfsc.en\/\">Hierarchical Fair Service Curve<\/a><\/noindex>. Hiermee onderscheiden we twee klassen verkeer: hoogprioritaire prod en laagprioritaire batch\/idle. De uiteindelijke configuratie voor het uitgaande verkeer ziet er als volgt uit:<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/gh\/5k\/kf\/gh5kkfwkhwv0ilmbdmdbo83dp6k.png\"><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/3f52a968118b6021bd0c920af17a00c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<p>hier 1:0 \u2014 &#171;root qdisc&#187; discipline hsfc; 1:1 \u2014 child class hsfc met een totale bandbreedte limiet van 8 Gbit\/s, waaronder alle child classes van de containers zijn geplaatst; 1:2 \u2014 child class hsfc die gezamenlijk is voor alle batch- en idle-taken met een &#171;dynamische&#187; limiet, waarover hieronder meer. De overige child classes hsfc zijn toegewezen voor de momenteel actieve prod-containers met limieten die overeenkomen met hun manifests, \u2014 450 en 400 Mbit\/s. Aan elke hsfc class is een qdisc wachtrij fq of fq_codel toegewezen, afhankelijk van de versie van de linux kernel, om pakketverlies tijdens verkeerspieken te voorkomen. <\/p>\n<p><\/p>\n<p>Normaal gesproken dienen tc-disciplines alleen voor het prioriteren van uitgaand verkeer. Maar wij willen ook het inkomende verkeer prioriteren \u2014 want een bepaalde batch-taak kan eenvoudigweg de hele inkomende bandbreedte opeisen, bijvoorbeeld bij het ontvangen van een groot pakket inkomende gegevens voor map&amp;reduce. Hiervoor gebruiken we de module <noindex><a rel=\"nofollow\" href=\"https:\/\/serverfault.com\/questions\/350023\/tc-ingress-policing-and-ifb-mirroring\">ifb<\/a><\/noindex>, die een virtuele interface ifbX aanmaakt voor elke netwerkinterface en het inkomende verkeer van de interface omleidt naar het uitgaande verkeer op ifbX. Vervolgens werken voor ifbX alle dezelfde disciplines voor het beheersen van uitgaand verkeer, waarvoor de hsfc-configuratie zeer vergelijkbaar zal zijn:<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/iz\/ao\/-k\/izao-kgthgu_ptgyq9cjb1il0wm.png\"><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/967da9c0637cc70ba195af781db18adf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<p>Tijdens experimenten hebben we vastgesteld dat hsfc de beste resultaten behaalt wanneer de klasse 1:2 van niet-prioritaire batch\/idle-verkeer op minion-machines niet meer dan een zekere beschikbare bandbreedte overschrijdt. Anders heeft niet-prioritair verkeer te veel invloed op de latentie van prod-taken. De huidige waarde van de beschikbare bandbreedte wordt elke seconde door miniond bepaald door het gemiddelde verkeer dat alle prod-taken van deze minion verbruiken <img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/9d6f38110d3b1693afe222b01430b9bb.jpg\" style=\"display:block;margin: 0 auto;\" \/> en dit van de bandbreedte van de netwerkinterface af te trekken <img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/d5608ec4c58e44b8571ab0b1d0cc7701.jpg\" style=\"display:block;margin: 0 auto;\" \/> met een kleine marge, d.w.z.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/fb01347c2224bd5bbd82169861eeb7e4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De bandbreedtes worden onafhankelijk gedefinieerd voor inkomend en uitgaand verkeer. En in overeenstemming met de nieuwe waarden herconfigureert miniond de limiet van de niet-prioritaire klasse 1:2.<\/p>\n<p><\/p>\n<p>Op deze manier hebben we alle drie de isolatieklassen ge\u00efmplementeerd: prod, batch en idle. Deze klassen hebben een grote invloed op de prestaties van de taken. Daarom hebben we besloten dit kenmerk bovenaan de hi\u00ebrarchie te plaatsen, zodat het bij het bekijken van de naam van de hi\u00ebrarchische wachtrij meteen duidelijk is waar we mee te maken hebben: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/34dc89c461db711b19a0f4eccc50efce.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Al onze bekende <strong>web<\/strong> en <strong>music<\/strong> fronten worden dan onder prod in de hi\u00ebrarchie geplaatst. Bijvoorbeeld laten we de service <strong>music catalog onder batch plaatsen.<\/strong>, dat periodiek een catalogus van tracks samenstelt uit de verzameling mp3-bestanden die in 'Odnoklassniki' zijn ge\u00fcpload. Een voorbeeld van een idle-service kan zijn <strong>muziektransformator<\/strong>, die het geluidsniveau van muziek normaliseert.<\/p>\n<p><\/p>\n<p>Door de overbodige lijnen opnieuw te verwijderen, kunnen we de namen van onze diensten platter opschrijven door de klasse van taakisolatie aan het einde van de volledige servicenaam toe te voegen: <strong>web.front.prod<\/strong>, <strong>catalog.music.batch<\/strong>, <strong>transformer.music.idle<\/strong>.<\/p>\n<p><\/p>\n<p>En nu, kijkend naar de naam van de service, begrijpen we niet alleen welke functie deze vervult, maar ook zijn klasse van isolatie, en dus zijn kritiekheid enzovoort.<\/p>\n<p><\/p>\n<p>Alles is geweldig, maar er is \u00e9\u00e9n bittere waarheid. Het is onmogelijk om taken die op \u00e9\u00e9n machine draaien volledig te isoleren.<\/p>\n<p><\/p>\n<p>Wat we hebben bereikt: als de batch intensief CPU-resources verbruikt, doet de ingebouwde Linux CPU-scheduler zijn taak heel goed, en de invloed op de prod-taak is bijna verwaarloosbaar. Maar als deze batch-taak actief met geheugen begint te werken, dan komt de wederzijdse invloed al naar voren. Dit gebeurt omdat de processor caches van de prod-taak worden 'leeggehaald' \u2014 uiteindelijk nemen de misses in de cache toe, en de processor verwerkt de prod-taak trager. Zo'n batch-taak kan de latentie van onze typische prod-container met 10% verhogen. <strong>van<\/strong> Het isoleren van verkeer is nog moeilijker omdat moderne netwerkkaarten een interne wachtrij voor pakketten hebben. Als een pakket van de batch-taak daar als eerste binnenkomt, dan wordt het ook als eerste via de kabel verzonden, en daar is niets aan te doen.<\/p>\n<p><\/p>\n<p>Bovendien hebben we tot nu toe alleen de prioriteringsopgave van TCP-verkeer kunnen oplossen: voor UDP werkt de aanpak met hsfc niet. Zelfs in het geval van TCP-verkeer, als de batch-taak veel verkeer genereert, geeft dit ook ongeveer 10% extra vertraging voor de prod-taak.<\/p>\n<p><\/p>\n<p>Een van de doelen bij het ontwikkelen van one-cloud was het verbeteren van de fouttolerantie van Odnoklassniki. Daarom wil ik verder ingaan op de mogelijke falen- en noodscenario's. Laten we beginnen met een eenvoudig scenario \u2014 de uitval van een container.<\/p>\n<p><\/p>\n<h2 id=\"otkazoustoychivost\">Resilience<\/h2>\n<p><\/p>\n<p>Een van de doelstellingen bij de ontwikkeling van one-cloud was het verbeteren van de uitvalbestendigheid van Odnoklassniki. Daarom wil ik nu dieper ingaan op de mogelijke uitvalscenario's en noodgevallen. Laten we beginnen met een eenvoudig scenario: het falen van een container. <\/p>\n<p><\/p>\n<p>Een container kan op verschillende manieren falen. Dit kan een experiment, een bug of een fout in het manifest zijn, waardoor de prod-taak meer middelen gaat gebruiken dan in het manifest is aangegeven. We hadden een geval waarbij een ontwikkelaar een complex algoritme implementeerde, het meerdere keren herwerkte, zichzelf overcompliceerde en zo in een situatie belandde waarin de taak behoorlijk gecompliceerd vastliep. Aangezien de prod-taak een hogere prioriteit heeft dan alle andere op dezelfde minions, begon deze alle beschikbare CPU-resources te verbruiken. In deze situatie hielp isolatie, meer bepaald de quota voor CPU-tijd. Als er een quota aan de taak is toegewezen, verbruikt de taak niet meer. Daarom merkte geen van de batch- en andere prod-taken die op dezelfde machine draaiden, iets op. <\/p>\n<p><\/p>\n<p>Een tweede mogelijke tegenslag is de crash van een container. En hier komen de restart-beleid van pas, die iedereen kent; Docker gaat daar prima mee om. Bijna alle prod-taken hebben de restart policy altijd ingesteld. Soms gebruiken we on_failure voor batch-taken of voor het debuggen van prod-containers.<\/p>\n<p><\/p>\n<p>Wat kunnen we doen als een hele minion niet beschikbaar is?<\/p>\n<p><\/p>\n<p>Het is duidelijk dat we de container op een andere machine moeten opstarten. Het interessante hierbij is wat er gebeurt met het IP-adres (de adressen) die aan de container zijn toegewezen. <\/p>\n<p><\/p>\n<p>We kunnen containers dezelfde IP-adressen toewijzen als die van de minion-machines waarop deze containers draaien. Wanneer een container op een andere machine wordt opgestart, verandert zijn IP-adres, en alle clients moeten begrijpen dat de container is verhuisd en nu naar een ander adres moet worden gegaan, wat een aparte Service Discovery vereist. <\/p>\n<p><\/p>\n<p>Service Discovery is handig. Er zijn veel oplossingen op de markt met verschillende niveaus van fouttolerantie voor het opzetten van een service registry. Vaak wordt in dergelijke oplossingen ook de logica van een load balancer ge\u00efmplementeerd, evenals het opslaan van aanvullende configuratie in de vorm van een KV-opslag, enz.<br \/>\nEchter, we zouden graag zonder de noodzaak van een aparte registry willen werken, aangezien dit zou betekenen dat we een kritische systeem moeten invoeren dat door alle diensten in productie wordt gebruikt. Dit zou dus een potenti\u00eble faalpunt zijn, en we moeten een zeer fouttolerante oplossing kiezen of ontwikkelen, wat duidelijk erg moeilijk, tijdrovend en duur is. <\/p>\n<p><\/p>\n<p>En nog een groot nadeel: om onze oude infrastructuur samen te laten werken met de nieuwe, zou alles opnieuw geschreven moeten worden om gebruik te maken van een of andere Service Discovery-systeem. Er is HEEL veel werk, en op enkele plekken is dit bijna onmogelijk, vooral als het gaat om low-level apparaten die werken op het niveau van de OS-kernel of direct met de hardware. Het implementeren van deze functionaliteit met behulp van gevestigde oplossingspatronen, zoals bijvoorbeeld <noindex><a rel=\"nofollow\" href=\"https:\/\/linkerd.io\">side-car<\/a><\/noindex> zou op sommige plekken extra belasting betekenen, op andere plekken complicatie van de exploitatie en extra uitvalszenario's. We wilden het ons niet moeilijker maken, dus besloten we om het gebruik van Service Discovery optioneel te maken. <\/p>\n<p><\/p>\n<p>In one-cloud volgt het IP-adres de container, dat wil zeggen dat elke instantie van een taak zijn eigen IP-adres heeft. Dit adres is 'statistisch': het wordt toegewezen aan elke instantie op het moment van de eerste verzending van de service naar de cloud. Als de service tijdens zijn levensduur verschillende aantallen instanties had, dan zal uiteindelijk het aantal IP-adressen dat aan de service is toegewezen gelijk zijn aan het maximale aantal instanties.<\/p>\n<p><\/p>\n<p>Deze adressen veranderen daarna niet: ze worden eenmaal toegewezen en blijven bestaan gedurende de hele levensduur van de service in productie. De IP-adressen volgen de containers over het netwerk. Als een container naar een andere minion wordt verplaatst, zal het adres ook meeverhuizen. <\/p>\n<p><\/p>\n<p>Zo verandert de toewijzing van de servicenaam aan zijn lijst van IP-adressen zeer zelden. Als we nog eens kijken naar de namen van de service-instanties die we aan het begin van het artikel noemden (<strong>1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, ...<\/strong>), dan we zullen opmerken dat ze lijken op FQDN's die in DNS worden gebruikt. Dat klopt, om de namen van de service-instanties aan hun IP-adressen weer te geven, gebruiken we het DNS-protocol. Dit DNS retourneert alle gereserveerde IP-adressen van alle containers - zowel actieve als gestopte (stel dat er drie replica's worden gebruikt, terwijl er vijf adressen zijn gereserveerd - alle vijf zullen worden geretourneerd). Klanten die deze informatie ontvangen, zullen proberen verbinding te maken met alle vijf replica's - en zo bepalen welke actief zijn. Deze aanpak voor het bepalen van beschikbaarheid is aanzienlijk betrouwbaarder, omdat er geen DNS of Service Discovery bij betrokken is, wat betekent dat er ook geen ingewikkelde problemen zijn met het waarborgen van actuele informatie en de weerbaarheid van deze systemen. Bovendien kunnen we in kritieke diensten, waarop de werking van het hele portaal afhankelijk is, helemaal geen DNS gebruiken, maar eenvoudigweg de IP-adressen in de configuratie invoeren.<\/p>\n<p><\/p>\n<p>De implementatie van zo'n IP-overdracht tussen containers kan niet triviaal zijn - en we zullen ons richten op hoe dit werkt aan de hand van het volgende voorbeeld:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/faf99c2609a57daa1bdc193cb0f4cb31.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Laten we zeggen dat de one-cloud master de minion M1 opdraagt om te starten <strong>1.ok-web.group1.web.front.prod<\/strong> met het adres 1.1.1.1. Op de minion draait <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Bird_Internet_routing_daemon\">BIRD<\/a><\/noindex>, die dit adres aankondigt aan speciale servers <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Route_reflector\">route reflector<\/a><\/noindex>. De laatste heeft een BGP-sessie met de netwerkapparatuur, waar de route van het adres 1.1.1.1 naar M1 wordt getransmitteerd. M1 routert de pakketten naar binnen de container met behulp van Linux. Er zijn drie route reflectors, omdat dit een zeer kritieke schakel in de one-cloud infrastructuur is - zonder hen zal het netwerk in one-cloud niet functioneren. We plaatsen ze in verschillende rekken, indien mogelijk in verschillende datacenterruimtes, om de kans op een gelijktijdige storing van alle drie te verkleinen.<\/p>\n<p><\/p>\n<p>Laten we nu aannemen dat de verbinding tussen de one-cloud master en de minion M1 is verbroken. De one-cloud master zal nu handelen op basis van de veronderstelling dat M1 volledig is uitgevallen. Dit betekent dat hij de minion M2 opdraagt om te starten <strong>web.group1.web.front.prod<\/strong> met hetzelfde adres 1.1.1.1. Nu hebben we twee conflicterende routes in het netwerk voor 1.1.1.1: op M1 en op M2. Om dergelijke conflicten op te lossen, gebruiken we Multi Exit Discriminator (MED), dat wordt gespecificeerd in de BGP-aankondiging. Dit is een getal dat het gewicht van de aangekondigde route aangeeft. Uit de conflicterende routes wordt de route met de lagere MED-waarde gekozen. De master one-cloud ondersteunt MED als een integraal onderdeel van de IP-adressen van containers. De eerste keer wordt het adres uitgegeven met een vrij hoge MED = 1.000.000. In het geval van een noodoverdracht van de container verlaagt de master de MED, en M2 ontvangt al de opdracht om het adres 1.1.1.1 aan te kondigen met MED = 999.999. De instantie die op M1 draait, blijft op dat moment zonder verbinding, en onze verdere zorgen over zijn lot zijn gering totdat de verbinding met de master is hersteld, wanneer hij als oude dubbele instantie zal worden gestopt.<\/p>\n<p><\/p>\n<h2 id=\"avarii\">Ongevallen<\/h2>\n<p><\/p>\n<p>Alle datacenterbeheer systemen kunnen kleine storingen altijd goed afhandelen. Het uitvallen van een container is praktisch overal normaal.<\/p>\n<p><\/p>\n<p>Laten we eens kijken hoe we een storing afhandelen, bijvoorbeeld een stroomuitval in een of meer zalen van het datacenter.<\/p>\n<p><\/p>\n<p>Wat betekent een storing voor het datacenterbeheersysteem? In de eerste plaats is het een massale gelijktijdige uitval van een groot aantal machines, en het beheersysteem moet tegelijkertijd een groot aantal containers migreren. Maar als de storing zeer omvangrijk is, kan het gebeuren dat niet alle taken kunnen worden verplaatst naar andere minions, omdat de hulpbronnencapaciteit van het datacenter onder de 100% belasting daalt. <\/p>\n<p><\/p>\n<p>Vaak gaan storingen gepaard met het uitvallen van de beheerslaag. Dit kan gebeuren door het falen van zijn apparatuur, maar vaker omdat storingen niet worden getest en de beheerslaag zelf faalt door de verhoogde belasting. <\/p>\n<p><\/p>\n<p>Wat kunnen we hieraan doen?<\/p>\n<p><\/p>\n<p>Massale migraties betekenen dat er in de infrastructuur een groot aantal acties, migraties en plaatsingen ontstaat. Elke migratie kan enige tijd in beslag nemen, nodig voor het leveren en uitpakken van containerafbeeldingen naar de minions, het starten en initialiseren van de containers, enz. Daarom is het wenselijk dat belangrijkere taken eerst worden uitgevoerd voordat minder belangrijke taken worden gestart.<\/p>\n<p><\/p>\n<p>Laten we opnieuw naar de ons bekende hi\u00ebrarchie van services kijken en proberen te bepalen welke taken we als eerste willen uitvoeren.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/2e827271adb8d3ff3d385e53553aaacf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Natuurlijk zijn dit de processen die rechtstreeks betrokken zijn bij de verwerking van gebruikersverzoeken, dat wil zeggen prod. We geven dit aan met <strong>plaatsingsprioriteit<\/strong> \u2014 een nummer dat aan een wachtrij kan worden toegewezen. Als een wachtrij een hogere prioriteit heeft, worden de services daar eerst geplaatst.<\/p>\n<p><\/p>\n<p>Op prod geven we hogere prioriteiten, 0; op batch iets lager, 100; en op idle nog lager, 200. Prioriteiten worden hi\u00ebrarchisch toegepast. Alle taken lager in de hi\u00ebrarchie hebben de bijbehorende prioriteit. Als we willen dat binnen prod caches v\u00f3\u00f3r de frontends worden uitgevoerd, wijzen we prioriteiten toe aan cache = 0 en aan front subqueues = 1. Als we bijvoorbeeld willen dat de hoofdportal uit de fronten eerst wordt gestart, en de music front daarna, kunnen we de laatste een lagere prioriteit geven \u2014 10.<\/p>\n<p><\/p>\n<p>Het volgende probleem is een tekort aan middelen. Dus, we hebben een groot aantal apparatuur verloren, hele zalen van de datacenters, en we hebben zoveel services opgestart dat er nu niet genoeg middelen zijn voor iedereen. We moeten beslissen welke taken we moeten opofferen, zodat de belangrijkste kritieke services blijven draaien. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/1b1ad3da16df6677dd0ba4b038cdd7d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>In tegenstelling tot de plaatsingsprioriteit kunnen we niet zomaar alle batch-taken opofferen, sommige zijn belangrijk voor de werking van het portal. Daarom hebben we apart <strong>verstotingprioriteit<\/strong> toegewezen. Bij het plaatsen kan een taak met een hogere prioriteit een taak met een lagere prioriteit verdringen, dat wil zeggen stoppen, als er geen vrije minions meer zijn. In dat geval zal de taak met een lagere prioriteit waarschijnlijk onverplaatst blijven, dat wil zeggen, er zal geen geschikte minion met voldoende vrije middelen meer zijn.<\/p>\n<p><\/p>\n<p>In onze hi\u00ebrarchie is het heel eenvoudig om zo'n verstotingprioriteit aan te geven, zodat prod- en batch-taken idle-taken verdringen of stoppen, maar niet elkaar, door idle een prioriteit gelijk aan 200 te geven. Net als in het geval van de plaatsingsprioriteit kunnen we onze hi\u00ebrarchie gebruiken om complexere regels te beschrijven. Bijvoorbeeld, we geven muziekfuncties op als we niet genoeg middelen hebben voor het belangrijkste webportal, door voor de bijbehorende knooppunten een lagere prioriteit in te stellen: 10.<\/p>\n<p><\/p>\n<h2 id=\"avarii-dc-celikom\">Uitval van DC in zijn geheel<\/h2>\n<p><\/p>\n<p>Waarom kan een hele datacenter falen? Natuurramp. Er was een goed bericht over hoe <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/dataline\/blog\/333578\/\">een orkaan de werking van het datacenter be\u00efnvloedde<\/a><\/noindex>. Een voorbeeld van een ravage zijn daklozen, die ooit in een verzamelplaats glasvezel hebben verbrand, waardoor het datacentrum volledig het contact met andere locaties verloor. Menselijk falen kan ook een oorzaak zijn: een operator kan een commando geven waardoor het hele datacentrum uitvalt. Dit kan gebeuren door een grote bug. Kortom, datacentra falen \u2014 dat is geen uitzondering. Bij ons gebeurt dit om de paar maanden. <\/p>\n<p><\/p>\n<p>En dit is wat we doen, zodat niemand #okzhivi iets op Twitter plaatst.<\/p>\n<p><\/p>\n<p>De eerste strategie is isolatie. Elke instance van one-cloud is ge\u00efsoleerd en kan alleen de machines van \u00e9\u00e9n datacentrum beheren. Dit betekent dat het verlies van het cloudplatform door bugs of een verkeerd commando van de operator slechts \u00e9\u00e9n datacentrum verliest. Wij zijn hierop voorbereid: er is een back-uppolitiek, waarbij de replicas van applicaties en gegevens in alle datacentra worden geplaatst. We gebruiken fouttolerante databases en testen regelmatig op storingen.<br \/>\nAangezien we vandaag de dag vier datacentra hebben, zijn er ook vier afzonderlijke, volledig ge\u00efsoleerde instanties van one-cloud.<\/p>\n<p><\/p>\n<p>Deze aanpak beschermt niet alleen tegen fysieke uitval, maar kan ook beschermen tegen fouten van de operator.<\/p>\n<p><\/p>\n<p>Wat kan er nog meer gedaan worden met het menselijke aspect? Wanneer een operator het cloudplatform een vreemde of potentieel gevaarlijke opdracht geeft, kan hij plotseling gevraagd worden een kleine taak op te lossen, om te controleren hoe goed hij nadenkt. Bijvoorbeeld, als het gaat om een massale stopzetting van veel replicas of gewoon een vreemde opdracht \u2014 het verminderen van het aantal replicas of het wijzigen van de naam van het beeld, en niet alleen het versienummer in de nieuwe manifest.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/vh\/vw\/0d\/vhvw0dzobo9sd4x7zih_cnfnlu8.png\"><img decoding=\"async\" alt=\"One-cloud \u2014 OS van datacenter-niveau in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/f7ee44a77e30612a3cd99a6f7aee3820.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<h2 id=\"itogi\">Conclusies<\/h2>\n<p><\/p>\n<p>Kenmerken van one-cloud: <\/p>\n<p><\/p>\n<ul>\n<li><strong>Een hi\u00ebrarchisch en overzichtelijk naamgevingssysteem voor diensten en containers<\/strong>, wat het mogelijk maakt om heel snel te achterhalen wat voor taak het is, tot welke het behoort en hoe het werkt en wie ervoor verantwoordelijk is. <\/li>\n<li>Wij passen onze <strong>techniek van het combineren van prod- en batch-<\/strong>taken toe op minions om de effici\u00ebntie van het gedeeld gebruik van machines te vergroten. In plaats van cpuset gebruiken we CPU-quota, shares, CPU-scheduler-beleiden en Linux QoS.<\/li>\n<li>Volledig isoleren van containers die op dezelfde machine draaien, is ons niet gelukt, maar hun wederzijdse invloed blijft binnen de 20%.<\/li>\n<li>Het organiseren van diensten in een hi\u00ebrarchie helpt bij automatische rampenbestrijding door middel van <strong>plaatsingsprioriteiten en verdringing<\/strong>.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"chavo\">VAW<\/h2>\n<p><\/p>\n<p>Waarom we geen kant-en-klare oplossing hebben genomen.<\/p>\n<p><\/p>\n<ul>\n<li>Verschillende klassen van taakisolatie vereisen verschillende logica bij het plaatsen op minions. Terwijl productie-taken eenvoudig kunnen worden gereserveerd voor middelen, moeten batch- en idle-taken worden geplaatst met inzicht in de daadwerkelijke benutting van middelen op de minion-machines. <\/li>\n<li>De noodzaak om rekening te houden met de middelen die door zulke taken worden verbruikt, zoals: \n<ul>\n<li>de netwerkbandbreedte;<\/li>\n<li>schijven types en 'spindles'.<\/li>\n<\/ul>\n<\/li>\n<li>De noodzaak om prioriteiten voor diensten aan te geven bij het afhandelen van storingen, rechten en quota voor teams op middelen, wat wordt opgelost door hi\u00ebrarchische wachtrijen in one-cloud.<\/li>\n<li>De noodzaak om menselijke namen voor containers te hebben om de reactietijden op storingen en incidenten te verkorten.<\/li>\n<li>De onmogelijkheid om Service Discovery gelijktijdig alomtegenwoordig in te voeren; de noodzaak om gedurende lange tijd samen te bestaan met taken die op fysieke hosts zijn geplaatst, wat kan worden opgelost met 'statische' IP-adressen die de containers volgen, en als gevolg daarvan de noodzaak van unieke integratie met een grote netwerkstructuur.<\/li>\n<\/ul>\n<p><\/p>\n<p>Al deze functies zouden aanzienlijke wijzigingen vereisen van bestaande oplossingen om aan onze behoeften te voldoen, en na beoordeling van de hoeveelheid werk realiseerden we ons dat we onze eigen oplossing konden ontwikkelen met ongeveer dezelfde werkbelastingen. Maar onze oplossing zou aanzienlijk gemakkelijker te exploiteren en te ontwikkelen zijn - het bevat geen onnodige abstracties die ons niet benodigde functionaliteit ondersteunen. <\/p>\n<p><\/p>\n<p>Dank aan degenen die deze laatste zinnen lezen voor hun geduld en aandacht!<\/p>\n<p>Bron: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/odnoklassniki\/blog\/346868\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u041e\u043b\u0435\u0433 \u0410\u043d\u0430\u0441\u0442\u0430\u0441\u044c\u0435\u0432, \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0410 \u043a\u0440\u043e\u043c\u0435 \u043c\u0435\u043d\u044f, \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0443\u0447\u0430 \u0436\u0435\u043b\u0435\u0437\u0430. \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0447\u0435\u0442\u044b\u0440\u0435 \u0426\u041e\u0414\u0430, \u0432 \u043d\u0438\u0445 \u043e\u043a\u043e\u043b\u043e 500 \u0441\u0442\u043e\u0435\u043a \u0431\u043e\u043b\u0435\u0435 \u0447\u0435\u043c \u0441 8 \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432. \u0412 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u044b \u043f\u043e\u043d\u044f\u043b\u0438, \u0447\u0442\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u043a\u0443, \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":84115,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-84114","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b!\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47One-cloud \u2014 \u041e\u0421 \u0443\u0440\u043e\u0432\u043d\u044f \u0434\u0430\u0442\u0430-\u0446\u0435\u043d\u0442\u0440\u0430 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-06-05T05:42:55+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-06-05T05:42:55+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47One-cloud \u2014 Datacenter niveau OS in Odnoklassniki | ProHoster","description":"Aloha, mensen!","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47One-cloud \u2014 \u041e\u0421 \u0443\u0440\u043e\u0432\u043d\u044f \u0434\u0430\u0442\u0430-\u0446\u0435\u043d\u0442\u0440\u0430 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 | ProHoster","og:description":"\u0410\u043b\u043e\u0445\u0430, \u043f\u0438\u043f\u043b!","og:url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-06-05T05:42:55+00:00","article:modified_time":"2020-06-05T05:42:55+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"84114","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:04:42","updated":"2022-10-02 14:53:14","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/84114","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=84114"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/84114\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/84115"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=84114"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=84114"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=84114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}