Was wissen wir über Microservices?

Hallo! Mein Name ist Vadim Madison, ich leite die Entwicklung der Avito System Platform. Es wurde mehr als einmal gesagt, dass wir im Unternehmen von einer monolithischen Architektur zu einer Microservices-Architektur übergehen. Es ist an der Zeit, Ihnen mitzuteilen, wie wir unsere Infrastruktur umgestaltet haben, um das Beste aus Microservices herauszuholen und zu verhindern, dass wir uns darin verlieren. Wie uns PaaS hier hilft, wie wir das Deployment vereinfacht und die Erstellung eines Microservices auf einen Klick reduziert haben – lesen Sie weiter. Nicht alles, worüber ich unten schreibe, ist vollständig in Avito implementiert, ein Teil davon hängt davon ab, wie wir unsere Plattform entwickeln.

(Und am Ende dieses Artikels werde ich über die Möglichkeit sprechen, an einem dreitägigen Seminar des Microservice-Architekturexperten Chris Richardson teilzunehmen.)

Was wissen wir über Microservices?

Wie wir zu Microservices kamen

Avito ist eine der größten Kleinanzeigenseiten der Welt; täglich werden dort mehr als 15 Millionen neue Anzeigen veröffentlicht. Unser Backend akzeptiert mehr als 20 Anfragen pro Sekunde. Derzeit verfügen wir über mehrere hundert Microservices.

Wir bauen seit mehreren Jahren eine Microservice-Architektur auf. Wie genau – unsere Kollegen im Detail erzählt in unserer Sektion beim RIT++ 2017. Beim CodeFest 2017 (siehe. Video), erklärten Sergey Orlov und Mikhail Prokopchuk ausführlich, warum wir den Übergang zu Microservices brauchten und welche Rolle Kubernetes dabei spielte. Nun tun wir alles, um die mit einer solchen Architektur verbundenen Skalierungskosten zu minimieren.

Zunächst haben wir kein Ökosystem geschaffen, das uns umfassend bei der Entwicklung und Einführung von Microservices unterstützen würde. Sie sammelten einfach sinnvolle Open-Source-Lösungen, brachten sie zu Hause auf den Markt und luden den Entwickler ein, sich damit auseinanderzusetzen. Infolgedessen besuchte er ein Dutzend Orte (Dashboards, interne Dienste), woraufhin sein Wunsch stärker wurde, Code auf die alte Art und Weise in einen Monolithen zu schneiden. Die grüne Farbe in den Diagrammen unten zeigt an, was der Entwickler auf die eine oder andere Weise mit seinen eigenen Händen macht, und die gelbe Farbe zeigt Automatisierung an.

Was wissen wir über Microservices?

Jetzt wird im PaaS-CLI-Dienstprogramm mit einem Befehl ein neuer Dienst erstellt und mit zwei weiteren eine neue Datenbank hinzugefügt und auf Stage bereitgestellt.

Was wissen wir über Microservices?

Wie man die Ära der „Microservice-Fragmentierung“ überwindet

Bei einer monolithischen Architektur waren Entwickler aus Gründen der Konsistenz der Produktänderungen gezwungen, herauszufinden, was mit ihren Nachbarn los war. Bei der Arbeit an der neuen Architektur sind die Servicekontexte nicht mehr voneinander abhängig.

Damit eine Microservice-Architektur effektiv ist, müssen außerdem viele Prozesse eingerichtet werden, nämlich:

• Protokollierung;
• Anforderungsverfolgung (Jaeger);
• Fehleraggregation (Sentry);
• Status, Nachrichten, Ereignisse von Kubernetes (Event Stream Processing);
• Rennlimit / Leistungsschalter (Sie können Hystrix verwenden);
• Kontrolle der Dienstkonnektivität (wir verwenden Netramesh);
• Überwachung (Grafana);
• Versammlung (TeamCity);
• Kommunikation und Benachrichtigung (Slack, E-Mail);
• Aufgabenverfolgung; (Jira)
• Vorbereitung der Dokumentation.

