{"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\/de\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","title":{"rendered":"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/fa983acacec59ff2d4ed098f87223971.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aloha, Leute! Ich hei\u00dfe Oleg Anastasyev, ich arbeite in Odnoklassniki im Plattform-Team. Neben mir gibt es in Odnoklassniki eine Menge Hardware. Wir haben vier Rechenzentren mit etwa 500 Racks und mehr als 8.000 Servern. Irgendwann haben wir verstanden, dass die Einf\u00fchrung eines neuen Verwaltungssystems es uns erm\u00f6glichen wird, die Technik effizienter zu betreiben, die Verwaltung von Zug\u00e4ngen zu erleichtern, die (Neu)Verteilung von Rechenressourcen zu automatisieren, die Einf\u00fchrung neuer Dienste zu beschleunigen und schneller auf gro\u00dfangelegte Ausf\u00e4lle zu reagieren. <\/p>\n<p><\/p>\n<p>Was ist daraus geworden? <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Neben mir und der Menge an Hardware gibt es auch Menschen, die mit dieser Hardware arbeiten: Ingenieure, die direkt in den Rechenzentren sind; Netzwerktechniker, die die Netzwerkinfrastruktur einrichten; Administratoren oder SRE, die die Ausfallsicherheit der Infrastruktur gew\u00e4hrleisten; und Entwicklerteams, von denen jedes f\u00fcr einen Teil der Funktionen des Portals verantwortlich ist. Die von ihnen entwickelte Software funktioniert ungef\u00e4hr so:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/592fd0acfa7322eb80fbb85601a92918.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Benutzeranfragen kommen sowohl an die Fronten des Hauptportals <noindex><a rel=\"nofollow\" href=\"http:\/\/www.ok.ru\/\">www.ok.ru<\/a><\/noindex>, als auch an andere, zum Beispiel an die Fronten der Musik-API. Diese rufen zur Verarbeitung der Gesch\u00e4ftslogik den Anwendungsserver auf, der bei der Bearbeitung der Anfrage die notwendigen spezialisierten Mikrodienste aufruft \u2013 one-graph (Graf sozialer Netzwerke), user-cache (Cache von Benutzerprofilen) usw.<\/p>\n<p><\/p>\n<p>Jeder dieser Dienste ist auf zahlreichen Maschinen bereitgestellt, und jeder von ihnen hat verantwortliche Entwickler, die f\u00fcr das Funktionieren der Module, deren Betrieb und technologische Entwicklung zust\u00e4ndig sind. All diese Dienste werden auf physischen Servern gestartet, und bis vor kurzem haben wir genau eine Aufgabe pro Server gestartet, d.h. er war f\u00fcr eine bestimmte Aufgabe spezialisiert.<\/p>\n<p><\/p>\n<p>Warum ist das so? Dieser Ansatz hatte mehrere Vorteile:<\/p>\n<p><\/p>\n<ul>\n<li>Es erleichtert <strong>die Massenverwaltung<\/strong>. Angenommen, eine Aufgabe erfordert bestimmte Bibliotheken oder Konfigurationen. Dann wird der Server genau einer bestimmten Gruppe zugewiesen, eine Policy f\u00fcr diese Gruppe wird beschrieben (oder sie ist bereits beschrieben) und diese Konfiguration wird zentral und automatisiert auf alle Server dieser Gruppe verteilt.<\/li>\n<li>Es vereinfacht <strong>die Diagnostik<\/strong>. Angenommen, Sie beobachten eine erh\u00f6hte Auslastung der CPU und erkennen, dass diese nur von dem Prozess verursacht worden sein kann, der auf dieser Hardware l\u00e4uft. Die Suche nach dem Schuldigen endet sehr schnell.<\/li>\n<li>Es vereinfacht <strong>\u00dcberwachung<\/strong>. Wenn mit dem Server etwas nicht stimmt, informiert der Monitor dar\u00fcber, und Sie wissen genau, wer schuld ist.<\/li>\n<\/ul>\n<p><\/p>\n<p>Ein Dienst, der aus mehreren Replikaten besteht, erh\u00e4lt mehreren Server zugewiesen \u2014 je einen f\u00fcr jede. Dann wird die Rechenressource f\u00fcr den Dienst sehr einfach zugewiesen: so viele Server der Dienst hat, so viel Ressourcen kann er maximal verbrauchen. \"Einfach\" bedeutet hier nicht, dass es leicht zu verwenden ist, sondern dass die Zuteilung der Ressourcen manuell erfolgt.<\/p>\n<p><\/p>\n<p>Ein solcher Ansatz erlaubte es uns auch, <strong>spezialisierte Hardwarekonfigurationen<\/strong> f\u00fcr Aufgaben zu erstellen, die auf diesem Server ausgef\u00fchrt werden. Wenn die Aufgabe gro\u00dfe Datenmengen speichert, verwenden wir einen 4U-Server mit einem Chassis f\u00fcr 38 Festplatten. Wenn die Aufgabe rein rechenintensiv ist, k\u00f6nnen wir einen g\u00fcnstigeren 1U-Server kaufen. Das ist aus Sicht der Rechenressourcen effizient. Zudem erm\u00f6glicht uns dieser Ansatz, viermal weniger Maschinen bei einer Auslastung zu verwenden, die mit einem uns freundlichen sozialen Netzwerk vergleichbar ist. <\/p>\n<p><\/p>\n<p>Eine solche Effizienz der Nutzung der Rechenressourcen sollte auch wirtschaftliche Effizienz gew\u00e4hrleisten, wenn man davon ausgeht, dass das teuerste die Server sind. Lange Zeit war die Hardware am teuersten, und wir haben viel Aufwand betrieben, um die Kosten der Hardware zu senken, indem wir Algorithmen zur Gew\u00e4hrleistung der Ausfallsicherheit entwickelten, um die Anforderungen an die Zuverl\u00e4ssigkeit der Ausstattung zu reduzieren. Und heute sind wir an einem Punkt angelangt, an dem der Preis des Servers nicht mehr entscheidend ist. Wenn man nicht die neueste Exotik betrachtet, hat die konkrete Konfiguration der Server im Rack keine Bedeutung. Jetzt sind wir mit einem anderen Problem konfrontiert \u2014 den Kosten f\u00fcr den Platz, den der Server im Rechenzentrum einnimmt, d.h. den Platz im Rack.<\/p>\n<p><\/p>\n<p>Sich dar\u00fcber im Klaren zu werden, haben wir beschlossen zu berechnen, wie effizient wir die Racks nutzen.<br \/>\nWir haben den Preis des leistungsst\u00e4rksten Servers aus wirtschaftlicher Sicht ermittelt, berechnet, wie viele solcher Server wir in unsere Racks stellen k\u00f6nnen, wie viele Aufgaben wir basierend auf dem alten Modell \"ein Server = eine Aufgabe\" darauf ausf\u00fchren k\u00f6nnten und inwieweit diese Aufgaben die Hardware auslasten w\u00fcrden. Wir haben das berechnet und waren ersch\u00fcttert. Es stellte sich heraus, dass die Effizienz der Rack-Nutzung bei uns bei etwa 11 % liegt. Die Schlussfolgerung ist offensichtlich: Wir m\u00fcssen die Effizienz der Nutzung von Rechenzentren steigern. Die L\u00f6sung scheint einfach: Auf einem Server mehrere Aufgaben gleichzeitig ausf\u00fchren. Doch hier beginnen die Schwierigkeiten. <\/p>\n<p><\/p>\n<p>Die Massenkonfiguration wird erheblich komplexer - jetzt ist es unm\u00f6glich, einem Server eine bestimmte Gruppe zuzuweisen. Denn jetzt k\u00f6nnen auf einem Server mehrere Aufgaben verschiedener Teams ausgef\u00fchrt werden. Dar\u00fcber hinaus kann die Konfiguration f\u00fcr verschiedene Anwendungen konfliktreich sein. Auch die Diagnose wird komplizierter: Wenn Sie einen erh\u00f6hten Prozessor- oder Festplattenverbrauch auf einem Server sehen, wissen Sie nicht, welches der Aufgaben Probleme verursacht.<\/p>\n<p><\/p>\n<p>Das Wichtigste ist jedoch, dass es keine Isolation zwischen den Aufgaben gibt, die auf demselben Rechner ausgef\u00fchrt werden. Beispielsweise zeigt das Diagramm der durchschnittlichen Antwortzeiten einer Serveranwendung vor und nachdem auf demselben Server eine zus\u00e4tzliche, nicht mit der ersten verbundene Anwendung gestartet wurde - die Antwortzeit der Hauptaufgabe hat sich erheblich erh\u00f6ht.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/c7c07359ae572ca8c84a4c63559e4083.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Offensichtlich m\u00fcssen Aufgaben entweder in Containern oder in virtuellen Maschinen ausgef\u00fchrt werden. Da praktisch alle unsere Aufgaben unter einer einzigen OS (Linux) laufen oder entsprechend angepasst sind, ist es nicht erforderlich, viele verschiedene Betriebssysteme zu unterst\u00fctzen. Entsprechend ist Virtualisierung nicht notwendig, da sie aufgrund der zus\u00e4tzlichen Betriebskosten weniger effizient ist als Containerisierung.<\/p>\n<p><\/p>\n<p>Als Umsetzung von Containern zur Ausf\u00fchrung von Aufgaben direkt auf Docker-Servern ist das eine gute Option: Die Images von Dateisystemen l\u00f6sen die Probleme mit konfliktierenden Konfigurationen gut. Die M\u00f6glichkeit, dass Images aus mehreren Schichten bestehen, erm\u00f6glicht es uns, das ben\u00f6tigte Datenvolumen f\u00fcr ihre Bereitstellung in der Infrastruktur erheblich zu reduzieren, indem wir gemeinsame Teile in separate Basisschichten auslagern. Damit werden die Basisschichten (und die gr\u00f6\u00dften) recht schnell in der gesamten Infrastruktur zwischengespeichert, und f\u00fcr die Bereitstellung verschiedener Anwendungstypen und Versionen m\u00fcssen nur noch kleine Schichten \u00fcbertragen werden. <\/p>\n<p><\/p>\n<p>Zudem bieten das bereitgestellte Registry und die Tagging-Funktion von Docker uns fertige Primitiven f\u00fcr Versionierung und Code-Bereitstellung in der Produktion.<\/p>\n<p><\/p>\n<p>Docker stellt, wie jede andere \u00e4hnliche Technologie, von Haus aus ein gewisses Ma\u00df an Isolation der Container bereit. Zum Beispiel wird jedem Container ein Limit f\u00fcr die Nutzung des Arbeitsspeichers der Maschine zugewiesen, das er nicht \u00fcberschreiten kann. Au\u00dferdem k\u00f6nnen die Container hinsichtlich der CPU-Nutzung isoliert werden. F\u00fcr uns war die Standardisolation jedoch nicht ausreichend. Aber dazu mehr weiter unten.<\/p>\n<p><\/p>\n<p>Die direkte Ausf\u00fchrung von Containern auf Servern ist nur ein Teil der Probleme. Ein anderer Teil betrifft die Platzierung der Container auf den Servern. Man muss verstehen, welcher Container auf welchen Server gesetzt werden kann. Diese Aufgabe ist nicht so einfach, da die Container m\u00f6glichst eng auf den Servern platziert werden m\u00fcssen, ohne die Geschwindigkeit ihrer Ausf\u00fchrung zu verringern. Eine solche Platzierung kann auch hinsichtlich der Ausfallsicherheit kompliziert sein. Oft m\u00f6chten wir die Replikate desselben Dienstes in verschiedenen Racks oder sogar in verschiedenen Hallen des Rechenzentrums platzieren, damit wir bei einem Ausfall eines Racks oder einer Halle nicht alle Replikate des Dienstes gleichzeitig verlieren. <\/p>\n<p><\/p>\n<p>Container manuell zu verteilen, ist keine Option, wenn man 8000 Server und 8000 bis 16000 Container hat. <\/p>\n<p><\/p>\n<p>Zudem wollten wir den Entwicklern mehr Autonomie bei der Ressourcenzuteilung geben, sodass sie ihre Dienste selbstst\u00e4ndig in der Produktion bereitstellen k\u00f6nnen, ohne Hilfe eines Administrators. Dabei wollten wir die Kontrolle behalten, damit ein weniger wichtiger Dienst nicht alle Ressourcen unserer Rechenzentren verbraucht. <\/p>\n<p><\/p>\n<p>Offensichtlich ist eine Verwaltungs-Ebene erforderlich, die dies automatisch \u00fcbernimmt.<\/p>\n<p><\/p>\n<p>Hier sind wir bei einem einfachen und verst\u00e4ndlichen Bild angekommen, das alle Architekten lieben: drei K\u00e4stchen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene 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 \u2013 ein ausfallsicherer Cluster, der f\u00fcr die Orchestrierung der Cloud verantwortlich ist. Der Entwickler sendet ein Manifest an den Master, das alle notwendigen Informationen zur Bereitstellung des Dienstes enth\u00e4lt. Der Master gibt auf dieser Grundlage Anweisungen an die ausgew\u00e4hlten Minions (Maschinen, die zum Starten von Containern vorgesehen sind). Auf den Minions befindet sich unser Agent, der den Befehl erh\u00e4lt, bereits seine Befehle an Docker \u00fcbergibt, und Docker konfiguriert den Linux-Kernel zum Start des entsprechenden Containers. Neben der Ausf\u00fchrung von Befehlen berichtet der Agent kontinuierlich an den Master \u00fcber Status\u00e4nderungen sowohl des Minion-Ger\u00e4ts als auch der darauf gestarteten Container.<\/p>\n<p><\/p>\n<h2 id=\"raspredelenie-resursov\">Ressourcenzuteilung<\/h2>\n<p><\/p>\n<p>Jetzt lassen Sie uns die komplexere Aufgabe der Ressourcenzuteilung f\u00fcr mehrere Minions betrachten.<\/p>\n<p><\/p>\n<p>Rechenressource in one-cloud \u2013 das ist:<\/p>\n<p><\/p>\n<ul>\n<li>Die Rechenleistung des Prozessors, die von einer bestimmten Aufgabe ben\u00f6tigt wird. <\/li>\n<li>Der verf\u00fcgbare Speicher f\u00fcr die Aufgabe. <\/li>\n<li>Netzwerkverkehr. Jeder der Minions hat ein spezifisches Netzwerkinterface mit begrenzter Bandbreite, daher k\u00f6nnen Aufgaben nicht ohne Ber\u00fccksichtigung des \u00fcbertragenden Datenvolumens im Netzwerk verteilt werden. <\/li>\n<li>Festplatten. Neben dem offensichtlichen Platz f\u00fcr die Daten der Aufgabe weisen wir auch den Festplattentyp zu: HDD oder SSD. Festplatten k\u00f6nnen eine bestimmte Anzahl von Anfragen pro Sekunde bedienen \u2013 IOPS. Daher weisen wir f\u00fcr Aufgaben, die mehr IOPS generieren als eine einzelne Festplatte bedienen kann, auch \"Spindeln\" zu \u2013 d. h. Speichereinheiten, die ausschlie\u00dflich f\u00fcr die Aufgabe reserviert werden m\u00fcssen.<\/li>\n<\/ul>\n<p><\/p>\n<p>F\u00fcr einen bestimmten Dienst, beispielsweise user-cache, k\u00f6nnen wir die ben\u00f6tigten Ressourcen auf folgende Weise festhalten: 400 CPU-Kerne, 2,5 TB Speicher, 50 Gbit\/s Netzwerkverkehr in beide Richtungen, 6 TB Speicher auf HDD, verteilt auf 100 Spindeln. Oder in einer f\u00fcr uns vertrauteren Form so:<\/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>Die Ressourcen des Dienstes user-cache verbrauchen nur einen Teil aller verf\u00fcgbaren Ressourcen in der Produktionsinfrastruktur. Daher m\u00f6chten wir sicherstellen, dass user-cache nicht mehr Ressourcen verbraucht, als ihm zugewiesen wurden, egal ob durch einen Operatorfehler oder nicht. Das hei\u00dft, wir m\u00fcssen die Ressourcen limitieren. Aber woran k\u00f6nnten wir das Kontingent festmachen?<\/p>\n<p><\/p>\n<p>Lassen Sie uns zu unserem stark vereinfachten Schema der Interaktion von Komponenten zur\u00fcckkehren und es mit mehr Details neu zeichnen \u2013 so: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/27e5bfbffadd3d4b9fdc6bf138d135ed.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Was ins Auge f\u00e4llt:<\/p>\n<p><\/p>\n<ul>\n<li>Web-Frontend und Musik verwenden isolierte Cluster desselben Anwendungsservers.<\/li>\n<li>Es lassen sich logische Schichten unterscheiden, zu denen diese Cluster geh\u00f6ren: Frontends, Caches, Speicher- und Datenverwaltungsschicht.<\/li>\n<li>Das Frontend ist heterogen, es besteht aus verschiedenen funktionalen Teilsystemen. <\/li>\n<li>Caches k\u00f6nnen ebenfalls nach dem Teilsystem verteilt werden, dessen Daten sie cachen.<\/li>\n<\/ul>\n<p><\/p>\n<p>Lassen Sie uns das Bild noch einmal neu zeichnen:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/905dacc0aca859e65bd33ef751a557cf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Oh! Wir sehen eine Hierarchie! Das bedeutet, dass wir Ressourcen in gr\u00f6\u00dferen Einheiten verteilen k\u00f6nnen: einen verantwortlichen Entwickler f\u00fcr einen Knoten dieser Hierarchie zuweisen, der zur funktionalen Teilsystem (wie \u201emusic\u201c im Bild) geh\u00f6rt, und zu demselben Hierarchielevel ein Kontingent binden. Eine solche Hierarchie erm\u00f6glicht es uns auch, die Dienste flexibler zur besseren Verwaltung zu organisieren. Zum Beispiel teilen wir alle Webdienste, da dies eine sehr gro\u00dfe Gruppierung von Servern ist, in mehrere kleinere Gruppen auf, die im Bild als group1, group2 angezeigt werden.<\/p>\n<p><\/p>\n<p>Indem wir \u00fcberfl\u00fcssige Linien entfernen, k\u00f6nnen wir jeden Knoten unseres Bildes in einer flacheren Form notieren: <strong>group1.web.front<\/strong>, <strong>api.music.front<\/strong>, <strong>user-cache.cache<\/strong>.<\/p>\n<p><\/p>\n<p>So kommen wir zum Konzept der \u201ehierarchischen Warteschlange\u201c. Diese hat einen Namen wie \u201egroup1.web.front\u201c. Ihr wird ein Kontingent f\u00fcr Ressourcen und Nutzerrechte zugewiesen. Eine Person aus DevOps erh\u00e4lt das Recht, einen Dienst in die Warteschlange zu senden, und dieser Mitarbeiter kann etwas in der Warteschlange starten, w\u00e4hrend jemand aus OpsDev \u2013 administrative Rechte erh\u00e4lt und jetzt die Warteschlange verwalten kann, Personen zuweisen, diesen Personen Rechte geben usw. Dienste, die in dieser Warteschlange gestartet werden, werden im Rahmen des Kontingents der Warteschlange ausgef\u00fchrt. Wenn das Rechenkontingent der Warteschlange nicht ausreicht, um alle Dienste gleichzeitig auszuf\u00fchren, werden sie nacheinander ausgef\u00fchrt und bilden somit die Warteschlange. <\/p>\n<p><\/p>\n<p>Lassen Sie uns die Dienste genauer betrachten. Ein Dienst hat einen vollst\u00e4ndigen Namen, der immer den Namen der Warteschlange enth\u00e4lt. Der Dienst des Web-Frontends wird dann den Namen haben <strong>ok-web.group1.web.front<\/strong>. Der Dienst des Anwendungsservers, auf den er zugreift, wird den Namen erhalten <strong>ok-app.group1.web.front<\/strong>. Jeder Dienst hat ein Manifest, in dem alle erforderlichen Informationen f\u00fcr die Bereitstellung auf bestimmten Maschinen angegeben sind: Wie viele Ressourcen diese Aufgabe ben\u00f6tigt, welche Konfiguration daf\u00fcr erforderlich ist, wie viele Repliken vorhanden sein m\u00fcssen, Eigenschaften zur Fehlerbehandlung dieses Dienstes. Nach der Bereitstellung des Dienstes auf den Maschinen erscheinen seine Instanzen. Diese werden ebenfalls eindeutig benannt - mit der Instanznummer und dem Namen des Dienstes: <strong>1.ok-web.group1.web.front, 2.ok-web.group1.web.front, \u2026<\/strong><\/p>\n<p><\/p>\n<p>Das ist sehr praktisch: Wenn wir nur den Namen des laufenden Containers betrachten, k\u00f6nnen wir sofort viel herausfinden.<\/p>\n<p><\/p>\n<p>Lassen Sie uns nun n\u00e4her kennenlernen, was diese Instanzen eigentlich tun: die Aufgaben.<\/p>\n<p><\/p>\n<h2 id=\"klassy-izolyacii-zadach\">Isolationsklassen von Aufgaben<\/h2>\n<p><\/p>\n<p>Alle Aufgaben in OK (und wahrscheinlich \u00fcberall) k\u00f6nnen in Gruppen eingeteilt werden:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Aufgaben mit kurzer Latenz - prod<\/strong>. F\u00fcr solche Aufgaben und Dienste ist die Antwortlatenz (latency) sehr wichtig, wie schnell jede Anfrage vom System verarbeitet wird. Beispiele f\u00fcr Aufgaben sind: Web-Frontends, Caches, Anwendungsserver, OLTP-Speicher usw.<\/li>\n<li><strong>Berechnung Aufgaben - batch<\/strong>. Hier ist die Geschwindigkeit der Verarbeitung jeder einzelnen Anfrage unwichtig. F\u00fcr sie ist wichtig, wie viele Berechnungen insgesamt in einem bestimmten (gro\u00dfen) Zeitraum diese Aufgabe durchf\u00fchrt (throughput). Dazu geh\u00f6ren alle Aufgaben in MapReduce, Hadoop, maschinelles Lernen, Statistik.<\/li>\n<li><strong>Hintergrundaufgaben - idle<\/strong>. F\u00fcr solche Aufgaben sind weder Latenz noch Durchsatz besonders wichtig. Dazu geh\u00f6ren verschiedene Tests, Migrationen, Neuberechnungen, Datenkonvertierungen von einem Format in ein anderes. Einerseits \u00e4hneln sie den Berechnungsaufgaben, andererseits ist es uns nicht so wichtig, wie schnell sie abgeschlossen werden. <\/li>\n<\/ul>\n<p><\/p>\n<p>Schauen wir uns an, wie solche Aufgaben Ressourcen, zum Beispiel die CPU, verbrauchen.<\/p>\n<p><\/p>\n<p><strong>Aufgaben mit kurzer Latenz.<\/strong> Ein solches Aufgabemuster wird folgenderma\u00dfen aussehen:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/1ed82c0df76325eb30056ad9af86e86e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Eine Anfrage vom Benutzer wird bearbeitet, die Aufgabe nutzt alle verf\u00fcgbaren CPU-Kerne, verarbeitet die Anfrage, gibt eine Antwort zur\u00fcck, wartet auf die n\u00e4chste Anfrage und bleibt stehen. Eine neue Anfrage kommt - wieder wird alles gew\u00e4hlt, was verf\u00fcgbar ist, berechnet und wir warten auf die n\u00e4chste.<\/p>\n<p><\/p>\n<p>Um eine minimale Latenz f\u00fcr eine solche Aufgabe zu garantieren, m\u00fcssen wir die maximal verbrauchten Ressourcen reservieren und die erforderliche Anzahl von Kernen auf dem Minion (der Maschine, die die Aufgabe ausf\u00fchrt) reservieren. Dann ergibt sich die Reservierungsformel f\u00fcr unsere Aufgabe wie folgt:<\/p>\n<p><\/p>\n<pre><code>alloc: cpu = 4 (max)<\/code><\/pre>\n<p><\/p>\n<p>Und wenn wir einen Minion-Server mit 16 Kernen haben, k\u00f6nnen darauf genau vier solcher Aufgaben platziert werden. Besonders hervorzuheben ist, dass der durchschnittliche CPU-Verbrauch dieser Aufgaben oft sehr niedrig ist \u2014 was offensichtlich ist, da ein erheblicher Teil der Zeit die Aufgabe auf eine Anfrage wartet und nichts tut.<\/p>\n<p><\/p>\n<p><strong>Berechnungsaufgaben.<\/strong> Ihr Muster wird etwas anders sein:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/35b37fa1d70a137287cafdbfe3bcfc2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Der durchschnittliche Ressourcenverbrauch der CPU bei solchen Aufgaben ist ziemlich hoch. Oft m\u00f6chten wir, dass die Berechnungsaufgabe innerhalb einer bestimmten Zeit ausgef\u00fchrt wird, daher m\u00fcssen wir die minimale Anzahl an Prozessoren reservieren, die sie ben\u00f6tigt, damit die gesamte Berechnung in einer akzeptablen Zeit abgeschlossen werden kann. Ihre Reservierungsformel wird so aussehen:<\/p>\n<p><\/p>\n<pre><code>alloc: cpu = [1,*)<\/code><\/pre>\n<p><\/p>\n<p><em>\u201eBitte platziere es auf dem Minion, wo es mindestens einen freien Kern gibt, und alles Weitere wird genutzt.\u201c<\/em><\/p>\n<p><\/p>\n<p>Hier ist die Effizienz der Nutzung bereits weitaus besser als bei Aufgaben mit kurzer Verz\u00f6gerung. Doch der Gewinn wird viel gr\u00f6\u00dfer, wenn man beide Aufgabentypen auf demselben Minion-Server kombiniert und dessen Ressourcen dynamisch verteilt. Wenn die Aufgabe mit kurzer Verz\u00f6gerung CPU ben\u00f6tigt, erh\u00e4lt sie sie sofort, und wenn die Ressourcen nicht mehr ben\u00f6tigt werden, werden sie der Berechnungsaufgabe zugeteilt, d. h. so:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/875ad8d3f6a01e4fd0a89d0931e986c1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Aber wie macht man das?<\/p>\n<p><\/p>\n<p>Zun\u00e4chst kl\u00e4ren wir die Sache mit prod und seinem alloc: cpu = 4. Wir m\u00fcssen vier Kerne reservieren. In Docker run gibt es zwei M\u00f6glichkeiten, dies zu tun: <\/p>\n<p><\/p>\n<ul>\n<li>Durch die Option <code>--cpuset=1-4<\/code>, d. h. der Aufgabe vier bestimmte Kerne auf dem Server zuweisen.<\/li>\n<li>Verwenden <code>--cpuquota=400_000 --cpuperiod=100_000<\/code>, eine CPU-Zeitquote zuweisen, d. h. angeben, dass die Aufgabe alle 100 ms Echtzeit nicht mehr als 400 ms CPU-Zeit verbrauchen darf. Es handelt sich um dieselben vier Kerne. <\/li>\n<\/ul>\n<p><\/p>\n<p>Aber welche dieser Methoden ist geeignet?<\/p>\n<p><\/p>\n<p>Das cpuset sieht ziemlich attraktiv aus. Die Aufgabe hat vier dedizierte Kerne, was bedeutet, dass die CPU-Caches h\u00f6chst effizient arbeiten werden. Das hat jedoch auch eine Kehrseite: Wir m\u00fcssten die Verteilung der Berechnungen auf die weniger ausgelasteten Kerne der Maschine selbst \u00fcbernehmen, anstatt dies durch das Betriebssystem erledigen zu lassen, was eine ziemlich anspruchsvolle Aufgabe ist, insbesondere wenn wir versuchen, Batch-Aufgaben auf einer solchen Maschine zu platzieren. Tests haben gezeigt, dass hier die Quoten-Option besser geeignet ist: So hat das Betriebssystem mehr Freiheit bei der Auswahl des Kerns f\u00fcr die Ausf\u00fchrung der Aufgabe im aktuellen Moment und die Prozessorzeit wird effizienter verteilt.<\/p>\n<p><\/p>\n<p>Lass uns anschauen, wie man in Docker eine Reservierung nach Mindestanzahl an Kernen erstellt. Eine Quote f\u00fcr Batch-Aufgaben ist bereits nicht mehr anwendbar, da das Festlegen eines Maximums nicht notwendig ist; es reicht aus, lediglich ein Minimum zu garantieren. Hier eignet sich die Option gut, <code>docker run --cpushares<\/code>.<\/p>\n<p><\/p>\n<p>Wir haben uns darauf geeinigt, dass wenn ein Batch ein Minimum von einem Kern garantiert, wir angeben, <code>--cpushares=1024<\/code>, und wenn mindestens zwei Kerne ben\u00f6tigt werden, dann geben wir an, <code>--cpushares=2048<\/code>. CPU-Anteile beeinflussen nicht die Verteilung der Prozessorzeit, solange diese ausreicht. Wenn also der Prod momentan nicht alle seine vier Kerne nutzt, gibt es nichts, was die Batch-Aufgaben einschr\u00e4nkt, und sie k\u00f6nnen die zus\u00e4tzliche Prozessorzeit verwenden. In einer Situation mit Prozessorengp\u00e4ssen, wenn der Prod alle vier Kerne verbraucht hat und auf die Quote st\u00f6\u00dft, wird die verbleibende Prozessorzeit proportional zu den cpushares verteilt, d.h. in einer Situation mit drei freien Kernen erh\u00e4lt die Aufgabe mit 1024 cpushares einen Kern, und die anderen beiden - die Aufgabe mit 2048 cpushares.<\/p>\n<p><\/p>\n<p>Aber die Verwendung von Quoten und Anteilen reicht nicht aus. Wir m\u00fcssen sicherstellen, dass eine Aufgabe mit kurzer Verz\u00f6gerung Priorit\u00e4t gegen\u00fcber einer Batch-Aufgabe bei der Verteilung der Prozessorzeit erh\u00e4lt. Ohne eine solche Priorisierung w\u00fcrde die Batch-Aufgabe die gesamte Prozessorzeit in Anspruch nehmen, wenn sie f\u00fcr den Prod erforderlich ist. Bei Docker run gibt es keine Optionen zur Priorisierung von Containern, aber CPU-Scheduler-Richtlinien in Linux kommen zur Hilfe. Mehr dazu kann man lesen, <noindex><a rel=\"nofollow\" href=\"http:\/\/man7.org\/linux\/man-pages\/man2\/sched_setscheduler.2.html\">hier<\/a><\/noindex>, und im Rahmen dieses Artikels werden wir sie kurz durchgehen:<\/p>\n<p><\/p>\n<ul>\n<li><strong>SCHED_OTHER<\/strong><br \/>\nStandardm\u00e4\u00dfig erhalten alle normalen Benutzerprozesse auf einer Linux-Maschine.<\/li>\n<li><strong>SCHED_BATCH<\/strong><br \/>\nF\u00fcr ressourcenintensive Prozesse vorgesehen. Wenn eine Aufgabe im Prozessor platziert wird, wird eine sogenannte Aktivierungsstrafe eingef\u00fchrt: Eine solche Aufgabe hat eine geringere Wahrscheinlichkeit, Prozessorressourcen zu erhalten, wenn dieser gerade von einer Aufgabe mit SCHED_OTHER verwendet wird.<\/li>\n<li><strong>SCHED_IDLE<\/strong><br \/>\nHintergrundprozess mit sehr niedriger Priorit\u00e4t, sogar niedriger als nice \u201319. Wir verwenden unsere Open-Source-Bibliothek <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/odnoklassniki\/one-nio\">one-nio<\/a><\/noindex>, um die erforderliche Politik beim Starten des Containers \u00fcber den Befehl festzulegen<\/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>Aber selbst wenn Sie nicht in Java programmieren, kann das Gleiche mit dem Befehl chrt getan werden:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">chrt -i 0 $pid<\/code><\/pre>\n<p><\/p>\n<p>Lassen Sie uns alle unsere Isolationsstufen in einer Tabelle zur Veranschaulichung zusammenfassen:<\/p>\n<p><\/p>\n<p>Isolationsklasse<br \/>\nBeispiel alloc<br \/>\nDocker Run Optionen<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>*Wenn Sie chrt aus dem Container heraus durchf\u00fchren, k\u00f6nnte die Berechtigung sys_nice erforderlich sein, da Docker diese Berechtigung standardm\u00e4\u00dfig beim Starten des Containers entzieht.<\/p>\n<p><\/p>\n<p>Aber Aufgaben ben\u00f6tigen nicht nur Prozessorressourcen, sondern auch Verkehr, der die Verz\u00f6gerung der Netzwerkaufgabe noch mehr beeinflusst als eine falsche Verteilung der Prozessorressourcen. Daher m\u00f6chten wir nat\u00fcrlich dasselbe Bild auch f\u00fcr den Verkehr erhalten. Das hei\u00dft, wenn eine prod-Aufgabe irgendwelche Pakete ins Netzwerk sendet, quotieren wir die maximale Geschwindigkeit (Formel <em>alloc: lan=[*,500mbps)<\/em> ), mit der die Prod das tun kann. F\u00fcr Batch garantieren wir jedoch nur eine minimale Bandbreite, beschr\u00e4nken jedoch nicht die maximale (Formel <em>alloc: lan=[10Mbps,*)<\/em> ) Dabei muss der Verkehr von Prod Vorrang vor Batch-Aufgaben haben.<br \/>\nHier hat Docker keine primitiven Elemente, die wir verwenden k\u00f6nnten. Aber uns kommt <noindex><a rel=\"nofollow\" href=\"http:\/\/lartc.org\/\">Linux Traffic Control<\/a><\/noindex>zur Hilfe. Wir konnten das gew\u00fcnschte Ergebnis mit der Disziplin <noindex><a rel=\"nofollow\" href=\"http:\/\/linux-ip.net\/articles\/hfsc.en\/\">Hierarchical Fair Service Curve<\/a><\/noindex>erreichen. Damit teilen wir zwei Klassen von Verkehr auf: hochpriorisierter Prod und niedrigpriorisierter Batch\/Idle. Das Ergebnis der Konfiguration f\u00fcr den ausgehenden Verkehr sieht so aus:<\/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 ein Betriebssystem auf Datacenter-Ebene 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 \u00abRoot qdisc\u00bb der Disziplin hsfc; 1:1 \u2014 Tochterklasse hsfc mit einem gemeinsamen Bandbreitenlimit von 8 Gbit\/s, unter das alle Tochterklassen aller Container fallen; 1:2 \u2014 Tochterklasse hsfc, die f\u00fcr alle Batch- und Idle-Aufgaben gemeinsam ist, mit einem \u201edynamischen\u201c Limit, \u00fcber das weiter unten mehr zu lesen ist. Die \u00fcbrigen Tochterklassen hsfc sind spezielle Klassen f\u00fcr die derzeit aktiven Prod-Container mit Limits, die ihren Manifesten entsprechen \u2014 450 und 400 Mbit\/s. Jede hsfc-Klasse hat eine qdisc-Warteschlange vom Typ fq oder fq_codel zugewiesen, abh\u00e4ngig von der Version des Linux-Kernels, um Paketverluste bei Traffic-Spitzen zu vermeiden. <\/p>\n<p><\/p>\n<p>In der Regel dienen die Disziplinen tc nur der Priorisierung des ausgehenden Verkehrs. Aber wir m\u00f6chten auch den eingehenden Verkehr priorisieren \u2013 denn irgendeine batch-Aufgabe kann m\u00fchelos den gesamten eingehenden Kanal belegen, indem sie beispielsweise ein gro\u00dfes Paket eingehender Daten f\u00fcr Map&amp;Reduce erh\u00e4lt. Daf\u00fcr verwenden wir das Modul <noindex><a rel=\"nofollow\" href=\"https:\/\/serverfault.com\/questions\/350023\/tc-ingress-policing-and-ifb-mirroring\">ifb<\/a><\/noindex>, das ein virtuelles Interface ifbX f\u00fcr jede Netzwerkschnittstelle erstellt und den eingehenden Verkehr von der Schnittstelle zum ausgehenden auf ifbX umleitet. Anschlie\u00dfend arbeiten f\u00fcr ifbX dieselben Disziplinen zur Kontrolle des ausgehenden Verkehrs, f\u00fcr den die hsfc-Konfiguration sehr \u00e4hnlich sein wird:<\/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 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/967da9c0637cc70ba195af781db18adf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p><\/p>\n<p>In unseren Experimenten haben wir festgestellt, dass hsfc die besten Ergebnisse liefert, wenn die Klasse 1:2 des nicht priorisierten batch\/idle Verkehrs auf den Minion-Maschinen auf nicht mehr als einen bestimmten freien Durchsatz begrenzt wird. Andernfalls beeinflusst der nicht priorisierte Verkehr die Latenz der prod-Aufgaben zu stark. Der aktuelle Wert des freien Durchsatzes wird von miniond jede Sekunde bestimmt, indem der durchschnittliche Verkehr von allen prod-Aufgaben dieses Minions gemessen <img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/9d6f38110d3b1693afe222b01430b9bb.jpg\" style=\"display:block;margin: 0 auto;\" \/> und von der Bandbreite der Netzwerkschnittstelle <img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/d5608ec4c58e44b8571ab0b1d0cc7701.jpg\" style=\"display:block;margin: 0 auto;\" \/> mit einem kleinen Puffer abgezogen wird, d. h.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/fb01347c2224bd5bbd82169861eeb7e4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Die Bandbreiten werden unabh\u00e4ngig f\u00fcr den eingehenden und ausgehenden Verkehr bestimmt. Und gem\u00e4\u00df den neuen Werten konfiguriert miniond das Limit der nicht priorisierten Klasse 1:2 neu.<\/p>\n<p><\/p>\n<p>So haben wir alle drei Isolationsklassen implementiert: prod, batch und idle. Diese Klassen haben einen signifikanten Einfluss auf die Ausf\u00fchrungsmerkmale der Aufgaben. Daher haben wir beschlossen, dieses Merkmal an die Spitze der Hierarchie zu setzen, damit bei einem Blick auf den Namen der hierarchischen Warteschlange sofort klar ist, womit wir es zu tun haben: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/34dc89c461db711b19a0f4eccc50efce.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>All unsere Bekannten <strong>web<\/strong> und <strong>music<\/strong> Fronten werden dann in der Hierarchie unter prod platziert. Zum Beispiel lassen Sie uns den Dienst <strong>Music Catalog<\/strong>, der regelm\u00e4\u00dfig einen Katalog von Tracks aus der Sammlung von hochgeladenen mp3-Dateien in \"Odnoklassniki\" erstellt. Ein Beispiel f\u00fcr einen Idle-Service k\u00f6nnte sein <strong>music transformer<\/strong>, der die Lautst\u00e4rke der Musik normalisiert.<\/p>\n<p><\/p>\n<p>Nachdem wir die \u00fcberfl\u00fcssigen Linien wieder entfernt haben, k\u00f6nnen wir die Namen unserer Dienste flacher gestalten, indem wir die Klassifizierung der Aufgabe am Ende des vollst\u00e4ndigen Dienstnamens anf\u00fcgen: <strong>web.front.prod<\/strong>, <strong>catalog.music.batch<\/strong>, <strong>transformer.music.idle<\/strong>.<\/p>\n<p><\/p>\n<p>Und jetzt, wenn wir uns den Servicenamen ansehen, verstehen wir nicht nur, welche Funktion er erf\u00fcllt, sondern auch seine Klassifizierung, was bedeutet, dass wir seine Kritikalit\u00e4t usw. erkennen.<\/p>\n<p><\/p>\n<p>Alles ist wunderbar, aber es gibt eine bittere Wahrheit. Es ist unm\u00f6glich, Aufgaben, die auf einer Maschine laufen, vollst\u00e4ndig zu isolieren.<\/p>\n<p><\/p>\n<p>Was wir erreicht haben: Wenn die Batch-Aufgabe intensiv <strong>nur<\/strong> CPU-Ressourcen verbraucht, dann erledigt der integrierte CPU-Planer in Linux seine Aufgabe sehr gut, und es gibt praktisch keinen Einfluss auf die Prod-Aufgabe. Wenn diese Batch-Aufgabe jedoch aktiv mit dem Speicher arbeitet, zeigt sich der gegenseitige Einfluss bereits. Das geschieht, weil die Prozessor-Caches der Prod-Aufgabe \"ausgesogen\" werden \u2014 letztlich nehmen die Cache-Fehler zu, und der Prozessor verarbeitet die Prod-Aufgabe langsamer. Solch eine Batch-Aufgabe kann die Latenz unseres typischen Prod-Containers um 10 % erh\u00f6hen.<\/p>\n<p><\/p>\n<p>Die Isolierung des Verkehrs ist noch schwieriger, da moderne Netzwerkkarten \u00fcber eine interne Warteschlange f\u00fcr Pakete verf\u00fcgen. Wenn ein Paket von der Batch-Aufgabe zuerst eingereicht wird, wird es auch zuerst \u00fcber das Kabel \u00fcbertragen, und da kann man nichts machen.<\/p>\n<p><\/p>\n<p>Au\u00dferdem ist es uns bisher nur gelungen, die Aufgabe der Priorisierung von TCP-Verkehr zu l\u00f6sen: F\u00fcr UDP funktioniert der Ansatz mit HSFC nicht. Und selbst im Fall von TCP-Verkehr, wenn die Batch-Aufgabe viel Verkehr generiert, erh\u00f6ht sich auch hier die Latenz der Prod-Aufgabe um etwa 10 %.<\/p>\n<p><\/p>\n<h2 id=\"otkazoustoychivost\">Fehlertoleranz<\/h2>\n<p><\/p>\n<p>Eines der Ziele bei der Entwicklung von One-Cloud war die Verbesserung der Fehlertoleranz von Odnoklassniki. Daher m\u00f6chte ich im Folgenden m\u00f6gliche Ausfallszenarien und Notf\u00e4lle genauer betrachten. Lassen Sie uns mit einem einfachen Szenario beginnen \u2013 dem Ausfall eines Containers. <\/p>\n<p><\/p>\n<p>Ein Container kann auf verschiedene Weise ausfallen. Dies kann ein Experiment, ein Fehler oder ein Problem im Manifest sein, wodurch die Prod-Aufgabe mehr Ressourcen verbraucht als im Manifest angegeben. Wir hatten einen Fall, in dem ein Entwickler einen komplexen Algorithmus implementierte, ihn mehrmals \u00fcberarbeitete, sich dabei selbst verwirrte und schlie\u00dflich so kompliziert wurde, dass die Aufgabe ziemlich untrivial in eine Endlosschleife geriet. Da die Prod-Aufgabe jedoch eine h\u00f6here Priorit\u00e4t hat als alle anderen auf denselben Minions, begann sie, alle verf\u00fcgbaren CPU-Ressourcen zu verbrauchen. In dieser Situation half die Isolation, genauer gesagt, das Kontingent f\u00fcr die CPU-Zeit. Wenn einer Aufgabe ein Kontingent zugewiesen ist, verbraucht sie nicht mehr. Daher bemerkten die Batch- und anderen Prod-Aufgaben, die auf demselben Rechner liefen, nichts. <\/p>\n<p><\/p>\n<p>Das zweite m\u00f6gliche Problem ist der Absturz des Containers. Hier helfen uns die Neustart-Richtlinien, die jeder kennt; Docker kommt damit sehr gut zurecht. Praktisch alle Prod-Aufgaben haben die Neustart-Richtlinie \"always\". Manchmal verwenden wir \"on_failure\" f\u00fcr Batch-Aufgaben oder zur Fehlerbehebung von Prod-Containern.<\/p>\n<p><\/p>\n<p>Was kann man tun, wenn ein ganzer Minion nicht verf\u00fcgbar ist?<\/p>\n<p><\/p>\n<p>Offensichtlich kann man den Container auf einem anderen Rechner starten. Das Interessanteste dabei ist, was mit der IP-Adresse (den IP-Adressen), die dem Container zugewiesen sind, passiert. <\/p>\n<p><\/p>\n<p>Wir k\u00f6nnen Containern die gleichen IP-Adressen zuweisen wie den Maschinen-Minions, auf denen diese Container gestartet werden. Dann \u00e4ndert sich die IP-Adresse des Containers, wenn er auf einem anderen Rechner gestartet wird, und alle Clients m\u00fcssen verstehen, dass der Container umgezogen ist; sie m\u00fcssen nun die andere Adresse ansteuern, was einen separaten Service f\u00fcr die Service Discovery erfordert. <\/p>\n<p><\/p>\n<p>Service Discovery ist praktisch. Auf dem Markt gibt es viele L\u00f6sungen mit unterschiedlichem Grad an Ausfallsicherheit zur Organisation eines Service-Registers. Oft wird in solchen L\u00f6sungen auch die Logik eines Lastenausgleichers implementiert, sowie die Speicherung zus\u00e4tzlicher Konfigurationen in Form eines KV-Speichers usw.<br \/>\nWir m\u00f6chten jedoch auf die Notwendigkeit verzichten, ein separates Register einzuf\u00fchren, da das die Einf\u00fchrung eines kritischen Systems bedeuten w\u00fcrde, das von allen Diensten in der Produktion genutzt wird. Das bedeutet, dass es einen potenziellen Ausfallpunkt darstellt, und es m\u00fcssen sehr ausfallsichere L\u00f6sungen gew\u00e4hlt oder entwickelt werden, was offensichtlich sehr kompliziert, zeitaufwendig und teuer ist. <\/p>\n<p><\/p>\n<p>Und ein weiterer gro\u00dfer Nachteil: Damit unsere alte Infrastruktur mit der neuen funktioniert, m\u00fcsste man alle Aufgaben vollst\u00e4ndig umschreiben, um ein Service Discovery-System zu verwenden. Es gibt SEHR viel Arbeit, und manchmal ist es bis zur Unm\u00f6glichkeit, wenn es um niedrigstufige Ger\u00e4te geht, die auf Betriebssystemkern- oder Hardware-Ebene arbeiten. Die Implementierung dieser Funktionalit\u00e4t mithilfe etablierter L\u00f6sungsans\u00e4tze, wie zum Beispiel <noindex><a rel=\"nofollow\" href=\"https:\/\/linkerd.io\">side-car<\/a><\/noindex> , w\u00fcrde an vielen Stellen eine zus\u00e4tzliche Last bedeuten, an anderen Stellen \u2014 eine Komplexit\u00e4t der Wartung und zus\u00e4tzliche Ausfallszenarien. Da wir die Komplexit\u00e4t nicht erh\u00f6hen wollten, entschieden wir uns, die Nutzung von Service Discovery optional zu machen. <\/p>\n<p><\/p>\n<p>In one-cloud folgt die IP der Instanz, d.h. jede Aufgabeninstanz hat ihre eigene IP-Adresse. Diese Adresse ist \"statisch\": sie wird jeder Instanz zum Zeitpunkt der ersten Bereitstellung des Dienstes in der Cloud zugewiesen. Wenn der Dienst w\u00e4hrend seiner Lebensdauer eine unterschiedliche Anzahl von Instanzen hatte, wird im Ergebnis so viele IP-Adressen zugewiesen, wie es maximal Instanzen gab.<\/p>\n<p><\/p>\n<p>Diese Adressen \u00e4ndern sich anschlie\u00dfend nicht: Sie werden einmal zugewiesen und existieren w\u00e4hrend der gesamten Lebensdauer des Dienstes in der Produktion weiter. Die IP-Adressen folgen den Containern im Netzwerk. Wenn ein Container auf einen anderen Knoten verschoben wird, wird die Adresse ebenfalls mit ihm \u00fcbertragen. <\/p>\n<p><\/p>\n<p>So kommt es selten vor, dass der Dienstnamen mit seiner Liste von IP-Adressen abgeglichen wird. Wenn man sich noch einmal die Instanznamen des Dienstes betrachtet, die wir zu Beginn des Artikels erw\u00e4hnt haben (<strong>1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, \u2026<\/strong>), dann werden wir feststellen, dass sie FQDN \u00e4hneln, die im DNS verwendet werden. Das ist auch der Fall, denn zur Anzeige der Instanznamen von Diensten in ihren IP-Adressen verwenden wir das DNS-Protokoll. Dabei gibt dieses DNS alle reservierten IP-Adressen aller Container zur\u00fcck \u2013 sowohl der laufenden als auch der gestoppten (angenommen, es werden drei Replikate verwendet, und uns stehen f\u00fcnf Adressen zur Verf\u00fcgung \u2013 alle f\u00fcnf werden zur\u00fcckgegeben). Die Clients, die diese Informationen erhalten, versuchen, eine Verbindung zu allen f\u00fcnf Replikaten herzustellen \u2013 und bestimmen auf diese Weise, welche davon aktiv sind. Diese Methode zur Feststellung der Verf\u00fcgbarkeit ist deutlich zuverl\u00e4ssiger, da hier weder DNS noch Service Discovery beteiligt sind, was bedeutet, dass es keine schwer l\u00f6sbaren Probleme hinsichtlich der Aktualit\u00e4t der Informationen und der Fehlertoleranz dieser Systeme gibt. Dar\u00fcber hinaus k\u00f6nnen wir in kritischen Diensten, von denen der gesamte Portalbetrieb abh\u00e4ngt, auf DNS ganz verzichten und die IP-Adressen einfach in die Konfiguration eintragen.<\/p>\n<p><\/p>\n<p>Die Umsetzung eines solchen IP-Transfers f\u00fcr Container kann nicht trivial sein \u2013 und wir werden an einem n\u00e4chsten Beispiel darauf eingehen, wie das funktioniert:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/faf99c2609a57daa1bdc193cb0f4cb31.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Angenommen, der one-cloud Master befiehlt dem Minion M1, zu starten <strong>1.ok-web.group1.web.front.prod<\/strong> mit der Adresse 1.1.1.1. Auf dem Minion l\u00e4uft <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Bird_Internet_routing_daemon\">BIRD<\/a><\/noindex>, das diese Adresse an spezielle Server ank\u00fcndigt <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Route_reflector\">route reflector<\/a><\/noindex>. Letztere haben eine BGP-Session mit dem Netzwerkger\u00e4t, in das die Route der Adresse 1.1.1.1 auf M1 \u00fcbertragen wird. M1 routet die Pakete mit den Mitteln von Linux ins Containerinnere. Es gibt drei route reflectoren, da dies ein sehr kritischer Teil der one-cloud-Infrastruktur ist \u2013 ohne sie wird das Netzwerk in der one-cloud nicht funktionieren. Wir platzieren sie in verschiedenen Racks, wenn m\u00f6glich in verschiedenen R\u00e4umen des Rechenzentrums, um die Wahrscheinlichkeit eines gleichzeitigen Ausfalls aller drei zu verringern.<\/p>\n<p><\/p>\n<p>Nehmen wir nun an, die Verbindung zwischen dem one-cloud Master und dem Minion M1 ist abgebrochen. Der one-cloud Master wird nun davon ausgehen, dass M1 vollst\u00e4ndig ausgefallen ist. Das hei\u00dft, er wird dem Minion M2 den Befehl geben, zu starten <strong>web.group1.web.front.prod<\/strong> Mit der gleichen Adresse 1.1.1.1. Jetzt haben wir zwei Konflikt-Routen im Netz f\u00fcr 1.1.1.1: auf M1 und auf M2. Um solche Konflikte zu l\u00f6sen, verwenden wir den Multi Exit Discriminator, der in der BGP-Ank\u00fcndigung angegeben wird. Dies ist eine Zahl, die das Gewicht der angek\u00fcndigten Route anzeigt. Die Route mit dem niedrigeren MED-Wert wird aus den Konflikten ausgew\u00e4hlt. Der Master von one-cloud unterst\u00fctzt MED als integralen Bestandteil der IP-Adressen von Containern. Zuerst wird die Adresse mit einem relativ hohen MED = 1.000.000 ausgegeben. Wenn es jedoch zu einem Notfall-Transfer des Containers kommt, verringert der Master das MED, und M2 erh\u00e4lt den Befehl, die Adresse 1.1.1.1 mit MED = 999.999 anzuk\u00fcndigen. Der Instance, die auf M1 l\u00e4uft, bleibt dabei offline, und ihr weiteres Schicksal interessiert uns kaum, bis die Verbindung zum Master wiederhergestellt ist, wenn sie dann wie ein alter Duplicat gestoppt wird.<\/p>\n<p><\/p>\n<h2 id=\"avarii\">Notf\u00e4lle<\/h2>\n<p><\/p>\n<p>Alle Systeme zur Verwaltung von Rechenzentren bew\u00e4ltigen kleinere Ausf\u00e4lle in der Regel akzeptabel. Der Ausfall eines Containers ist praktisch \u00fcberall die Norm.<\/p>\n<p><\/p>\n<p>Schauen wir uns an, wie wir mit einem Notfall umgehen, zum Beispiel mit einem Stromausfall in einem oder mehreren R\u00e4umen des Rechenzentrums.<\/p>\n<p><\/p>\n<p>Was bedeutet ein Notfall f\u00fcr das System zur Verwaltung des Rechenzentrums? Zuerst einmal ist es ein massiver gleichzeitiger Ausfall vieler Maschinen, und das Management-System muss gleichzeitig viele Container migrieren. Aber bei einem sehr gro\u00dffl\u00e4chigen Notfall kann es vorkommen, dass nicht alle Aufgaben auf anderen Minions umverteilt werden k\u00f6nnen, da die Ressourcen-Kapazit\u00e4t des Rechenzentrums unter 100 % Auslastung f\u00e4llt. <\/p>\n<p><\/p>\n<p>Oft gehen Notf\u00e4lle mit einem Ausfall auch der Management-Ebene einher. Dies kann durch einen Ausfall der Hardware verursacht werden, h\u00e4ufiger jedoch, weil Notf\u00e4lle nicht getestet werden und die Management-Ebene selbst unter der erh\u00f6hten Last zusammenbricht. <\/p>\n<p><\/p>\n<p>Was kann man in all dem tun?<\/p>\n<p><\/p>\n<p>Massive Migrationen bedeuten, dass in der Infrastruktur eine gro\u00dfe Anzahl von Aktionen, Migrationen und Platzierungen stattfindet. Jede Migration kann einige Zeit in Anspruch nehmen, die notwendig ist, um Container-Images zu den Minions zu liefern und zu entpacken, Container zu starten und zu initialisieren usw. Daher ist es w\u00fcnschenswert, dass wichtigere Aufgaben vor weniger wichtigen gestartet werden.<\/p>\n<p><\/p>\n<p>Lassen Sie uns erneut die uns vertraute Hierarchie der Dienste betrachten und versuchen zu entscheiden, welche Aufgaben wir zuerst starten m\u00f6chten.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/2e827271adb8d3ff3d385e53553aaacf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Nat\u00fcrlich sind dies die Prozesse, die direkt an der Bearbeitung von Benutzeranfragen beteiligt sind, d. h. prod. Wir geben dies an mit <strong>Priorit\u00e4t der Platzierung<\/strong> \u2014 einer Zahl, die einer Warteschlange zugewiesen werden kann. Wenn eine Warteschlange eine h\u00f6here Priorit\u00e4t hat, werden ihre Dienste zuerst platziert.<\/p>\n<p><\/p>\n<p>In prod weisen wir h\u00f6here Priorit\u00e4ten zu, 0; in batch etwas niedrigere, 100; in idle noch niedrigere, 200. Die Priorit\u00e4ten werden hierarchisch angewendet. Alle Aufgaben auf einer tieferen Hierarchieebene haben die entsprechende Priorit\u00e4t. Wenn wir wollen, dass innerhalb von prod die Caches vor den Frontends gestartet werden, weisen wir den Caches eine Priorit\u00e4t von 0 und den Frontunterwarteschlangen eine Priorit\u00e4t von 1 zu. Wenn wir beispielsweise m\u00f6chten, dass das Hauptportal aus den Frontends zuerst gestartet wird und der Musik-Frontend danach, k\u00f6nnen wir letzterem eine niedrigere Priorit\u00e4t zuweisen \u2014 10.<\/p>\n<p><\/p>\n<p>Ein weiteres Problem ist der Mangel an Ressourcen. Wir haben also eine gro\u00dfe Anzahl von Ger\u00e4ten verloren, ganze S\u00e4le im Rechenzentrum, und wir haben so viele Dienste gestartet, dass es jetzt f\u00fcr alle nicht genug Ressourcen gibt. Wir m\u00fcssen entscheiden, welche Aufgaben wir opfern, damit die wichtigsten kritischen Dienste weiterhin funktionieren. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"One-cloud \u2014 ein Betriebssystem auf Datacenter-Ebene in Odnoklassniki\" src=\"\/wp-content\/uploads\/2020\/06\/1b1ad3da16df6677dd0ba4b038cdd7d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Im Gegensatz zur Priorit\u00e4t der Platzierung k\u00f6nnen wir nicht einfach alle batch-Aufgaben opfern, einige davon sind wichtig f\u00fcr den Betrieb des Portals. Daher haben wir separat <strong>Priorit\u00e4t der Verdr\u00e4ngung<\/strong> aufgaben \u0432\u044b\u0434\u0435\u043b espec\u00edal. Bei der Platzierung kann eine Aufgabe mit h\u00f6herer Priorit\u00e4t eine Aufgabe mit niedrigerer Priorit\u00e4t verdr\u00e4ngen, d. h. anhalten, wenn es keine freien Minions mehr gibt. In diesem Fall wird die Aufgabe mit niedrigerer Priorit\u00e4t wahrscheinlich unplatziert bleiben, d. h. es gibt keinen geeigneten Minion mit ausreichend freien Ressourcen mehr.<\/p>\n<p><\/p>\n<p>In unserer Hierarchie ist es sehr einfach, eine solche Verdr\u00e4ngungspriorit\u00e4t anzugeben, dass prod- und batch-Aufgaben idle-Aufgaben verdr\u00e4ngen oder anhalten, aber sich gegenseitig nicht, indem wir f\u00fcr idle eine Priorit\u00e4t von 200 angeben. Genau wie im Fall der Platzierungspriorit\u00e4t k\u00f6nnen wir unsere Hierarchie nutzen, um komplexere Regeln zu beschreiben. Zum Beispiel geben wir an, dass wir auf die Musikfunktion verzichten, wenn uns die Ressourcen f\u00fcr das Haupt-Webportal fehlen, indem wir f\u00fcr die entsprechenden Knoten eine niedrigere Priorit\u00e4t festlegen: 10.<\/p>\n<p><\/p>\n<h2 id=\"avarii-dc-celikom\">Vorf\u00e4lle im Rechenzentrum<\/h2>\n<p><\/p>\n<p>Warum kann das gesamte Rechenzentrum ausfallen? Naturkatastrophen. Es gab einen interessanten Beitrag dar\u00fcber, wie <noindex><a rel=\"nofollow\" href=\"https:\/\/habrahabr.ru\/company\/dataline\/blog\/333578\/\">ein Hurrikan die Arbeit des Rechenzentrums beeinflusst hat.<\/a><\/noindex>. Die Elemente kann man als Obdachlose betrachten, die einmal im Kanal die Optik abgebrannt haben, und das Rechenzentrum komplett den Kontakt zu den anderen Standorten verloren hat. Ein Grund f\u00fcr den Ausfall kann auch der menschliche Faktor sein: Ein Operator k\u00f6nnte einen Befehl erteilen, der dazu f\u00fchrt, dass das gesamte Rechenzentrum ausf\u00e4llt. Dies kann durch einen gro\u00dfen Bug geschehen. Insgesamt fallen Rechenzentren \u2014 das ist keine Seltenheit. Bei uns passiert das alle paar Monate einmal. <\/p>\n<p><\/p>\n<p>Und das machen wir, damit niemand #\u043e\u043a\u0436\u0438\u0432\u0438 auf Twitter postet.<\/p>\n<p><\/p>\n<p>Die erste Strategie ist die Isolation. Jede Instanz von one-cloud ist isoliert und kann Maschinen nur eines Rechenzentrums verwalten. Das hei\u00dft, der Verlust der Cloud aufgrund von Bugs oder falschen Befehlen des Operators bedeutet den Verlust nur eines Rechenzentrums. Darauf sind wir vorbereitet: Es gibt eine Reservierungspolitik, bei der die Replikate der Anwendungen und Daten in allen Rechenzentren platziert werden. Wir nutzen ausfallsichere Datenbanken und testen regelm\u00e4\u00dfig Ausf\u00e4lle.<br \/>\nDa wir heute \u00fcber vier Rechenzentren verf\u00fcgen, gibt es auch vier separate, vollst\u00e4ndig isolierte Instanzen von one-cloud.<\/p>\n<p><\/p>\n<p>Dieser Ansatz sch\u00fctzt nicht nur vor physischen Ausf\u00e4llen, sondern kann auch vor Fehlern des Operators sch\u00fctzen.<\/p>\n<p><\/p>\n<p>Was kann man noch mit dem menschlichen Faktor machen? Wenn ein Operator der Cloud einen seltsamen oder potenziell gef\u00e4hrlichen Befehl erteilt, k\u00f6nnte pl\u00f6tzlich verlangt werden, eine kleine Aufgabe zu l\u00f6sen, um zu \u00fcberpr\u00fcfen, wie gut er \u00fcberlegt hat. Zum Beispiel, wenn es sich um einen massiven Stopp vieler Replikate handelt oder einfach um einen seltsamen Befehl \u2014 die Anzahl der Replikate zu reduzieren oder den Namen des Images zu \u00e4ndern und nicht nur die Versionsnummer im neuen 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 ein Betriebssystem auf Datacenter-Ebene 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\">Ergebnisse<\/h2>\n<p><\/p>\n<p>Einzigartige Merkmale von one-cloud: <\/p>\n<p><\/p>\n<ul>\n<li><strong>Eine hierarchische und \u00fcbersichtliche Benennungsskema f\u00fcr Dienste und Container,<\/strong>, die es erm\u00f6glicht, sehr schnell zu erkennen, um welche Aufgabe es sich handelt, zu welchem Zweck sie dient, wie sie funktioniert und wer daf\u00fcr verantwortlich ist. <\/li>\n<li>Wir verwenden unsere <strong>Techniken zur Kombination von Prod- und Batch-<\/strong>Aufgaben auf Minions, um die Effizienz der Maschinen gemeinsam zu nutzen, zu erh\u00f6hen. Statt cpuset verwenden wir CPU-Quoten, Shares, CPU-Planerpolitiken und Linux QoS.<\/li>\n<li>Es gelang uns nicht, die Container, die auf einer Maschine arbeiten, vollst\u00e4ndig zu isolieren, aber ihr gegenseitiger Einfluss bleibt auf 20 % beschr\u00e4nkt.<\/li>\n<li>Die Organisation der Dienste in eine Hierarchie hilft bei der automatischen Beseitigung von Notf\u00e4llen mithilfe von <strong>Platzierungs- und Verdr\u00e4ngungspriorit\u00e4ten.<\/strong>.<\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"chavo\">FAQ<\/h2>\n<p><\/p>\n<p>Warum haben wir keine fertige L\u00f6sung \u00fcbernommen?<\/p>\n<p><\/p>\n<ul>\n<li>Verschiedene Klassen von Aufgabenisolierungen erfordern unterschiedliche Logik beim Deployment auf Minions. W\u00e4hrend Prod-Aufgaben einfach durch Ressourcensicherung bereitgestellt werden k\u00f6nnen, m\u00fcssen Batch- und Idle-Aufgaben unter Ber\u00fccksichtigung der tats\u00e4chlichen Ressourcenauslastung auf den Maschinen-Minions platziert werden. <\/li>\n<li>Die Notwendigkeit, solche Ressourcen, die von Aufgaben verbraucht werden, zu ber\u00fccksichtigen, wie: \n<ul>\n<li>Netzwerkbandbreite;<\/li>\n<li>Arten und \u201eSpindeln\u201c von Festplatten.<\/li>\n<\/ul>\n<\/li>\n<li>Die Notwendigkeit, Priorit\u00e4ten der Dienste bei der Behebung von St\u00f6rungen festzulegen, sowie die Rechte und Quoten von Teams auf Ressourcen, was durch hierarchische Warteschlangen in one-cloud gel\u00f6st wird.<\/li>\n<li>Die Notwendigkeit, menschliche Bezeichnungen f\u00fcr Container zu haben, um die Reaktionszeiten auf St\u00f6rungen und Vorf\u00e4lle zu verk\u00fcrzen.<\/li>\n<li>Die Unm\u00f6glichkeit, Service Discovery gleichzeitig fl\u00e4chendeckend zu implementieren; die Notwendigkeit, lange Zeit mit Aufgaben zu koexistieren, die auf physischen Hosts platziert sind \u2013 dies wird durch \u201estatische\u201c IP-Adressen, die Container folgen, gel\u00f6st, und infolgedessen die Notwendigkeit einer einzigartigen Integration in gro\u00dfe Netzwerkstrukturen.<\/li>\n<\/ul>\n<p><\/p>\n<p>All diese Funktionen w\u00fcrden erhebliche Umgestaltungen bestehender L\u00f6sungen erfordern, und nach einer Absch\u00e4tzung des Arbeitsaufwands haben wir festgestellt, dass wir unsere eigene L\u00f6sung mit ungef\u00e4hr dem gleichen Aufwand entwickeln k\u00f6nnen. Doch unsere L\u00f6sung wird erheblich einfacher zu betreiben und weiterzuentwickeln sein \u2013 sie enth\u00e4lt keine unn\u00f6tigen Abstraktionen, die unn\u00f6tige Funktionalit\u00e4ten unterst\u00fctzen. <\/p>\n<p><\/p>\n<p>An diejenigen, die die letzten Zeilen lesen \u2013 danke f\u00fcr Ihre Geduld und Aufmerksamkeit!<\/p>\n<p>Quelle: <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.1.1 - 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\/de\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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\/de\/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 \u2013 das Betriebssystem auf Rechenzentrumsniveau bei Odnoklassniki | ProHoster","description":"Aloha, Leute!","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/one-cloud-os-urovnya-data-czentra-v-odnoklassnikah","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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\/de\/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\/de\/wp-json\/wp\/v2\/posts\/84114","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=84114"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/84114\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/84115"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=84114"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=84114"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=84114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}