Um sicherzustellen, dass das System seine Integrität nicht verliert und bei der Skalierung effektiv bleibt, haben wir die Organisation der Microservices in Avito neu überdacht.

Wie wir Microservices verwalten

Folgendes hilft bei der Implementierung einer einheitlichen „Parteirichtlinie“ für viele Avito-Mikrodienste:

  • Aufteilung der Infrastruktur in Schichten;
  • Platform as a Service (PaaS)-Konzept;
  • Überwachen Sie alles, was mit Microservices passiert.

Die Abstraktionsschichten der Infrastruktur umfassen drei Schichten. Gehen wir von oben nach unten vor.

A. Oben – Servicenetz. Zuerst haben wir Istio ausprobiert, aber es stellte sich heraus, dass es zu viele Ressourcen verbraucht, was für unsere Bände zu teuer ist. Deshalb entwickelte der leitende Ingenieur im Architekturteam Alexander Lukyanchenko seine eigene Lösung – Netramesh (verfügbar in Open Source), das wir derzeit in der Produktion verwenden und das um ein Vielfaches weniger Ressourcen verbraucht als Istio (aber nicht alles kann, womit Istio aufwarten kann).
B. Medium – Kubernetes. Wir implementieren und betreiben darauf Microservices.
C. Unterseite – blankes Metall. Wir nutzen keine Clouds oder Dinge wie OpenStack, sondern setzen komplett auf Bare Metal.

Alle Schichten werden durch PaaS kombiniert. Und diese Plattform wiederum besteht aus drei Teilen.

I. Generatoren, gesteuert über ein CLI-Dienstprogramm. Sie ist es, die dem Entwickler hilft, einen Microservice auf die richtige Art und Weise und mit minimalem Aufwand zu erstellen.

II. Konsolidierter Sammler mit Steuerung aller Tools über ein gemeinsames Dashboard.

III. Lagerung. Verbindet sich mit Planern, die automatisch Auslöser für wichtige Aktionen setzen. Dank eines solchen Systems wird keine einzige Aufgabe verpasst, nur weil jemand vergessen hat, eine Aufgabe in Jira einzurichten. Wir nutzen hierfür ein internes Tool namens Atlas.

Was wissen wir über Microservices?

Die Implementierung von Microservices in Avito erfolgt ebenfalls nach einem einzigen Schema, was die Kontrolle über sie in jeder Entwicklungs- und Releasephase vereinfacht.

Wie funktioniert eine Standard-Microservice-Entwicklungspipeline?

Im Allgemeinen sieht die Microservice-Erstellungskette folgendermaßen aus:

CLI-Push → Kontinuierliche Integration → Backen → Bereitstellen → Künstliche Tests → Kanarische Tests → Squeeze-Testing → Produktion → Wartung.

Gehen wir es genau in dieser Reihenfolge durch.

CLI-Push

• Erstellen eines Microservices.
Wir haben lange Zeit darum gekämpft, jedem Entwickler beizubringen, wie man Microservices macht. Dazu gehörte auch das Verfassen detaillierter Anweisungen in Confluence. Aber die Schemata änderten sich und wurden ergänzt. Das Ergebnis ist, dass zu Beginn der Reise ein Engpass auftrat: Die Einführung von Microservices dauerte viel länger und dennoch traten bei ihrer Erstellung häufig Probleme auf.

Am Ende haben wir ein einfaches CLI-Dienstprogramm erstellt, das die grundlegenden Schritte beim Erstellen eines Microservices automatisiert. Tatsächlich ersetzt es den ersten Git-Push. Hier ist, was sie genau tut.

— Erstellt einen Dienst nach einer Vorlage – Schritt für Schritt im „Assistenten“-Modus. Wir haben Vorlagen für die wichtigsten Programmiersprachen im Avito-Backend: PHP, Golang und Python.

– Ein Befehl nach dem anderen stellt eine Umgebung für die lokale Entwicklung auf einem bestimmten Computer bereit – Minikube wird gestartet, Helm-Charts werden automatisch generiert und in lokalen Kubernetes gestartet.

— Verbindet die erforderliche Datenbank. Der Entwickler muss IP, Login und Passwort nicht kennen, um Zugriff auf die benötigte Datenbank zu erhalten – sei es lokal, auf der Bühne oder in der Produktion. Darüber hinaus wird die Datenbank sofort in einer fehlertoleranten Konfiguration und mit Balancing bereitgestellt.

— Es führt die Live-Montage selbst durch. Nehmen wir an, ein Entwickler hat über seine IDE etwas in einem Microservice korrigiert. Das Dienstprogramm erkennt Änderungen im Dateisystem und erstellt auf dieser Grundlage die Anwendung (für Golang) neu und startet sie neu. Für PHP leiten wir einfach das Verzeichnis innerhalb des Cubes weiter und dort erfolgt der Live-Reload „automatisch“.

– Erzeugt Autotests. In Form von Rohlingen, aber durchaus gebrauchstauglich.

• Microservice-Bereitstellung.

Die Bereitstellung eines Microservices war für uns früher eine kleine lästige Pflicht. Folgendes war erforderlich:

I. Docker-Datei.

II. Konfig.
III. Helmdiagramm, das selbst umständlich ist und Folgendes enthält:

— die Diagramme selbst;
— Vorlagen;
— spezifische Werte unter Berücksichtigung unterschiedlicher Umgebungen.

Wir haben die Überarbeitung von Kubernetes-Manifesten vereinfacht, sodass sie jetzt automatisch generiert werden. Vor allem aber haben sie die Bereitstellung bis zum Äußersten vereinfacht. Von nun an haben wir eine Docker-Datei und der Entwickler schreibt die gesamte Konfiguration in eine einzige kurze app.toml-Datei.

Was wissen wir über Microservices?

Ja, und in app.toml selbst gibt es eine Minute lang nichts zu tun. Wir geben an, wo und wie viele Kopien des Dienstes erstellt werden sollen (auf dem Entwicklungsserver, beim Staging, in der Produktion) und geben seine Abhängigkeiten an. Beachten Sie die Zeile size = „small“ im [engine]-Block. Dies ist das Limit, das dem Dienst über Kubernetes zugewiesen wird.

Anschließend werden auf Basis der Konfiguration automatisch alle notwendigen Helm-Charts generiert und Verbindungen zu den Datenbanken hergestellt.

• Grundlegende Validierung. Auch solche Prüfungen erfolgen automatisiert.
Folgendes muss nachverfolgt werden:
– Gibt es eine Docker-Datei?
— gibt es app.toml;
— Ist eine Dokumentation verfügbar?
— Ist die Abhängigkeit in Ordnung?
— ob Alarmregeln festgelegt wurden.
Zum letzten Punkt: Der Inhaber des Dienstes bestimmt selbst, welche Produktmetriken überwacht werden sollen.

• Erstellung der Dokumentation.
Immer noch ein Problembereich. Es scheint das Offensichtlichste zu sein, aber gleichzeitig ist es auch eine „oft vergessene“ Aufzeichnung und daher ein verletzliches Glied in der Kette.
Es ist notwendig, dass für jeden Microservice eine Dokumentation vorhanden ist. Es enthält die folgenden Blöcke.

I. Kurze Beschreibung der Dienstleistung. Im wahrsten Sinne des Wortes ein paar Sätze darüber, was es tut und warum es benötigt wird.

II. Link zum Architekturdiagramm. Wichtig ist, dass man auf den ersten Blick gut erkennen kann, ob man beispielsweise Redis zum Caching oder als Hauptdatenspeicher im persistenten Modus nutzt. In Avito ist dies vorerst ein Link zu Confluence.

III. Runbook. Eine kurze Anleitung zum Starten des Dienstes und den Feinheiten der Handhabung.

NS. FAQ, wo es gut wäre, die Probleme zu antizipieren, auf die Ihre Kollegen bei der Arbeit mit dem Dienst stoßen könnten.

V. Beschreibung der Endpunkte für die API. Wenn Sie die Ziele plötzlich nicht mehr angegeben haben, werden Kollegen, deren Microservices mit Ihren verwandt sind, mit ziemlicher Sicherheit dafür bezahlen. Jetzt verwenden wir dafür Swagger und unsere Lösung namens Brief.

VI. Etiketten. Oder Markierungen, die zeigen, zu welchem ​​Produkt, welcher Funktionalität oder welchem ​​Strukturbereich des Unternehmens die Dienstleistung gehört. Sie helfen Ihnen beispielsweise schnell zu verstehen, ob Sie Funktionen kürzen, die Ihre Kollegen vor einer Woche für denselben Geschäftsbereich eingeführt haben.

VII. Eigentümer oder Eigentümer des Dienstes. In den meisten Fällen können sie oder sie mithilfe von PaaS automatisch ermittelt werden. Um auf der sicheren Seite zu sein, verlangen wir jedoch, dass der Entwickler sie manuell angibt.

Schließlich ist es eine gute Praxis, die Dokumentation zu überprüfen, ähnlich wie bei der Codeüberprüfung.

Kontinuierliche Integration

  • Repositories vorbereiten.
  • Erstellen einer Pipeline in TeamCity.
  • Rechte festlegen.
  • Suchen Sie nach Dienstbesitzern. Hier gibt es ein Hybridschema – manuelle Markierung und minimale Automatisierung durch PaaS. Ein vollautomatisches Schema schlägt fehl, wenn Dienste zur Unterstützung an ein anderes Entwicklungsteam übertragen werden oder wenn beispielsweise der Dienstentwickler kündigt.
  • Registrieren eines Dienstes in Atlas (siehe oben). Mit all seinen Eigentümern und Abhängigkeiten.
  • Migrationen prüfen. Wir prüfen, ob sie potenziell gefährlich sind. In einem von ihnen taucht beispielsweise eine Alter-Tabelle oder etwas anderes auf, das die Kompatibilität des Datenschemas zwischen verschiedenen Versionen des Dienstes beeinträchtigen kann. Dann wird die Migration nicht durchgeführt, sondern in ein Abonnement eingebunden – der PaaS muss dem Serviceeigentümer signalisieren, wann die Nutzung sicher ist.

Backen

Der nächste Schritt besteht darin, die Dienste vor der Bereitstellung zu packen.

  • Erstellen der Anwendung. Ganz nach den Klassikern – im Docker-Image.
  • Generierung von Helm-Diagrammen für den Dienst selbst und zugehörige Ressourcen. Einschließlich für Datenbanken und Cache. Sie werden automatisch gemäß der app.toml-Konfiguration erstellt, die in der CLI-Push-Phase generiert wurde.
  • Erstellen von Tickets für Administratoren zum Öffnen von Ports (wenn benötigt).
  • Ausführen von Unit-Tests und Berechnen der Codeabdeckung. Wenn die Codeabdeckung unter dem angegebenen Schwellenwert liegt, wird der Dienst höchstwahrscheinlich nicht mit der Bereitstellung fortfahren. Liegt er kurz vor dem Akzeptablen, wird dem Dienst ein „pessimisierender“ Koeffizient zugewiesen: Wenn sich der Indikator im Laufe der Zeit nicht verbessert, erhält der Entwickler eine Benachrichtigung, dass es bei den Tests keine Fortschritte gibt ( und es muss etwas dagegen getan werden).
  • Berücksichtigung von Speicher- und CPU-Einschränkungen. Wir schreiben Microservices hauptsächlich in Golang und führen sie in Kubernetes aus. Daher eine Feinheit, die mit der Besonderheit der Golang-Sprache verbunden ist: Standardmäßig werden beim Start alle Kerne auf der Maschine verwendet, wenn Sie die Variable GOMAXPROCS nicht explizit festlegen und wenn mehrere solcher Dienste auf derselben Maschine gestartet werden, beginnen sie um Ressourcen konkurrieren und sich gegenseitig stören. Die folgenden Diagramme zeigen, wie sich die Ausführungszeit ändert, wenn Sie die Anwendung ohne Konflikte und im Modus „Wettlauf um Ressourcen“ ausführen. (Quellen für Grafiken sind hier).

Was wissen wir über Microservices?

Ausführungszeit, weniger ist besser. Maximum: 643 ms, Minimum: 42 ms. Das Foto ist anklickbar.

Was wissen wir über Microservices?

Zeit für eine Operation, weniger ist besser. Maximum: 14091 ns, Minimum: 151 ns. Das Foto ist anklickbar.

In der Phase der Montagevorbereitung können Sie diese Variable explizit festlegen oder die Bibliothek verwenden automaxprocs von den Jungs von Uber.

Einsetzen

• Konventionen überprüfen. Bevor Sie mit der Bereitstellung von Service-Assemblys in Ihren vorgesehenen Umgebungen beginnen, müssen Sie Folgendes überprüfen:
- API-Endpunkte.
– Übereinstimmung der API-Endpunktantworten mit dem Schema.
— Protokollformat.
— Festlegen von Headern für Anfragen an den Dienst (derzeit wird dies von Netramesh durchgeführt)
— Festlegen des Eigentümertokens beim Senden von Nachrichten an den Ereignisbus. Dies ist erforderlich, um die Konnektivität von Diensten im gesamten Bus zu verfolgen. Sie können sowohl idempotente Daten an den Bus senden, was die Konnektivität von Diensten nicht erhöht (was gut ist), als auch Geschäftsdaten, die die Konnektivität von Diensten stärken (was sehr schlecht ist!). Und wenn diese Konnektivität zum Problem wird, hilft das Verständnis, wer den Bus schreibt und liest, dabei, die Dienste richtig zu trennen.

Es gibt noch nicht sehr viele Kongresse in Avito, aber ihr Pool wird immer größer. Je mehr solcher Vereinbarungen in einer für das Team verständlichen und verständlichen Form vorliegen, desto einfacher ist es, die Konsistenz zwischen Microservices aufrechtzuerhalten.

Synthetische Tests

• Closed-Loop-Tests. Dafür nutzen wir mittlerweile Open Source Hoverfly.io. Zunächst erfasst es die tatsächliche Auslastung des Dienstes und emuliert diese dann – eben in einer geschlossenen Schleife.

• Belastbarkeitstest. Wir versuchen, alle Leistungen optimal zur Geltung zu bringen. Und alle Versionen jedes Dienstes müssen einem Lasttest unterzogen werden – auf diese Weise können wir die aktuelle Leistung des Dienstes und den Unterschied zu früheren Versionen desselben Dienstes verstehen. Wenn nach einem Service-Update die Leistung um das Eineinhalbfache sinkt, ist dies ein klares Signal für seine Besitzer: Sie müssen sich in den Code vertiefen und die Situation korrigieren.
Wir nutzen die gesammelten Daten beispielsweise, um Autoscaling richtig umzusetzen und am Ende generell zu verstehen, wie skalierbar der Dienst ist.

Beim Lasttest prüfen wir, ob der Ressourcenverbrauch die gesetzten Grenzwerte einhält. Und wir konzentrieren uns vor allem auf Extreme.

a) Wir betrachten die Gesamtlast.
- Zu klein – höchstwahrscheinlich funktioniert etwas überhaupt nicht, wenn die Last mehrmals plötzlich abfällt.
- Zu groß – Optimierung erforderlich.

b) Wir betrachten den Cutoff gemäß RPS.
Hier betrachten wir den Unterschied zwischen der aktuellen und der vorherigen Version sowie die Gesamtmenge. Wenn ein Dienst beispielsweise 100 RPS produziert, ist er entweder schlecht geschrieben oder dies ist seine Besonderheit, aber in jedem Fall ist dies ein Grund, sich den Dienst genau anzusehen.
Wenn im Gegenteil zu viele RPS vorhanden sind, liegt möglicherweise ein Fehler vor und einige der Endpunkte haben die Ausführung der Nutzlast gestoppt und ein anderer wird einfach ausgelöst return true;

Kanarische Tests

Nachdem wir die synthetischen Tests bestanden haben, testen wir den Microservice an einer kleinen Anzahl von Benutzern. Wir beginnen vorsichtig mit einem winzigen Anteil der Zielgruppe des Dienstes – weniger als 0,1 %. In dieser Phase ist es sehr wichtig, dass die richtigen technischen und Produktmetriken in die Überwachung einbezogen werden, damit sie das Problem im Service so schnell wie möglich aufzeigen. Die Mindestzeit für einen Kanarienvogeltest beträgt 5 Minuten, der Haupttest 2 Stunden. Bei komplexen Dienstleistungen stellen wir die Uhrzeit manuell ein.
Wir analysieren:
– sprachspezifische Metriken, insbesondere PHP-FPM-Worker;
— Fehler in Sentry;
— Antwortstatus;
— Reaktionszeit, genau und durchschnittlich;
— Latenz;
— Ausnahmen, verarbeitet und nicht behandelt;
— Produktkennzahlen.

Squeeze-Test

Squeeze-Testing wird auch „Squeezing“-Testing genannt. Der Name der Technik wurde in Netflix eingeführt. Das Wesentliche besteht darin, dass wir zunächst eine Instanz bis zum Ausfallpunkt mit echtem Datenverkehr füllen und so deren Grenze festlegen. Dann fügen wir eine weitere Instanz hinzu und laden dieses Paar – wiederum bis zum Maximum; Wir sehen ihre Obergrenze und ihr Delta beim ersten „Squeeze“. Und so verbinden wir jeweils eine Instanz und berechnen das Änderungsmuster.
Testdaten fließen durch „Squeezing“ auch in eine gemeinsame Metrikdatenbank ein, wo wir entweder die künstlichen Belastungsergebnisse damit anreichern oder sogar „synthetische“ durch sie ersetzen.

Produktion

• Skalierung. Wenn wir einen Dienst in die Produktion einführen, überwachen wir, wie er skaliert. Unserer Erfahrung nach ist die Überwachung nur der CPU-Indikatoren wirkungslos. Die automatische Skalierung mit RPS-Benchmarking in Reinform funktioniert, allerdings nur für bestimmte Dienste, wie zum Beispiel Online-Streaming. Daher betrachten wir zunächst anwendungsspezifische Produktmetriken.

Als Ergebnis analysieren wir bei der Skalierung:
- CPU- und RAM-Anzeigen,
— die Anzahl der Anfragen in der Warteschlange,
- Reaktionszeit,
— Prognose basierend auf akkumulierten historischen Daten.

Bei der Skalierung eines Dienstes ist es auch wichtig, seine Abhängigkeiten zu überwachen, damit wir nicht den ersten Dienst in der Kette skalieren und diejenigen, auf die er zugreift, unter Last ausfallen. Um eine akzeptable Auslastung für den gesamten Dienstpool zu ermitteln, betrachten wir die historischen Daten des „nächsten“ abhängigen Dienstes (basierend auf einer Kombination aus CPU- und RAM-Indikatoren, gekoppelt mit app-spezifischen Metriken) und vergleichen sie mit den historischen Daten des initialisierenden Dienstes usw. entlang der „Abhängigkeitskette“ von oben nach unten.

Service

Nachdem der Microservice in Betrieb genommen wurde, können wir Trigger daran anhängen.

Hier sind typische Situationen, in denen Auslöser auftreten.
— Potenziell gefährliche Migrationen erkannt.
— Sicherheitsupdates wurden veröffentlicht.
— Der Dienst selbst wurde schon lange nicht mehr aktualisiert.
— Die Auslastung des Dienstes ist merklich zurückgegangen oder einige seiner Produktkennzahlen liegen außerhalb des normalen Bereichs.
— Der Dienst erfüllt nicht mehr die neuen Plattformanforderungen.

Einige der Auslöser sind für die Stabilität des Betriebs verantwortlich, andere – als Funktion der Systemwartung – beispielsweise wurde ein Dienst längere Zeit nicht bereitgestellt und sein Basis-Image besteht die Sicherheitsprüfungen nicht mehr.

Dashboard

Kurz gesagt, das Dashboard ist das Bedienfeld unseres gesamten PaaS.

  • Ein zentraler Informationspunkt über den Dienst mit Daten zu seiner Testabdeckung, der Anzahl seiner Bilder, der Anzahl der Produktionskopien, Versionen usw.
  • Ein Tool zum Filtern von Daten nach Diensten und Labels (Markierungen für die Zugehörigkeit zu Geschäftsbereichen, Produktfunktionalität usw.)
  • Ein Tool zur Integration in Infrastrukturtools zur Nachverfolgung, Protokollierung und Überwachung.
  • Eine zentrale Service-Dokumentation.
  • Eine einzige Sicht auf alle Ereignisse über alle Dienste hinweg.

Was wissen wir über Microservices?
Was wissen wir über Microservices?
Was wissen wir über Microservices?
Was wissen wir über Microservices?

Insgesamt

Vor der Einführung von PaaS könnte ein neuer Entwickler mehrere Wochen damit verbringen, sich mit allen Tools vertraut zu machen, die zum Starten eines Microservices in der Produktion erforderlich sind: Kubernetes, Helm, unsere internen TeamCity-Funktionen, fehlertolerantes Einrichten von Verbindungen zu Datenbanken und Caches usw. Nun ist es soweit Es dauert ein paar Stunden, den Schnellstart zu lesen und den Dienst selbst zu erstellen.

Ich habe zu diesem Thema für HighLoad++ 2018 einen Bericht verfasst, den Sie sich ansehen können Video и Präsentation.

Bonustrack für diejenigen, die bis zum Ende lesen

Wir von Avito organisieren eine interne dreitägige Schulung für Entwickler von Chris Richardson, ein Experte für Microservice-Architektur. Wir möchten einem der Leser dieses Beitrags die Möglichkeit geben, daran teilzunehmen. Hier Das Schulungsprogramm wurde veröffentlicht.

Die Schulung findet vom 5. bis 7. August in Moskau statt. Es handelt sich um Arbeitstage, die voll ausgelastet sein werden. Das Mittagessen und die Schulung finden in unserem Büro statt, die Kosten für Reise und Unterkunft trägt der ausgewählte Teilnehmer selbst.

Sie können sich für die Teilnahme bewerben in diesem Google-Formular. Von Ihnen – die Antwort auf die Frage, warum Sie an der Schulung teilnehmen müssen und Informationen, wie Sie mit uns in Kontakt treten können. Antworten Sie auf Englisch, da Chris selbst den Teilnehmer auswählt, der an der Schulung teilnehmen wird.
Wir werden den Namen des Schulungsteilnehmers in einem Update dieses Beitrags und in den sozialen Netzwerken Avito für Entwickler (AvitoTech in) bekannt geben Фейсбуке, Vkontakte, Zwitschern) bis spätestens 19. Juli.

Source: habr.com

Kommentar hinzufügen